001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.db.generic;
029
030import org.opencms.configuration.CmsConfigurationManager;
031import org.opencms.configuration.CmsParameterConfiguration;
032import org.opencms.db.CmsDbContext;
033import org.opencms.db.CmsDbEntryAlreadyExistsException;
034import org.opencms.db.CmsDbEntryNotFoundException;
035import org.opencms.db.CmsDbIoException;
036import org.opencms.db.CmsDbSqlException;
037import org.opencms.db.CmsDbUtil;
038import org.opencms.db.CmsDriverManager;
039import org.opencms.db.CmsUserSettings;
040import org.opencms.db.CmsVisitEntryFilter;
041import org.opencms.db.I_CmsProjectDriver;
042import org.opencms.db.I_CmsUserDriver;
043import org.opencms.file.CmsDataAccessException;
044import org.opencms.file.CmsFolder;
045import org.opencms.file.CmsGroup;
046import org.opencms.file.CmsProject;
047import org.opencms.file.CmsProperty;
048import org.opencms.file.CmsPropertyDefinition;
049import org.opencms.file.CmsResource;
050import org.opencms.file.CmsResourceFilter;
051import org.opencms.file.CmsUser;
052import org.opencms.file.CmsUserSearchParameters;
053import org.opencms.file.CmsVfsResourceNotFoundException;
054import org.opencms.file.types.CmsResourceTypeFolder;
055import org.opencms.i18n.CmsEncoder;
056import org.opencms.i18n.CmsLocaleManager;
057import org.opencms.i18n.CmsMessageContainer;
058import org.opencms.main.CmsEvent;
059import org.opencms.main.CmsException;
060import org.opencms.main.CmsInitException;
061import org.opencms.main.CmsLog;
062import org.opencms.main.I_CmsEventListener;
063import org.opencms.main.OpenCms;
064import org.opencms.monitor.CmsMemoryMonitor;
065import org.opencms.relations.CmsRelation;
066import org.opencms.relations.CmsRelationFilter;
067import org.opencms.relations.CmsRelationType;
068import org.opencms.security.CmsAccessControlEntry;
069import org.opencms.security.CmsOrganizationalUnit;
070import org.opencms.security.CmsPasswordEncryptionException;
071import org.opencms.security.CmsRole;
072import org.opencms.security.I_CmsPrincipal;
073import org.opencms.util.CmsDataTypeUtil;
074import org.opencms.util.CmsMacroResolver;
075import org.opencms.util.CmsPair;
076import org.opencms.util.CmsStringUtil;
077import org.opencms.util.CmsUUID;
078
079import java.io.IOException;
080import java.security.MessageDigest;
081import java.security.NoSuchAlgorithmException;
082import java.sql.Connection;
083import java.sql.PreparedStatement;
084import java.sql.ResultSet;
085import java.sql.SQLException;
086import java.util.ArrayList;
087import java.util.Collections;
088import java.util.HashMap;
089import java.util.Iterator;
090import java.util.List;
091import java.util.Locale;
092import java.util.Map;
093import java.util.Map.Entry;
094import java.util.concurrent.locks.Lock;
095
096import org.apache.commons.logging.Log;
097
098import com.google.common.util.concurrent.Striped;
099
100/**
101 * Generic (ANSI-SQL) database server implementation of the user driver methods.<p>
102 *
103 * @since 6.0.0
104 */
105public class CmsUserDriver implements I_CmsUserDriver {
106
107    /** The root path for organizational units. */
108    public static final String ORGUNIT_BASE_FOLDER = "/system/orgunits/";
109
110    /** The internal request attribute to indicate that the password has not to be digested. */
111    public static final String REQ_ATTR_DONT_DIGEST_PASSWORD = "DONT_DIGEST_PASSWORD";
112
113    // TODO: remove all these constants
114    /** Attribute WRITE USER_ADDINFO. */
115    private static final String ATTRIBUTE_USERADDINFO = "A_USERADDINFO";
116
117    /** Attribute WRITE USER_ADDINFO value delete. */
118    private static final String ATTRIBUTE_USERADDINFO_VALUE_DELETE = "delete";
119
120    /** Attribute WRITE USER_ADDINFO value insert. */
121    private static final String ATTRIBUTE_USERADDINFO_VALUE_INSERT = "insert";
122
123    /** Attribute WRITE USER_ADDINFO value update. */
124    private static final String ATTRIBUTE_USERADDINFO_VALUE_UPDATE = "update";
125
126    /** The log object for this class. */
127    private static final Log LOG = CmsLog.getLog(org.opencms.db.generic.CmsUserDriver.class);
128
129    /** The name of the offline project. */
130    private static final String OFFLINE_PROJECT_NAME = "Offline";
131
132    /** Property for the organizational unit description. */
133    private static final String ORGUNIT_PROPERTY_DESCRIPTION = CmsPropertyDefinition.PROPERTY_DESCRIPTION;
134
135    /** Property for the organizational unit default project id. */
136    private static final String ORGUNIT_PROPERTY_PROJECTID = CmsPropertyDefinition.PROPERTY_KEYWORDS;
137
138    /** Striped lock used to synchronize writing of additional infos for users. */
139    private static Striped<Lock> USER_INFO_LOCKS = Striped.lock(16);
140
141    /** A digest to encrypt the passwords. */
142    protected MessageDigest m_digest;
143
144    /** The algorithm used to encode passwords. */
145    protected String m_digestAlgorithm;
146
147    /** The file.encoding to code passwords after encryption with digest. */
148    protected String m_digestFileEncoding;
149
150    /** The driver manager. */
151    protected CmsDriverManager m_driverManager;
152
153    /** The SQL manager. */
154    protected CmsSqlManager m_sqlManager;
155
156    /**
157     * @see org.opencms.db.I_CmsUserDriver#addResourceToOrganizationalUnit(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit, org.opencms.file.CmsResource)
158     */
159    public void addResourceToOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsResource resource)
160    throws CmsDataAccessException {
161
162        try {
163            // check if the resource is a folder
164            if (resource.isFile()) {
165                throw new CmsDataAccessException(
166                    Messages.get().container(
167                        Messages.ERR_ORGUNIT_RESOURCE_IS_NOT_FOLDER_2,
168                        orgUnit.getName(),
169                        dbc.removeSiteRoot(resource.getRootPath())));
170            }
171
172            // read the resource representing the organizational unit
173            CmsResource ouResource = m_driverManager.readResource(
174                dbc,
175                ORGUNIT_BASE_FOLDER + orgUnit.getName(),
176                CmsResourceFilter.ALL);
177
178            // get the associated resources
179            List<String> vfsPaths = new ArrayList<String>(internalResourcesForOrgUnit(dbc, ouResource));
180
181            // check resource scope for non root ous
182            if (orgUnit.getParentFqn() != null) {
183                // get the parent ou
184                CmsOrganizationalUnit parentOu = m_driverManager.readOrganizationalUnit(dbc, orgUnit.getParentFqn());
185                // validate
186                internalValidateResourceForOrgUnit(dbc, parentOu, resource.getRootPath());
187            } else {
188                // allow to set the first resource
189                if (!vfsPaths.isEmpty()) {
190                    throw new CmsDataAccessException(
191                        org.opencms.security.Messages.get().container(
192                            org.opencms.security.Messages.ERR_ORGUNIT_ROOT_EDITION_0));
193                }
194            }
195
196            // add the new resource
197            CmsRelation relation = new CmsRelation(ouResource, resource, CmsRelationType.OU_RESOURCE);
198            m_driverManager.getVfsDriver(dbc).createRelation(dbc, dbc.currentProject().getUuid(), relation);
199            m_driverManager.getVfsDriver(dbc).createRelation(dbc, CmsProject.ONLINE_PROJECT_ID, relation);
200
201            try {
202                // be sure the project was not deleted
203                CmsProject project = m_driverManager.readProject(dbc, orgUnit.getProjectId());
204                // maintain the default project synchronized
205                m_driverManager.getProjectDriver(dbc).createProjectResource(
206                    dbc,
207                    orgUnit.getProjectId(),
208                    resource.getRootPath());
209
210                OpenCms.fireCmsEvent(
211                    I_CmsEventListener.EVENT_PROJECT_MODIFIED,
212                    Collections.<String, Object> singletonMap("project", project));
213            } catch (CmsDbEntryNotFoundException e) {
214                // ignore
215            } finally {
216                // fire a resource modification event
217                Map<String, Object> data = new HashMap<String, Object>(2);
218                data.put(I_CmsEventListener.KEY_RESOURCE, ouResource);
219                data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CmsDriverManager.CHANGED_RESOURCE));
220                OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data));
221            }
222        } catch (CmsException e) {
223            throw new CmsDataAccessException(e.getMessageContainer(), e);
224        }
225    }
226
227    /**
228     * @see org.opencms.db.I_CmsUserDriver#countUsers(org.opencms.db.CmsDbContext, org.opencms.file.CmsUserSearchParameters)
229     */
230    public long countUsers(CmsDbContext dbc, CmsUserSearchParameters searchParams) throws CmsDataAccessException {
231
232        CmsPair<String, List<Object>> queryAndParams = createUserQuery(searchParams, true);
233        ResultSet res = null;
234        PreparedStatement stmt = null;
235        Connection conn = null;
236        try {
237            conn = m_sqlManager.getConnection(dbc);
238            stmt = m_sqlManager.getPreparedStatementForSql(conn, queryAndParams.getFirst());
239            CmsDbUtil.fillParameters(stmt, queryAndParams.getSecond());
240            res = stmt.executeQuery();
241            long result = 0;
242            while (res.next()) {
243                result = res.getLong(1);
244            }
245            return result;
246        } catch (SQLException e) {
247            throw new CmsDbSqlException(
248                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
249                e);
250        } finally {
251            m_sqlManager.closeAll(dbc, conn, stmt, res);
252        }
253
254    }
255
256    /**
257     * @see org.opencms.db.I_CmsUserDriver#createAccessControlEntry(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, int, int, int)
258     */
259    public void createAccessControlEntry(
260        CmsDbContext dbc,
261        CmsProject project,
262        CmsUUID resource,
263        CmsUUID principal,
264        int allowed,
265        int denied,
266        int flags)
267    throws CmsDataAccessException {
268
269        PreparedStatement stmt = null;
270        Connection conn = null;
271
272        try {
273            conn = m_sqlManager.getConnection(dbc);
274            stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_CREATE_5");
275
276            stmt.setString(1, resource.toString());
277            stmt.setString(2, principal.toString());
278            stmt.setInt(3, allowed);
279            stmt.setInt(4, denied);
280            stmt.setInt(5, flags);
281
282            stmt.executeUpdate();
283        } catch (SQLException e) {
284            throw new CmsDbSqlException(
285                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
286                e);
287        } finally {
288            m_sqlManager.closeAll(dbc, conn, stmt, null);
289        }
290    }
291
292    /**
293     * @see org.opencms.db.I_CmsUserDriver#createGroup(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, java.lang.String, java.lang.String, int, java.lang.String)
294     */
295    public CmsGroup createGroup(
296        CmsDbContext dbc,
297        CmsUUID groupId,
298        String groupFqn,
299        String description,
300        int flags,
301        String parentGroupFqn)
302    throws CmsDataAccessException {
303
304        CmsUUID parentId = CmsUUID.getNullUUID();
305        CmsGroup group = null;
306        Connection conn = null;
307        PreparedStatement stmt = null;
308
309        if (existsGroup(dbc, groupFqn)) {
310            CmsMessageContainer message = Messages.get().container(
311                Messages.ERR_GROUP_WITH_NAME_ALREADY_EXISTS_1,
312                groupFqn);
313            if (LOG.isErrorEnabled()) {
314                LOG.error(message.key());
315            }
316            throw new CmsDbEntryAlreadyExistsException(message);
317        }
318
319        try {
320            // get the id of the parent group if necessary
321            if (CmsStringUtil.isNotEmpty(parentGroupFqn)) {
322                parentId = readGroup(dbc, parentGroupFqn).getId();
323            }
324
325            conn = getSqlManager().getConnection(dbc);
326            stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_CREATE_GROUP_6");
327
328            // write new group to the database
329            stmt.setString(1, groupId.toString());
330            stmt.setString(2, parentId.toString());
331            stmt.setString(3, CmsOrganizationalUnit.getSimpleName(groupFqn));
332            stmt.setString(4, m_sqlManager.validateEmpty(description));
333            stmt.setInt(5, flags);
334            stmt.setString(6, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(groupFqn));
335            stmt.executeUpdate();
336
337            group = new CmsGroup(groupId, parentId, groupFqn, description, flags);
338        } catch (SQLException e) {
339            throw new CmsDbSqlException(
340                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
341                e);
342        } finally {
343            m_sqlManager.closeAll(dbc, conn, stmt, null);
344        }
345
346        return group;
347    }
348
349    /**
350     * @see org.opencms.db.I_CmsUserDriver#createOrganizationalUnit(org.opencms.db.CmsDbContext, java.lang.String, java.lang.String, int, org.opencms.security.CmsOrganizationalUnit, String)
351     */
352    public CmsOrganizationalUnit createOrganizationalUnit(
353        CmsDbContext dbc,
354        String name,
355        String description,
356        int flags,
357        CmsOrganizationalUnit parent,
358        String associatedResource)
359    throws CmsDataAccessException {
360
361        // check the parent
362        if ((parent == null) && !name.equals("")) {
363            throw new CmsDataAccessException(
364                org.opencms.db.Messages.get().container(org.opencms.db.Messages.ERR_PARENT_ORGUNIT_NULL_0));
365        }
366        try {
367            // get the parent ou folder
368            CmsResource parentFolder = internalOrgUnitFolder(dbc, parent);
369
370            CmsResource resource = null;
371            // only normal OUs have to have at least one resource
372            if (((flags & CmsOrganizationalUnit.FLAG_WEBUSERS) == 0) || (associatedResource != null)) {
373                // check that the associated resource exists and if is a folder
374                resource = m_driverManager.readFolder(dbc, associatedResource, CmsResourceFilter.ALL);
375            }
376
377            String ouPath = ORGUNIT_BASE_FOLDER;
378            // validate resource
379            if ((parentFolder != null) && (resource != null)) {
380                internalValidateResourceForOrgUnit(
381                    dbc,
382                    internalCreateOrgUnitFromResource(dbc, parentFolder),
383                    resource.getRootPath());
384            }
385            if (parentFolder != null) {
386                ouPath = parentFolder.getRootPath();
387                if (!ouPath.endsWith("/")) {
388                    ouPath += "/";
389                }
390            }
391
392            // create the resource
393            CmsResource ouFolder = internalCreateResourceForOrgUnit(dbc, ouPath + name, flags);
394
395            // write description property
396            internalWriteOrgUnitProperty(
397                dbc,
398                ouFolder,
399                new CmsProperty(ORGUNIT_PROPERTY_DESCRIPTION, description, null));
400
401            // create the ou object
402            CmsOrganizationalUnit ou = internalCreateOrgUnitFromResource(dbc, ouFolder);
403
404            if ((ou.getParentFqn() != null)) {
405                // if not the root ou, create default roles & groups
406                // for the root ou, are created in #fillDefaults
407                Locale locale = CmsLocaleManager.getDefaultLocale();
408                if (dbc.getRequestContext() != null) {
409                    locale = dbc.getRequestContext().getLocale();
410                }
411                // create default groups
412                internalCreateDefaultGroups(dbc, ou.getName(), ou.getDisplayName(locale), ou.hasFlagWebuser());
413                if (!ou.hasFlagWebuser()) {
414                    // create default project
415                    CmsProject project = m_driverManager.createProject(
416                        dbc,
417                        ou.getName() + OFFLINE_PROJECT_NAME,
418                        "",
419                        ou.getName() + OpenCms.getDefaultUsers().getGroupUsers(),
420                        ou.getName() + OpenCms.getDefaultUsers().getGroupUsers(),
421                        CmsProject.PROJECT_TYPE_NORMAL);
422
423                    // write project id property
424                    internalWriteOrgUnitProperty(
425                        dbc,
426                        ouFolder,
427                        new CmsProperty(ORGUNIT_PROPERTY_PROJECTID, project.getUuid().toString(), null));
428                } else {
429                    // write project id property
430                    internalWriteOrgUnitProperty(
431                        dbc,
432                        ouFolder,
433                        new CmsProperty(ORGUNIT_PROPERTY_PROJECTID, CmsUUID.getNullUUID().toString(), null));
434                }
435            } else {
436                // write project id property
437                internalWriteOrgUnitProperty(
438                    dbc,
439                    ouFolder,
440                    new CmsProperty(ORGUNIT_PROPERTY_PROJECTID, CmsUUID.getNullUUID().toString(), null));
441            }
442            // reread the ou, to actualize the project id
443            ou = internalCreateOrgUnitFromResource(dbc, ouFolder);
444            if (resource != null) {
445                // add the given resource
446                m_driverManager.addResourceToOrgUnit(dbc, ou, resource);
447            }
448            OpenCms.fireCmsEvent(I_CmsEventListener.EVENT_CLEAR_ONLINE_CACHES, null);
449            // return the new created ou
450            return ou;
451        } catch (CmsException e) {
452            throw new CmsDataAccessException(e.getMessageContainer(), e);
453        }
454    }
455
456    /**
457     * @see org.opencms.db.I_CmsUserDriver#createRootOrganizationalUnit(org.opencms.db.CmsDbContext)
458     */
459    public void createRootOrganizationalUnit(CmsDbContext dbc) {
460
461        try {
462            readOrganizationalUnit(dbc, "");
463        } catch (CmsException e) {
464            try {
465                CmsProject onlineProject = dbc.currentProject();
466                CmsProject setupProject = onlineProject;
467                // get the right offline project
468                try {
469                    // this if setting up OpenCms
470                    setupProject = m_driverManager.readProject(dbc, I_CmsProjectDriver.SETUP_PROJECT_NAME);
471                } catch (CmsException exc) {
472                    // this if updating OpenCms
473                    try {
474                        setupProject = m_driverManager.readProject(dbc, "Offline");
475                    } catch (CmsException exc2) {
476                        // there is nothing to do, if no offline project found
477                    }
478                }
479                dbc.getRequestContext().setCurrentProject(setupProject);
480                try {
481                    createOrganizationalUnit(
482                        dbc,
483                        "",
484                        CmsMacroResolver.localizedKeyMacro(Messages.GUI_ORGUNIT_ROOT_DESCRIPTION_0, null),
485                        0,
486                        null,
487                        "/");
488                } finally {
489                    dbc.getRequestContext().setCurrentProject(onlineProject);
490                }
491                if (CmsLog.INIT.isInfoEnabled()) {
492                    CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ROOT_ORGUNIT_DEFAULTS_INITIALIZED_0));
493                }
494            } catch (CmsException exc) {
495                if (CmsLog.INIT.isErrorEnabled()) {
496                    CmsLog.INIT.error(
497                        Messages.get().getBundle().key(Messages.INIT_ROOT_ORGUNIT_INITIALIZATION_FAILED_0),
498                        exc);
499                }
500                throw new CmsInitException(Messages.get().container(Messages.ERR_INITIALIZING_USER_DRIVER_0), exc);
501            }
502        }
503    }
504
505    /**
506     * @see org.opencms.db.I_CmsUserDriver#createUser(CmsDbContext, CmsUUID, String, String, String, String, String, long, int, long, Map)
507     */
508    public CmsUser createUser(
509        CmsDbContext dbc,
510        CmsUUID id,
511        String userFqn,
512        String password,
513        String firstname,
514        String lastname,
515        String email,
516        long lastlogin,
517        int flags,
518        long dateCreated,
519        Map<String, Object> additionalInfos)
520    throws CmsDataAccessException {
521
522        Connection conn = null;
523        PreparedStatement stmt = null;
524
525        if (existsUser(dbc, userFqn)) {
526            CmsMessageContainer message = Messages.get().container(
527                Messages.ERR_USER_WITH_NAME_ALREADY_EXISTS_1,
528                userFqn);
529            if (LOG.isErrorEnabled()) {
530                LOG.error(message.key());
531            }
532            throw new CmsDbEntryAlreadyExistsException(message);
533        }
534
535        try {
536            conn = m_sqlManager.getConnection(dbc);
537            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_ADD_10");
538
539            stmt.setString(1, id.toString());
540            stmt.setString(2, CmsOrganizationalUnit.getSimpleName(userFqn));
541            stmt.setString(3, password);
542            stmt.setString(4, m_sqlManager.validateEmpty(firstname));
543            stmt.setString(5, m_sqlManager.validateEmpty(lastname));
544            stmt.setString(6, m_sqlManager.validateEmpty(email));
545            stmt.setLong(7, lastlogin);
546            stmt.setInt(8, flags);
547            stmt.setString(9, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(userFqn));
548            stmt.setLong(10, (dateCreated == 0 ? System.currentTimeMillis() : dateCreated));
549            stmt.executeUpdate();
550        } catch (SQLException e) {
551            throw new CmsDbSqlException(
552                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
553                e);
554        } finally {
555            m_sqlManager.closeAll(dbc, conn, stmt, null);
556        }
557        internalWriteUserInfos(dbc, id, additionalInfos);
558
559        return readUser(dbc, id);
560    }
561
562    /**
563     * @see org.opencms.db.I_CmsUserDriver#createUserInGroup(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
564     */
565    public void createUserInGroup(CmsDbContext dbc, CmsUUID userId, CmsUUID groupId) throws CmsDataAccessException {
566
567        Connection conn = null;
568        PreparedStatement stmt = null;
569
570        // check if user is already in group
571        if (!internalValidateUserInGroup(dbc, userId, groupId)) {
572            // if not, add this user to the group
573            try {
574                conn = getSqlManager().getConnection(dbc);
575                stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_ADD_USER_TO_GROUP_3");
576
577                // write the new assignment to the database
578                stmt.setString(1, groupId.toString());
579                stmt.setString(2, userId.toString());
580                // flag field is not used yet
581                stmt.setInt(3, 0);
582                stmt.executeUpdate();
583            } catch (SQLException e) {
584                throw new CmsDbSqlException(
585                    Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
586                    e);
587            } finally {
588                m_sqlManager.closeAll(dbc, conn, stmt, null);
589            }
590        }
591    }
592
593    /**
594     * @see org.opencms.db.I_CmsUserDriver#deleteGroup(org.opencms.db.CmsDbContext, java.lang.String)
595     */
596    public void deleteGroup(CmsDbContext dbc, String groupFqn) throws CmsDataAccessException {
597
598        Connection conn = null;
599        PreparedStatement stmt = null;
600
601        try {
602            conn = getSqlManager().getConnection(dbc);
603            stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_DELETE_GROUP_2");
604
605            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(groupFqn));
606            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(groupFqn));
607            stmt.executeUpdate();
608        } catch (SQLException e) {
609            throw new CmsDbSqlException(
610                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
611                e);
612        } finally {
613            m_sqlManager.closeAll(dbc, conn, stmt, null);
614        }
615    }
616
617    /**
618     * @see org.opencms.db.I_CmsUserDriver#deleteOrganizationalUnit(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit)
619     */
620    public void deleteOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit organizationalUnit)
621    throws CmsDataAccessException {
622
623        try {
624            CmsResource resource = m_driverManager.readResource(
625                dbc,
626                ORGUNIT_BASE_FOLDER + organizationalUnit.getName(),
627                CmsResourceFilter.DEFAULT);
628            internalDeleteOrgUnitResource(dbc, resource);
629            if (organizationalUnit.getProjectId() != null) {
630                try {
631                    // maintain the default project synchronized
632                    m_driverManager.deleteProject(
633                        dbc,
634                        m_driverManager.readProject(dbc, organizationalUnit.getProjectId()),
635                        false);
636                } catch (CmsDbEntryNotFoundException e) {
637                    // ignore
638                }
639            }
640        } catch (CmsException e) {
641            throw new CmsDataAccessException(e.getMessageContainer(), e);
642        }
643    }
644
645    /**
646     * @see org.opencms.db.I_CmsUserDriver#deleteUser(org.opencms.db.CmsDbContext, java.lang.String)
647     */
648    public void deleteUser(CmsDbContext dbc, String userFqn) throws CmsDataAccessException {
649
650        CmsUser user = readUser(dbc, userFqn);
651
652        Connection conn = null;
653        PreparedStatement stmt = null;
654
655        try {
656            conn = getSqlManager().getConnection(dbc);
657            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_DELETE_2");
658
659            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(userFqn));
660            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(userFqn));
661            stmt.executeUpdate();
662        } catch (SQLException e) {
663            throw new CmsDbSqlException(
664                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
665                e);
666        } finally {
667            m_sqlManager.closeAll(dbc, conn, stmt, null);
668        }
669        // delete the additional infos
670        deleteUserInfos(dbc, user.getId());
671
672        if (OpenCms.getSubscriptionManager().isEnabled()) {
673            // delete visited resource information from log
674            CmsVisitEntryFilter filter = CmsVisitEntryFilter.ALL.filterUser(user.getId());
675            m_driverManager.getSubscriptionDriver().deleteVisits(
676                dbc,
677                OpenCms.getSubscriptionManager().getPoolName(),
678                filter);
679
680            // delete all subscribed resources for user
681            m_driverManager.getSubscriptionDriver().unsubscribeAllResourcesFor(
682                dbc,
683                OpenCms.getSubscriptionManager().getPoolName(),
684                user);
685        }
686    }
687
688    /**
689     * @see org.opencms.db.I_CmsUserDriver#deleteUserInfos(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
690     */
691    public void deleteUserInfos(CmsDbContext dbc, CmsUUID userId) throws CmsDataAccessException {
692
693        Connection conn = null;
694        PreparedStatement stmt = null;
695
696        try {
697            conn = getSqlManager().getConnection(dbc);
698            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERDATA_DELETE_1");
699
700            stmt.setString(1, userId.toString());
701            stmt.executeUpdate();
702        } catch (SQLException e) {
703            throw new CmsDbSqlException(
704                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
705                e);
706        } finally {
707            m_sqlManager.closeAll(dbc, conn, stmt, null);
708        }
709    }
710
711    /**
712     * @see org.opencms.db.I_CmsUserDriver#deleteUserInGroup(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
713     */
714    public void deleteUserInGroup(CmsDbContext dbc, CmsUUID userId, CmsUUID groupId) throws CmsDataAccessException {
715
716        PreparedStatement stmt = null;
717        Connection conn = null;
718        try {
719            conn = getSqlManager().getConnection(dbc);
720            stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_REMOVE_USER_FROM_GROUP_2");
721
722            stmt.setString(1, groupId.toString());
723            stmt.setString(2, userId.toString());
724            stmt.executeUpdate();
725        } catch (SQLException e) {
726            throw new CmsDbSqlException(
727                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
728                e);
729        } finally {
730            m_sqlManager.closeAll(dbc, conn, stmt, null);
731        }
732    }
733
734    /**
735     * @see org.opencms.db.I_CmsUserDriver#destroy()
736     */
737    public void destroy() throws Throwable {
738
739        m_sqlManager = null;
740        m_driverManager = null;
741
742        if (CmsLog.INIT.isInfoEnabled()) {
743            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SHUTDOWN_DRIVER_1, getClass().getName()));
744        }
745    }
746
747    /**
748     * @see org.opencms.db.I_CmsUserDriver#existsGroup(org.opencms.db.CmsDbContext, java.lang.String)
749     */
750    public boolean existsGroup(CmsDbContext dbc, String groupFqn) throws CmsDataAccessException {
751
752        ResultSet res = null;
753        PreparedStatement stmt = null;
754        Connection conn = null;
755        boolean result = false;
756
757        try {
758            conn = getSqlManager().getConnection(dbc);
759            stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_READ_BY_NAME_2");
760
761            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(groupFqn));
762            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(groupFqn));
763            res = stmt.executeQuery();
764
765            // create new Cms group object
766            if (res.next()) {
767                result = true;
768                while (res.next()) {
769                    // do nothing only move through all rows because of mssql odbc driver
770                }
771            } else {
772                result = false;
773            }
774
775        } catch (SQLException e) {
776            throw new CmsDbSqlException(
777                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
778                e);
779        } finally {
780            m_sqlManager.closeAll(dbc, conn, stmt, res);
781        }
782
783        return result;
784    }
785
786    /**
787     * @see org.opencms.db.I_CmsUserDriver#existsUser(org.opencms.db.CmsDbContext, java.lang.String)
788     */
789    public boolean existsUser(CmsDbContext dbc, String userFqn) throws CmsDataAccessException {
790
791        PreparedStatement stmt = null;
792        ResultSet res = null;
793        Connection conn = null;
794        boolean result = false;
795
796        try {
797            conn = getSqlManager().getConnection(dbc);
798            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_READ_BY_NAME_2");
799            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(userFqn));
800            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(userFqn));
801
802            res = stmt.executeQuery();
803
804            if (res.next()) {
805                result = true;
806                while (res.next()) {
807                    // do nothing only move through all rows because of mssql odbc driver
808                }
809            } else {
810                result = false;
811            }
812        } catch (SQLException e) {
813            throw new CmsDbSqlException(
814                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
815                e);
816        } finally {
817            m_sqlManager.closeAll(dbc, conn, stmt, res);
818        }
819
820        return result;
821    }
822
823    /**
824     * @see org.opencms.db.I_CmsUserDriver#fillDefaults(org.opencms.db.CmsDbContext)
825     */
826    public void fillDefaults(CmsDbContext dbc) throws CmsInitException {
827
828        try {
829            CmsOrganizationalUnit ou = (CmsOrganizationalUnit)(dbc.getAttribute(CmsDriverManager.ATTR_INIT_OU));
830            if (ou == null) {
831                internalCreateDefaultGroups(dbc, "", "", false);
832            } else {
833                internalCreateDefaultGroups(dbc, ou.getName(), ou.getDescription(), ou.hasFlagWebuser());
834            }
835        } catch (CmsException e) {
836            if (CmsLog.INIT.isErrorEnabled()) {
837                CmsLog.INIT.error(Messages.get().getBundle().key(Messages.INIT_DEFAULT_USERS_CREATION_FAILED_0), e);
838            }
839            throw new CmsInitException(Messages.get().container(Messages.ERR_INITIALIZING_USER_DRIVER_0), e);
840        }
841    }
842
843    /**
844     * @see org.opencms.db.I_CmsUserDriver#getGroups(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit, boolean, boolean)
845     */
846    public List<CmsGroup> getGroups(
847        CmsDbContext dbc,
848        CmsOrganizationalUnit orgUnit,
849        boolean includeSubOus,
850        boolean readRoles)
851    throws CmsDataAccessException {
852
853        // compose the query
854        String sqlQuery = createRoleQuery("C_GROUPS_GET_GROUPS_0", includeSubOus, readRoles);
855        // adjust parameter to use with LIKE
856        String ouFqn = CmsOrganizationalUnit.SEPARATOR + orgUnit.getName();
857        if (includeSubOus) {
858            ouFqn += "%";
859        }
860
861        // execute it
862        List<CmsGroup> groups = new ArrayList<CmsGroup>();
863        ResultSet res = null;
864        PreparedStatement stmt = null;
865        Connection conn = null;
866        try {
867            // create statement
868            conn = m_sqlManager.getConnection(dbc);
869            stmt = m_sqlManager.getPreparedStatementForSql(conn, sqlQuery);
870
871            stmt.setString(1, ouFqn);
872            stmt.setInt(2, I_CmsPrincipal.FLAG_GROUP_ROLE);
873
874            res = stmt.executeQuery();
875
876            // create new Cms group objects
877            while (res.next()) {
878                groups.add(internalCreateGroup(res));
879            }
880        } catch (SQLException e) {
881            throw new CmsDbSqlException(
882                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
883                e);
884        } finally {
885            m_sqlManager.closeAll(dbc, conn, stmt, res);
886        }
887        return groups;
888    }
889
890    /**
891     * @see org.opencms.db.I_CmsUserDriver#getOrganizationalUnits(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit, boolean)
892     */
893    public List<CmsOrganizationalUnit> getOrganizationalUnits(
894        CmsDbContext dbc,
895        CmsOrganizationalUnit parent,
896        boolean includeChildren)
897    throws CmsDataAccessException {
898
899        List<CmsOrganizationalUnit> orgUnits = new ArrayList<CmsOrganizationalUnit>();
900        try {
901            CmsResource parentFolder = internalOrgUnitFolder(dbc, parent);
902            Iterator<CmsResource> itResources = m_driverManager.readResources(
903                dbc,
904                parentFolder,
905                CmsResourceFilter.DEFAULT,
906                includeChildren).iterator();
907            while (itResources.hasNext()) {
908                CmsResource resource = itResources.next();
909                orgUnits.add(internalCreateOrgUnitFromResource(dbc, resource));
910            }
911        } catch (CmsException e) {
912            throw new CmsDataAccessException(e.getMessageContainer(), e);
913        }
914        return orgUnits;
915    }
916
917    /**
918     * @see org.opencms.db.I_CmsUserDriver#getResourcesForOrganizationalUnit(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit)
919     */
920    public List<CmsResource> getResourcesForOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit)
921    throws CmsDataAccessException {
922
923        List<CmsResource> result = new ArrayList<CmsResource>();
924        try {
925            CmsResource ouResource = m_driverManager.readResource(
926                dbc,
927                ORGUNIT_BASE_FOLDER + orgUnit.getName(),
928                CmsResourceFilter.ALL);
929            Iterator<String> itPaths = internalResourcesForOrgUnit(dbc, ouResource).iterator();
930            while (itPaths.hasNext()) {
931                String path = itPaths.next();
932                try {
933                    result.add(m_driverManager.readResource(dbc, path, CmsResourceFilter.ALL));
934                } catch (CmsVfsResourceNotFoundException e) {
935                    if (LOG.isWarnEnabled()) {
936                        LOG.warn(e.getLocalizedMessage(), e);
937                    }
938                }
939            }
940        } catch (CmsException e) {
941            throw new CmsDataAccessException(e.getMessageContainer(), e);
942        }
943        return result;
944    }
945
946    /**
947     * @see org.opencms.db.I_CmsUserDriver#getSqlManager()
948     */
949    public CmsSqlManager getSqlManager() {
950
951        return m_sqlManager;
952    }
953
954    /**
955     * @see org.opencms.db.I_CmsUserDriver#getUsers(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit, boolean)
956     */
957    public List<CmsUser> getUsers(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, boolean recursive)
958    throws CmsDataAccessException {
959
960        return internalGetUsers(dbc, orgUnit, recursive, true);
961    }
962
963    /**
964     * @see org.opencms.db.I_CmsUserDriver#getUsersWithoutAdditionalInfo(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit, boolean)
965     */
966    public List<CmsUser> getUsersWithoutAdditionalInfo(
967        CmsDbContext dbc,
968        CmsOrganizationalUnit orgUnit,
969        boolean recursive)
970    throws CmsDataAccessException {
971
972        return internalGetUsers(dbc, orgUnit, recursive, false);
973    }
974
975    /**
976     * @see org.opencms.db.I_CmsDriver#init(org.opencms.db.CmsDbContext, org.opencms.configuration.CmsConfigurationManager, java.util.List, org.opencms.db.CmsDriverManager)
977     */
978    public void init(
979        CmsDbContext dbc,
980        CmsConfigurationManager configurationManager,
981        List<String> successiveDrivers,
982        CmsDriverManager driverManager) {
983
984        CmsParameterConfiguration config = configurationManager.getConfiguration();
985
986        String poolUrl = config.get("db.user.pool");
987        String classname = config.get("db.user.sqlmanager");
988        m_sqlManager = initSqlManager(classname);
989        m_sqlManager.init(I_CmsUserDriver.DRIVER_TYPE_ID, poolUrl);
990
991        m_driverManager = driverManager;
992
993        if (CmsLog.INIT.isInfoEnabled()) {
994            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ASSIGNED_POOL_1, poolUrl));
995        }
996
997        m_digestAlgorithm = config.getString(CmsDriverManager.CONFIGURATION_DB + ".user.digest.type", "MD5");
998        if (CmsLog.INIT.isInfoEnabled()) {
999            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DIGEST_ALGORITHM_1, m_digestAlgorithm));
1000        }
1001
1002        m_digestFileEncoding = config.getString(
1003            CmsDriverManager.CONFIGURATION_DB + ".user.digest.encoding",
1004            CmsEncoder.ENCODING_UTF_8);
1005        if (CmsLog.INIT.isInfoEnabled()) {
1006            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DIGEST_ENCODING_1, m_digestFileEncoding));
1007        }
1008
1009        // create the digest
1010        try {
1011            m_digest = MessageDigest.getInstance(m_digestAlgorithm);
1012            if (CmsLog.INIT.isInfoEnabled()) {
1013                CmsLog.INIT.info(
1014                    Messages.get().getBundle().key(
1015                        Messages.INIT_DIGEST_ENC_3,
1016                        m_digest.getAlgorithm(),
1017                        m_digest.getProvider().getName(),
1018                        String.valueOf(m_digest.getProvider().getVersion())));
1019            }
1020        } catch (NoSuchAlgorithmException e) {
1021            if (CmsLog.INIT.isInfoEnabled()) {
1022                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SET_DIGEST_ERROR_0), e);
1023            }
1024        }
1025
1026        if ((successiveDrivers != null) && !successiveDrivers.isEmpty()) {
1027            if (LOG.isWarnEnabled()) {
1028                LOG.warn(
1029                    Messages.get().getBundle().key(
1030                        Messages.LOG_SUCCESSIVE_DRIVERS_UNSUPPORTED_1,
1031                        getClass().getName()));
1032            }
1033        }
1034    }
1035
1036    /**
1037     * @see org.opencms.db.I_CmsUserDriver#initSqlManager(String)
1038     */
1039    public org.opencms.db.generic.CmsSqlManager initSqlManager(String classname) {
1040
1041        return CmsSqlManager.getInstance(classname);
1042    }
1043
1044    /**
1045     * @see org.opencms.db.I_CmsUserDriver#publishAccessControlEntries(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsProject, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
1046     */
1047    public void publishAccessControlEntries(
1048        CmsDbContext dbc,
1049        CmsProject offlineProject,
1050        CmsProject onlineProject,
1051        CmsUUID offlineId,
1052        CmsUUID onlineId)
1053    throws CmsDataAccessException {
1054
1055        // at first, we remove all access contries of this resource in the online project
1056        m_driverManager.getUserDriver(dbc).removeAccessControlEntries(dbc, onlineProject, onlineId);
1057
1058        // then, we copy the access control entries from the offline project into the online project
1059        CmsUUID dbcProjectId = dbc.getProjectId();
1060        if ((dbcProjectId != null) && !dbc.getProjectId().isNullUUID()) {
1061            dbc.setProjectId(offlineProject.getUuid());
1062        } else {
1063            dbc.setProjectId(CmsUUID.getNullUUID());
1064        }
1065        List<CmsAccessControlEntry> aces = m_driverManager.getUserDriver(
1066            dbc).readAccessControlEntries(dbc, offlineProject, offlineId, false);
1067        dbc.setProjectId(dbcProjectId);
1068
1069        for (CmsAccessControlEntry ace : aces) {
1070            m_driverManager.getUserDriver(dbc).writeAccessControlEntry(dbc, onlineProject, ace);
1071        }
1072    }
1073
1074    /**
1075     * @see org.opencms.db.I_CmsUserDriver#readAccessControlEntries(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.util.CmsUUID, boolean)
1076     */
1077    public List<CmsAccessControlEntry> readAccessControlEntries(
1078        CmsDbContext dbc,
1079        CmsProject project,
1080        CmsUUID resource,
1081        boolean inheritedOnly)
1082    throws CmsDataAccessException {
1083
1084        List<CmsAccessControlEntry> aceList = new ArrayList<CmsAccessControlEntry>();
1085        PreparedStatement stmt = null;
1086        Connection conn = null;
1087        ResultSet res = null;
1088
1089        try {
1090            conn = m_sqlManager.getConnection(dbc);
1091            if (resource.equals(CmsAccessControlEntry.PRINCIPAL_READALL_ID)) {
1092                stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_READ_ENTRIES_0");
1093            } else {
1094                stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_READ_ENTRIES_1");
1095                String resId = resource.toString();
1096                stmt.setString(1, resId);
1097            }
1098
1099            res = stmt.executeQuery();
1100
1101            // create new CmsAccessControlEntry and add to list
1102            while (res.next()) {
1103                CmsAccessControlEntry ace = internalCreateAce(res);
1104                if (inheritedOnly && !ace.isInheriting()) {
1105                    continue;
1106                }
1107                if (inheritedOnly && ace.isInheriting()) {
1108                    ace.setFlags(CmsAccessControlEntry.ACCESS_FLAGS_INHERITED);
1109                }
1110                aceList.add(ace);
1111            }
1112            return aceList;
1113        } catch (SQLException e) {
1114            throw new CmsDbSqlException(
1115                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1116                e);
1117        } finally {
1118            m_sqlManager.closeAll(dbc, conn, stmt, res);
1119        }
1120    }
1121
1122    /**
1123     * @see org.opencms.db.I_CmsUserDriver#readAccessControlEntry(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
1124     */
1125    public CmsAccessControlEntry readAccessControlEntry(
1126        CmsDbContext dbc,
1127        CmsProject project,
1128        CmsUUID resource,
1129        CmsUUID principal)
1130    throws CmsDataAccessException {
1131
1132        CmsAccessControlEntry ace = null;
1133        PreparedStatement stmt = null;
1134        Connection conn = null;
1135        ResultSet res = null;
1136
1137        try {
1138            conn = m_sqlManager.getConnection(dbc);
1139            stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_READ_ENTRY_2");
1140
1141            stmt.setString(1, resource.toString());
1142            stmt.setString(2, principal.toString());
1143
1144            res = stmt.executeQuery();
1145
1146            // create new CmsAccessControlEntry
1147            if (res.next()) {
1148                ace = internalCreateAce(res);
1149                while (res.next()) {
1150                    // do nothing only move through all rows because of mssql odbc driver
1151                }
1152            } else {
1153                res.close();
1154                res = null;
1155                throw new CmsDbEntryNotFoundException(
1156                    Messages.get().container(Messages.ERR_NO_ACE_FOUND_2, resource, principal));
1157            }
1158
1159            return ace;
1160
1161        } catch (SQLException e) {
1162            throw new CmsDbSqlException(
1163                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1164                e);
1165        } finally {
1166            m_sqlManager.closeAll(dbc, conn, stmt, res);
1167        }
1168    }
1169
1170    /**
1171     * @see org.opencms.db.I_CmsUserDriver#readChildGroups(org.opencms.db.CmsDbContext, java.lang.String)
1172     */
1173    public List<CmsGroup> readChildGroups(CmsDbContext dbc, String parentGroupFqn) throws CmsDataAccessException {
1174
1175        List<CmsGroup> children = new ArrayList<CmsGroup>();
1176        ResultSet res = null;
1177        PreparedStatement stmt = null;
1178        Connection conn = null;
1179        try {
1180            // get parent group
1181            CmsGroup parent = m_driverManager.getUserDriver(dbc).readGroup(dbc, parentGroupFqn);
1182            // parent group exists, so get all children
1183            if (parent != null) {
1184                // create statement
1185                conn = m_sqlManager.getConnection(dbc);
1186                stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_GET_CHILD_1");
1187                stmt.setString(1, parent.getId().toString());
1188                res = stmt.executeQuery();
1189                // create new Cms group objects
1190                while (res.next()) {
1191                    children.add(internalCreateGroup(res));
1192                }
1193            }
1194        } catch (SQLException e) {
1195            throw new CmsDbSqlException(
1196                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1197                e);
1198        } finally {
1199            // close all db-resources
1200            m_sqlManager.closeAll(dbc, conn, stmt, res);
1201        }
1202        return children;
1203    }
1204
1205    /**
1206     * @see org.opencms.db.I_CmsUserDriver#readGroup(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
1207     */
1208    public CmsGroup readGroup(CmsDbContext dbc, CmsUUID groupId) throws CmsDataAccessException {
1209
1210        CmsGroup group = null;
1211        ResultSet res = null;
1212        PreparedStatement stmt = null;
1213        Connection conn = null;
1214
1215        try {
1216            conn = m_sqlManager.getConnection(dbc);
1217            stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_READ_BY_ID_1");
1218
1219            // read the group from the database
1220            stmt.setString(1, groupId.toString());
1221            res = stmt.executeQuery();
1222            // create new Cms group object
1223            if (res.next()) {
1224                group = internalCreateGroup(res);
1225                while (res.next()) {
1226                    // do nothing only move through all rows because of mssql odbc driver
1227                }
1228            } else {
1229                CmsMessageContainer message = Messages.get().container(Messages.ERR_NO_GROUP_WITH_ID_1, groupId);
1230                if (LOG.isDebugEnabled()) {
1231                    LOG.debug(message.key());
1232                }
1233                throw new CmsDbEntryNotFoundException(message);
1234            }
1235
1236        } catch (SQLException e) {
1237            throw new CmsDbSqlException(
1238                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1239                e);
1240        } finally {
1241            m_sqlManager.closeAll(dbc, conn, stmt, res);
1242        }
1243
1244        return group;
1245    }
1246
1247    /**
1248     * @see org.opencms.db.I_CmsUserDriver#readGroup(org.opencms.db.CmsDbContext, java.lang.String)
1249     */
1250    public CmsGroup readGroup(CmsDbContext dbc, String groupFqn) throws CmsDataAccessException {
1251
1252        CmsGroup group = null;
1253        ResultSet res = null;
1254        PreparedStatement stmt = null;
1255        Connection conn = null;
1256
1257        try {
1258            conn = m_sqlManager.getConnection(dbc);
1259            stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_READ_BY_NAME_2");
1260
1261            // read the group from the database
1262            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(groupFqn));
1263            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(groupFqn));
1264            res = stmt.executeQuery();
1265
1266            // create new Cms group object
1267            if (res.next()) {
1268                group = internalCreateGroup(res);
1269                while (res.next()) {
1270                    // do nothing only move through all rows because of mssql odbc driver
1271                }
1272            } else {
1273                CmsMessageContainer message = org.opencms.db.Messages.get().container(
1274                    org.opencms.db.Messages.ERR_UNKNOWN_GROUP_1,
1275                    groupFqn);
1276                if (LOG.isDebugEnabled()) {
1277                    LOG.debug(message.key(), new Exception());
1278                }
1279                throw new CmsDbEntryNotFoundException(message);
1280            }
1281        } catch (SQLException e) {
1282            throw new CmsDbSqlException(
1283                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1284                e);
1285        } finally {
1286            m_sqlManager.closeAll(dbc, conn, stmt, res);
1287        }
1288        return group;
1289    }
1290
1291    /**
1292     * @see org.opencms.db.I_CmsUserDriver#readGroupsOfUser(CmsDbContext, CmsUUID, String, boolean, String, boolean)
1293     */
1294    public List<CmsGroup> readGroupsOfUser(
1295        CmsDbContext dbc,
1296        CmsUUID userId,
1297        String ouFqn,
1298        boolean includeChildOus,
1299        String remoteAddress,
1300        boolean readRoles)
1301    throws CmsDataAccessException {
1302
1303        // compose the query
1304        String sqlQuery = createRoleQuery("C_GROUPS_GET_GROUPS_OF_USER_1", includeChildOus, readRoles);
1305        // adjust parameter to use with LIKE
1306        String ouFqnParam = CmsOrganizationalUnit.SEPARATOR + ouFqn;
1307        if (includeChildOus) {
1308            ouFqnParam += "%";
1309        }
1310
1311        // execute it
1312        List<CmsGroup> groups = new ArrayList<CmsGroup>();
1313
1314        PreparedStatement stmt = null;
1315        ResultSet res = null;
1316        Connection conn = null;
1317
1318        try {
1319            conn = m_sqlManager.getConnection(dbc);
1320            stmt = m_sqlManager.getPreparedStatementForSql(conn, sqlQuery);
1321
1322            //  get all all groups of the user
1323            stmt.setString(1, userId.toString());
1324            stmt.setString(2, ouFqnParam);
1325            stmt.setInt(3, I_CmsPrincipal.FLAG_GROUP_ROLE);
1326
1327            res = stmt.executeQuery();
1328
1329            while (res.next()) {
1330                groups.add(internalCreateGroup(res));
1331            }
1332        } catch (SQLException e) {
1333            throw new CmsDbSqlException(
1334                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1335                e);
1336        } finally {
1337            m_sqlManager.closeAll(dbc, conn, stmt, res);
1338        }
1339        return groups;
1340    }
1341
1342    /**
1343     * @see org.opencms.db.I_CmsUserDriver#readOrganizationalUnit(org.opencms.db.CmsDbContext, String)
1344     */
1345    public CmsOrganizationalUnit readOrganizationalUnit(CmsDbContext dbc, String ouFqn) throws CmsDataAccessException {
1346
1347        try {
1348            CmsResource resource = m_driverManager.readResource(
1349                dbc,
1350                ORGUNIT_BASE_FOLDER + ouFqn,
1351                CmsResourceFilter.DEFAULT);
1352            return internalCreateOrgUnitFromResource(dbc, resource);
1353        } catch (CmsVfsResourceNotFoundException e) {
1354            throw new CmsDbEntryNotFoundException(Messages.get().container(Messages.ERR_READ_ORGUNIT_1, ouFqn), e);
1355        } catch (CmsException e) {
1356            throw new CmsDataAccessException(e.getMessageContainer(), e);
1357        }
1358    }
1359
1360    /**
1361     * @see org.opencms.db.I_CmsUserDriver#readUser(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
1362     */
1363    public CmsUser readUser(CmsDbContext dbc, CmsUUID id) throws CmsDataAccessException {
1364
1365        PreparedStatement stmt = null;
1366        ResultSet res = null;
1367        CmsUser user = null;
1368        Connection conn = null;
1369
1370        try {
1371            conn = m_sqlManager.getConnection(dbc);
1372            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_READ_BY_ID_1");
1373
1374            stmt.setString(1, id.toString());
1375            res = stmt.executeQuery();
1376
1377            // create new Cms user object
1378            if (res.next()) {
1379                user = internalCreateUser(dbc, res);
1380                while (res.next()) {
1381                    // do nothing only move through all rows because of mssql odbc driver
1382                }
1383            } else {
1384                CmsMessageContainer message = Messages.get().container(Messages.ERR_NO_USER_WITH_ID_1, id);
1385                if (LOG.isDebugEnabled()) {
1386                    LOG.debug(message.key());
1387                }
1388                throw new CmsDbEntryNotFoundException(message);
1389            }
1390        } catch (SQLException e) {
1391            throw new CmsDbSqlException(
1392                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1393                e);
1394        } finally {
1395            m_sqlManager.closeAll(dbc, conn, stmt, res);
1396        }
1397
1398        Map<String, Object> info = readUserInfos(dbc, user.getId());
1399        user.setAdditionalInfo(info);
1400        return user;
1401    }
1402
1403    /**
1404     * @see org.opencms.db.I_CmsUserDriver#readUser(org.opencms.db.CmsDbContext, java.lang.String)
1405     */
1406    public CmsUser readUser(CmsDbContext dbc, String userFqn) throws CmsDataAccessException {
1407
1408        PreparedStatement stmt = null;
1409        ResultSet res = null;
1410        CmsUser user = null;
1411        Connection conn = null;
1412
1413        try {
1414            conn = m_sqlManager.getConnection(dbc);
1415            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_READ_BY_NAME_2");
1416            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(userFqn));
1417            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(userFqn));
1418
1419            res = stmt.executeQuery();
1420
1421            if (res.next()) {
1422                user = internalCreateUser(dbc, res);
1423                while (res.next()) {
1424                    // do nothing only move through all rows because of mssql odbc driver
1425                }
1426            } else {
1427                CmsMessageContainer message = org.opencms.db.Messages.get().container(
1428                    org.opencms.db.Messages.ERR_UNKNOWN_USER_1,
1429                    userFqn);
1430                if (LOG.isDebugEnabled()) {
1431                    LOG.debug(message.key());
1432                }
1433                throw new CmsDbEntryNotFoundException(message);
1434            }
1435        } catch (SQLException e) {
1436            throw new CmsDbSqlException(
1437                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1438                e);
1439        } finally {
1440            m_sqlManager.closeAll(dbc, conn, stmt, res);
1441        }
1442
1443        Map<String, Object> info = readUserInfos(dbc, user.getId());
1444        user.setAdditionalInfo(info);
1445        return user;
1446    }
1447
1448    /**
1449     * @see org.opencms.db.I_CmsUserDriver#readUser(org.opencms.db.CmsDbContext, java.lang.String, java.lang.String, String)
1450     */
1451    public CmsUser readUser(CmsDbContext dbc, String userFqn, String password, String remoteAddress)
1452    throws CmsDataAccessException {
1453
1454        PreparedStatement stmt = null;
1455        ResultSet res = null;
1456        CmsUser user = null;
1457        Connection conn = null;
1458
1459        try {
1460            conn = m_sqlManager.getConnection(dbc);
1461            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_READ_BY_NAME_2");
1462            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(userFqn));
1463            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(userFqn));
1464            res = stmt.executeQuery();
1465
1466            boolean success = false;
1467            // create the user object
1468            if (res.next()) {
1469                user = internalCreateUser(dbc, res);
1470                // validate the password stored for the user
1471                success = OpenCms.getPasswordHandler().checkPassword(password, user.getPassword(), true);
1472
1473                while (res.next()) {
1474                    // do nothing only move through all rows because of mssql odbc driver
1475                }
1476            }
1477            if (!success) {
1478                CmsMessageContainer message = org.opencms.db.Messages.get().container(
1479                    org.opencms.db.Messages.ERR_UNKNOWN_USER_1,
1480                    userFqn);
1481                if (LOG.isDebugEnabled()) {
1482                    LOG.debug(message.key());
1483                }
1484                throw new CmsDbEntryNotFoundException(message);
1485            }
1486        } catch (SQLException e) {
1487            throw new CmsDbSqlException(
1488                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1489                e);
1490        } finally {
1491            m_sqlManager.closeAll(dbc, conn, stmt, res);
1492        }
1493
1494        @SuppressWarnings("null")
1495        Map<String, Object> info = readUserInfos(dbc, user.getId());
1496        user.setAdditionalInfo(info);
1497        return user;
1498    }
1499
1500    /**
1501     * @see org.opencms.db.I_CmsUserDriver#readUserInfos(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID)
1502     */
1503    public Map<String, Object> readUserInfos(CmsDbContext dbc, CmsUUID userId) throws CmsDataAccessException {
1504
1505        Map<String, Object> infos = new HashMap<String, Object>();
1506
1507        ResultSet res = null;
1508        PreparedStatement stmt = null;
1509        Connection conn = null;
1510        try {
1511            // create statement
1512            conn = m_sqlManager.getConnection(dbc);
1513            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERDATA_READ_1");
1514
1515            stmt.setString(1, userId.toString());
1516            res = stmt.executeQuery();
1517            // read the infos
1518            while (res.next()) {
1519                String key = res.getString(m_sqlManager.readQuery("C_USERDATA_KEY_0"));
1520                String type = res.getString(m_sqlManager.readQuery("C_USERDATA_TYPE_0"));
1521                byte[] value = m_sqlManager.getBytes(res, m_sqlManager.readQuery("C_USERDATA_VALUE_0"));
1522                // deserialize
1523                Object data = null;
1524                try {
1525
1526                    if (LOG.isDebugEnabled()) {
1527                        LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_READUSERINFO_2, key, type));
1528                        if (value != null) {
1529                            try {
1530                                LOG.debug(
1531                                    Messages.get().getBundle().key(
1532                                        Messages.LOG_DBG_READUSERINFO_VALUE_1,
1533                                        new String(value)));
1534                            } catch (Exception e) {
1535                                // noop
1536                            }
1537                        } else {
1538                            LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_READUSERINFO_VALUE_1, null));
1539                        }
1540                    }
1541
1542                    data = CmsDataTypeUtil.dataDeserialize(value, type);
1543
1544                } catch (Exception e) {
1545                    LOG.error(
1546                        Messages.get().container(Messages.ERR_READING_ADDITIONAL_INFO_1, userId.toString()).key(),
1547                        e);
1548                }
1549                if ((key != null) && (data != null)) {
1550                    infos.put(key, data);
1551                }
1552            }
1553        } catch (SQLException e) {
1554            throw new CmsDbSqlException(
1555                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1556                e);
1557        } finally {
1558            m_sqlManager.closeAll(dbc, conn, stmt, res);
1559        }
1560
1561        return infos;
1562    }
1563
1564    /**
1565     * @see org.opencms.db.I_CmsUserDriver#readUsersOfGroup(CmsDbContext, String, boolean)
1566     */
1567    public List<CmsUser> readUsersOfGroup(CmsDbContext dbc, String groupFqn, boolean includeOtherOuUsers)
1568    throws CmsDataAccessException {
1569
1570        String sqlQuery = "C_GROUPS_GET_USERS_OF_GROUP_2";
1571        if (includeOtherOuUsers) {
1572            sqlQuery = "C_GROUPS_GET_ALL_USERS_OF_GROUP_2";
1573        }
1574
1575        List<CmsUser> users = new ArrayList<CmsUser>();
1576
1577        PreparedStatement stmt = null;
1578        ResultSet res = null;
1579        Connection conn = null;
1580
1581        try {
1582            conn = m_sqlManager.getConnection(dbc);
1583            stmt = m_sqlManager.getPreparedStatement(conn, sqlQuery);
1584            stmt.setString(1, CmsOrganizationalUnit.getSimpleName(groupFqn));
1585            stmt.setString(2, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(groupFqn));
1586
1587            res = stmt.executeQuery();
1588
1589            while (res.next()) {
1590                users.add(internalCreateUser(dbc, res));
1591            }
1592        } catch (SQLException e) {
1593            throw new CmsDbSqlException(
1594                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1595                e);
1596        } finally {
1597            m_sqlManager.closeAll(dbc, conn, stmt, res);
1598        }
1599
1600        for (CmsUser user : users) {
1601            Map<String, Object> info = readUserInfos(dbc, user.getId());
1602            user.setAdditionalInfo(info);
1603        }
1604        return users;
1605    }
1606
1607    /**
1608     * @see org.opencms.db.I_CmsUserDriver#removeAccessControlEntries(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.util.CmsUUID)
1609     */
1610    public void removeAccessControlEntries(CmsDbContext dbc, CmsProject project, CmsUUID resource)
1611    throws CmsDataAccessException {
1612
1613        PreparedStatement stmt = null;
1614        Connection conn = null;
1615
1616        try {
1617            conn = m_sqlManager.getConnection(dbc);
1618            stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_REMOVE_ALL_1");
1619
1620            stmt.setString(1, resource.toString());
1621
1622            stmt.executeUpdate();
1623
1624        } catch (SQLException e) {
1625            throw new CmsDbSqlException(
1626                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1627                e);
1628        } finally {
1629            m_sqlManager.closeAll(dbc, conn, stmt, null);
1630        }
1631    }
1632
1633    /**
1634     * @see org.opencms.db.I_CmsUserDriver#removeAccessControlEntriesForPrincipal(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.file.CmsProject, org.opencms.util.CmsUUID)
1635     */
1636    public void removeAccessControlEntriesForPrincipal(
1637        CmsDbContext dbc,
1638        CmsProject project,
1639        CmsProject onlineProject,
1640        CmsUUID principal)
1641    throws CmsDataAccessException {
1642
1643        PreparedStatement stmt = null;
1644        Connection conn = null;
1645        // TODO: refactor for only one project at a time
1646        if (dbc.getProjectId().isNullUUID()) {
1647            // offline project available
1648            try {
1649                conn = m_sqlManager.getConnection(dbc);
1650                stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_REMOVE_ALL_FOR_PRINCIPAL_1");
1651                stmt.setString(1, principal.toString());
1652                stmt.executeUpdate();
1653            } catch (SQLException e) {
1654                throw new CmsDbSqlException(
1655                    Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1656                    e);
1657            } finally {
1658                m_sqlManager.closeAll(dbc, conn, stmt, null);
1659            }
1660        }
1661
1662        try {
1663            conn = m_sqlManager.getConnection(dbc);
1664            stmt = m_sqlManager.getPreparedStatement(conn, onlineProject, "C_ACCESS_REMOVE_ALL_FOR_PRINCIPAL_1");
1665            stmt.setString(1, principal.toString());
1666            stmt.executeUpdate();
1667        } catch (SQLException e) {
1668            throw new CmsDbSqlException(
1669                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1670                e);
1671        } finally {
1672            m_sqlManager.closeAll(dbc, conn, stmt, null);
1673        }
1674    }
1675
1676    /**
1677     * @see org.opencms.db.I_CmsUserDriver#removeAccessControlEntry(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
1678     */
1679    public void removeAccessControlEntry(CmsDbContext dbc, CmsProject project, CmsUUID resource, CmsUUID principal)
1680    throws CmsDataAccessException {
1681
1682        PreparedStatement stmt = null;
1683        Connection conn = null;
1684
1685        try {
1686            conn = m_sqlManager.getConnection(dbc);
1687            stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_REMOVE_2");
1688
1689            stmt.setString(1, resource.toString());
1690            stmt.setString(2, principal.toString());
1691            stmt.executeUpdate();
1692
1693        } catch (SQLException e) {
1694            throw new CmsDbSqlException(
1695                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1696                e);
1697        } finally {
1698            m_sqlManager.closeAll(dbc, conn, stmt, null);
1699        }
1700    }
1701
1702    /**
1703     * @see org.opencms.db.I_CmsUserDriver#removeResourceFromOrganizationalUnit(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit, CmsResource)
1704     */
1705    public void removeResourceFromOrganizationalUnit(
1706        CmsDbContext dbc,
1707        CmsOrganizationalUnit orgUnit,
1708        CmsResource resource)
1709    throws CmsDataAccessException {
1710
1711        // check for root ou
1712        if (orgUnit.getParentFqn() == null) {
1713            throw new CmsDataAccessException(
1714                org.opencms.security.Messages.get().container(
1715                    org.opencms.security.Messages.ERR_ORGUNIT_ROOT_EDITION_0));
1716        }
1717
1718        try {
1719            // read the representing resource
1720            CmsResource ouResource = m_driverManager.readResource(
1721                dbc,
1722                ORGUNIT_BASE_FOLDER + orgUnit.getName(),
1723                CmsResourceFilter.ALL);
1724
1725            // get the associated resources
1726            List<String> vfsPaths = new ArrayList<String>(internalResourcesForOrgUnit(dbc, ouResource));
1727
1728            // check if associated
1729            if (!vfsPaths.contains(resource.getRootPath())) {
1730                throw new CmsDataAccessException(
1731                    Messages.get().container(
1732                        Messages.ERR_ORGUNIT_DOESNOT_CONTAINS_RESOURCE_2,
1733                        orgUnit.getName(),
1734                        dbc.removeSiteRoot(resource.getRootPath())));
1735            }
1736            if ((vfsPaths.size() == 1) && !orgUnit.hasFlagWebuser()) {
1737                // normal ous have to have at least one resource
1738                throw new CmsDataAccessException(
1739                    Messages.get().container(
1740                        Messages.ERR_ORGUNIT_REMOVE_LAST_RESOURCE_2,
1741                        orgUnit.getName(),
1742                        dbc.removeSiteRoot(resource.getRootPath())));
1743            }
1744
1745            // remove the resource
1746            CmsRelationFilter filter = CmsRelationFilter.TARGETS.filterPath(resource.getRootPath());
1747            m_driverManager.getVfsDriver(dbc).deleteRelations(dbc, dbc.currentProject().getUuid(), ouResource, filter);
1748            m_driverManager.getVfsDriver(dbc).deleteRelations(dbc, CmsProject.ONLINE_PROJECT_ID, ouResource, filter);
1749
1750            try {
1751                // be sure the project was not deleted
1752                CmsProject project = m_driverManager.readProject(dbc, orgUnit.getProjectId());
1753                // maintain the default project synchronized
1754                m_driverManager.getProjectDriver(dbc).deleteProjectResource(
1755                    dbc,
1756                    orgUnit.getProjectId(),
1757                    resource.getRootPath());
1758
1759                OpenCms.fireCmsEvent(
1760                    I_CmsEventListener.EVENT_PROJECT_MODIFIED,
1761                    Collections.<String, Object> singletonMap("project", project));
1762            } catch (CmsDbEntryNotFoundException e) {
1763                // ignore
1764            } finally {
1765                Map<String, Object> data = new HashMap<String, Object>(2);
1766                data.put(I_CmsEventListener.KEY_RESOURCE, ouResource);
1767                data.put(I_CmsEventListener.KEY_CHANGE, Integer.valueOf(CmsDriverManager.CHANGED_RESOURCE));
1768                OpenCms.fireCmsEvent(new CmsEvent(I_CmsEventListener.EVENT_RESOURCE_MODIFIED, data));
1769            }
1770        } catch (CmsException e) {
1771            throw new CmsDataAccessException(e.getMessageContainer(), e);
1772        }
1773    }
1774
1775    /**
1776     * @see org.opencms.db.I_CmsUserDriver#searchUsers(org.opencms.db.CmsDbContext, org.opencms.file.CmsUserSearchParameters)
1777     */
1778    public List<CmsUser> searchUsers(CmsDbContext dbc, CmsUserSearchParameters searchParams)
1779    throws CmsDataAccessException {
1780
1781        List<CmsUser> users = new ArrayList<CmsUser>();
1782        CmsPair<String, List<Object>> queryAndParams = createUserQuery(searchParams, false);
1783        ResultSet res = null;
1784        PreparedStatement stmt = null;
1785        Connection conn = null;
1786        try {
1787            conn = m_sqlManager.getConnection(dbc);
1788            stmt = m_sqlManager.getPreparedStatementForSql(conn, queryAndParams.getFirst());
1789            CmsDbUtil.fillParameters(stmt, queryAndParams.getSecond());
1790            res = stmt.executeQuery();
1791            while (res.next()) {
1792                CmsUser user = internalCreateUser(dbc, res);
1793                users.add(user);
1794            }
1795        } catch (SQLException e) {
1796            throw new CmsDbSqlException(
1797                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1798                e);
1799        } finally {
1800            m_sqlManager.closeAll(dbc, conn, stmt, res);
1801        }
1802        for (CmsUser user : users) {
1803            Map<String, Object> info = readUserInfos(dbc, user.getId());
1804            user.setAdditionalInfo(info);
1805        }
1806        return users;
1807    }
1808
1809    /**
1810     * @see org.opencms.db.I_CmsUserDriver#setDriverManager(org.opencms.db.CmsDriverManager)
1811     */
1812    public void setDriverManager(CmsDriverManager driverManager) {
1813
1814        m_driverManager = driverManager;
1815    }
1816
1817    /**
1818     * @see org.opencms.db.I_CmsUserDriver#setSqlManager(org.opencms.db.CmsSqlManager)
1819     */
1820    public void setSqlManager(org.opencms.db.CmsSqlManager sqlManager) {
1821
1822        m_sqlManager = (CmsSqlManager)sqlManager;
1823    }
1824
1825    /**
1826     * @see org.opencms.db.I_CmsUserDriver#setUsersOrganizationalUnit(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit, org.opencms.file.CmsUser)
1827     */
1828    public void setUsersOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, CmsUser user)
1829    throws CmsDataAccessException {
1830
1831        PreparedStatement stmt = null;
1832        Connection conn = null;
1833
1834        try {
1835            conn = m_sqlManager.getConnection(dbc);
1836            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_SET_ORGUNIT_2");
1837
1838            if (orgUnit == null) {
1839                stmt.setString(1, null);
1840            } else {
1841                stmt.setString(1, CmsOrganizationalUnit.SEPARATOR + orgUnit.getName());
1842            }
1843            stmt.setString(2, user.getId().toString());
1844
1845            stmt.executeUpdate();
1846        } catch (SQLException e) {
1847            throw new CmsDbSqlException(
1848                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1849                e);
1850        } finally {
1851            m_sqlManager.closeAll(dbc, conn, stmt, null);
1852        }
1853    }
1854
1855    /**
1856     * @see org.opencms.db.I_CmsUserDriver#writeAccessControlEntry(org.opencms.db.CmsDbContext, org.opencms.file.CmsProject, org.opencms.security.CmsAccessControlEntry)
1857     */
1858    public void writeAccessControlEntry(CmsDbContext dbc, CmsProject project, CmsAccessControlEntry acEntry)
1859    throws CmsDataAccessException {
1860
1861        PreparedStatement stmt = null;
1862        Connection conn = null;
1863        ResultSet res = null;
1864        CmsAccessControlEntry ace = null;
1865
1866        try {
1867            conn = m_sqlManager.getConnection(dbc);
1868            stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_READ_ENTRY_2");
1869
1870            stmt.setString(1, acEntry.getResource().toString());
1871            stmt.setString(2, acEntry.getPrincipal().toString());
1872
1873            res = stmt.executeQuery();
1874            if (res.next()) {
1875                ace = internalCreateAce(res);
1876            }
1877
1878        } catch (SQLException e) {
1879            throw new CmsDbSqlException(
1880                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1881                e);
1882        } finally {
1883            m_sqlManager.closeAll(dbc, conn, stmt, res);
1884        }
1885
1886        if (ace == null) {
1887            m_driverManager.getUserDriver(dbc).createAccessControlEntry(
1888                dbc,
1889                project,
1890                acEntry.getResource(),
1891                acEntry.getPrincipal(),
1892                acEntry.getAllowedPermissions(),
1893                acEntry.getDeniedPermissions(),
1894                acEntry.getFlags());
1895            return;
1896        } else {
1897            try {
1898                conn = m_sqlManager.getConnection(dbc);
1899
1900                // otherwise update the already existing entry
1901                stmt = m_sqlManager.getPreparedStatement(conn, project, "C_ACCESS_UPDATE_5");
1902
1903                stmt.setInt(1, acEntry.getAllowedPermissions());
1904                stmt.setInt(2, acEntry.getDeniedPermissions());
1905                stmt.setInt(3, acEntry.getFlags());
1906                stmt.setString(4, acEntry.getResource().toString());
1907                stmt.setString(5, acEntry.getPrincipal().toString());
1908
1909                stmt.executeUpdate();
1910            } catch (SQLException e) {
1911                throw new CmsDbSqlException(
1912                    Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1913                    e);
1914            } finally {
1915                m_sqlManager.closeAll(dbc, conn, stmt, null);
1916            }
1917        }
1918
1919    }
1920
1921    /**
1922     * @see org.opencms.db.I_CmsUserDriver#writeGroup(org.opencms.db.CmsDbContext, org.opencms.file.CmsGroup)
1923     */
1924    public void writeGroup(CmsDbContext dbc, CmsGroup group) throws CmsDataAccessException {
1925
1926        PreparedStatement stmt = null;
1927        Connection conn = null;
1928        if (group != null) {
1929            try {
1930                conn = getSqlManager().getConnection(dbc);
1931                stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_WRITE_GROUP_4");
1932
1933                stmt.setString(1, m_sqlManager.validateEmpty(group.getDescription()));
1934                stmt.setInt(2, group.getFlags());
1935                stmt.setString(3, group.getParentId().toString());
1936                stmt.setString(4, group.getId().toString());
1937                stmt.executeUpdate();
1938
1939            } catch (SQLException e) {
1940                throw new CmsDbSqlException(
1941                    Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
1942                    e);
1943            } finally {
1944                m_sqlManager.closeAll(dbc, conn, stmt, null);
1945            }
1946        } else {
1947            throw new CmsDbEntryNotFoundException(
1948                org.opencms.db.Messages.get().container(org.opencms.db.Messages.ERR_UNKNOWN_GROUP_1, "null"));
1949        }
1950    }
1951
1952    /**
1953     * @see org.opencms.db.I_CmsUserDriver#writeOrganizationalUnit(org.opencms.db.CmsDbContext, org.opencms.security.CmsOrganizationalUnit)
1954     */
1955    public void writeOrganizationalUnit(CmsDbContext dbc, CmsOrganizationalUnit organizationalUnit)
1956    throws CmsDataAccessException {
1957
1958        try {
1959            CmsResource resource = m_driverManager.readResource(
1960                dbc,
1961                organizationalUnit.getId(),
1962                CmsResourceFilter.DEFAULT);
1963
1964            // write the properties
1965            internalWriteOrgUnitProperty(
1966                dbc,
1967                resource,
1968                new CmsProperty(ORGUNIT_PROPERTY_DESCRIPTION, organizationalUnit.getDescription(), null));
1969
1970            CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID())
1971            ? dbc.currentProject().getUuid()
1972            : dbc.getProjectId();
1973            // update the resource flags
1974            resource.setFlags(organizationalUnit.getFlags() | CmsResource.FLAG_INTERNAL);
1975            m_driverManager.writeResource(dbc, resource);
1976            resource.setState(CmsResource.STATE_UNCHANGED);
1977            m_driverManager.getVfsDriver(dbc).writeResource(dbc, projectId, resource, CmsDriverManager.NOTHING_CHANGED);
1978
1979            if (!dbc.currentProject().isOnlineProject()) {
1980                // online persistence
1981                CmsProject onlineProject = m_driverManager.readProject(dbc, CmsProject.ONLINE_PROJECT_ID);
1982                resource.setState(CmsResource.STATE_UNCHANGED);
1983                m_driverManager.getVfsDriver(
1984                    dbc).writeResource(dbc, onlineProject.getUuid(), resource, CmsDriverManager.NOTHING_CHANGED);
1985            }
1986
1987            OpenCms.fireCmsEvent(I_CmsEventListener.EVENT_CLEAR_ONLINE_CACHES, null);
1988        } catch (CmsException e) {
1989            throw new CmsDataAccessException(e.getMessageContainer(), e);
1990        }
1991    }
1992
1993    /**
1994     * @see org.opencms.db.I_CmsUserDriver#writePassword(org.opencms.db.CmsDbContext, java.lang.String, java.lang.String, java.lang.String)
1995     */
1996    public void writePassword(CmsDbContext dbc, String userFqn, String oldPassword, String newPassword)
1997    throws CmsDataAccessException, CmsPasswordEncryptionException {
1998
1999        PreparedStatement stmt = null;
2000        Connection conn = null;
2001
2002        // check if the old password is valid
2003        if (oldPassword != null) {
2004            readUser(dbc, userFqn, oldPassword, "");
2005        }
2006        String pwd = newPassword;
2007        if (dbc.getRequestContext().getAttribute(REQ_ATTR_DONT_DIGEST_PASSWORD) == null) {
2008            pwd = OpenCms.getPasswordHandler().digest(newPassword);
2009        }
2010
2011        try {
2012            conn = getSqlManager().getConnection(dbc);
2013            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_SET_PWD_3");
2014            stmt.setString(1, pwd);
2015            stmt.setString(2, CmsOrganizationalUnit.getSimpleName(userFqn));
2016            stmt.setString(3, CmsOrganizationalUnit.SEPARATOR + CmsOrganizationalUnit.getParentFqn(userFqn));
2017            stmt.executeUpdate();
2018        } catch (SQLException e) {
2019            throw new CmsDbSqlException(
2020                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2021                e);
2022        } finally {
2023            m_sqlManager.closeAll(dbc, conn, stmt, null);
2024        }
2025    }
2026
2027    /**
2028     * @see org.opencms.db.I_CmsUserDriver#writeUser(org.opencms.db.CmsDbContext, org.opencms.file.CmsUser)
2029     */
2030    public void writeUser(CmsDbContext dbc, CmsUser user) throws CmsDataAccessException {
2031
2032        // get the login attribute
2033        String att_login = (String)dbc.getAttribute(CmsDriverManager.ATTRIBUTE_LOGIN);
2034
2035        PreparedStatement stmt = null;
2036        Connection conn = null;
2037
2038        // if the login attribute is set, do only update the last login information of this user
2039        // otherwise write the complete user data
2040        if (CmsStringUtil.isNotEmpty(att_login)) {
2041
2042            try {
2043                conn = getSqlManager().getConnection(dbc);
2044                stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_WRITE_2");
2045                // write data to database
2046                stmt.setLong(1, user.getLastlogin());
2047                stmt.setString(2, user.getId().toString());
2048                stmt.executeUpdate();
2049            } catch (SQLException e) {
2050                throw new CmsDbSqlException(
2051                    Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2052                    e);
2053            } finally {
2054                m_sqlManager.closeAll(dbc, conn, stmt, null);
2055            }
2056            // store user info values which may have been modified by the login code
2057            internalWriteUserInfos(dbc, user.getId(), user.getAdditionalInfo());
2058        } else {
2059
2060            try {
2061                conn = getSqlManager().getConnection(dbc);
2062                stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_WRITE_6");
2063                // write data to database
2064                stmt.setString(1, m_sqlManager.validateEmpty(user.getFirstname()));
2065                stmt.setString(2, m_sqlManager.validateEmpty(user.getLastname()));
2066                stmt.setString(3, m_sqlManager.validateEmpty(user.getEmail()));
2067                stmt.setLong(4, user.getLastlogin());
2068                stmt.setInt(5, user.getFlags());
2069                stmt.setString(6, user.getId().toString());
2070                stmt.executeUpdate();
2071            } catch (SQLException e) {
2072                throw new CmsDbSqlException(
2073                    Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2074                    e);
2075            } finally {
2076                m_sqlManager.closeAll(dbc, conn, stmt, null);
2077            }
2078            internalWriteUserInfos(dbc, user.getId(), user.getAdditionalInfo());
2079        }
2080    }
2081
2082    /**
2083     * @see org.opencms.db.I_CmsUserDriver#writeUserInfo(org.opencms.db.CmsDbContext, org.opencms.util.CmsUUID, java.lang.String, java.lang.Object)
2084     */
2085    public void writeUserInfo(CmsDbContext dbc, CmsUUID userId, String key, Object value)
2086    throws CmsDataAccessException {
2087
2088        // analyse the dbc attribute what to do here
2089        String mode = (String)dbc.getAttribute(ATTRIBUTE_USERADDINFO);
2090
2091        // delete the user info
2092        if (CmsStringUtil.isNotEmpty(mode) && mode.equals(ATTRIBUTE_USERADDINFO_VALUE_DELETE)) {
2093            internalDeleteUserInfo(dbc, userId, key);
2094        } else if (CmsStringUtil.isNotEmpty(mode) && mode.equals(ATTRIBUTE_USERADDINFO_VALUE_UPDATE)) {
2095            internalUpdateUserInfo(dbc, userId, key, value);
2096        } else {
2097            // default is to insert or update a new value
2098            internalWriteUserInfo(dbc, userId, key, value);
2099        }
2100    }
2101
2102    /**
2103     * Returns a sql query to select groups.<p>
2104     *
2105     * @param mainQuery the main select sql query
2106     * @param includeSubOus if groups in sub-ous should be included in the selection
2107     * @param readRoles if groups or roles whould be selected
2108     *
2109     * @return a sql query to select groups
2110     */
2111    protected String createRoleQuery(String mainQuery, boolean includeSubOus, boolean readRoles) {
2112
2113        String sqlQuery = m_sqlManager.readQuery(mainQuery);
2114        sqlQuery += " ";
2115        if (includeSubOus) {
2116            sqlQuery += m_sqlManager.readQuery("C_GROUPS_GROUP_OU_LIKE_1");
2117        } else {
2118            sqlQuery += m_sqlManager.readQuery("C_GROUPS_GROUP_OU_EQUALS_1");
2119        }
2120        sqlQuery += AND_CONDITION;
2121        if (readRoles) {
2122            sqlQuery += m_sqlManager.readQuery("C_GROUPS_SELECT_ROLES_1");
2123        } else {
2124            sqlQuery += m_sqlManager.readQuery("C_GROUPS_SELECT_GROUPS_1");
2125        }
2126        sqlQuery += " ";
2127        sqlQuery += m_sqlManager.readQuery("C_GROUPS_ORDER_0");
2128        return sqlQuery;
2129    }
2130
2131    /**
2132     * Creates a query for searching users.<p>
2133     *
2134     * @param searchParams the user search criteria
2135     * @param countOnly if true, the query will only count the total number of results instead of returning them
2136     *
2137     * @return a pair consisting of the query string and its parameters
2138     */
2139    protected CmsPair<String, List<Object>> createUserQuery(CmsUserSearchParameters searchParams, boolean countOnly) {
2140
2141        CmsUserQueryBuilder queryBuilder = createUserQueryBuilder();
2142        return queryBuilder.createUserQuery(searchParams, countOnly);
2143    }
2144
2145    /**
2146     * Creates a new user query builder.<p>
2147     *
2148     * @return the new user query builder
2149     */
2150    protected CmsUserQueryBuilder createUserQueryBuilder() {
2151
2152        return new CmsUserQueryBuilder();
2153    }
2154
2155    /**
2156     * Internal helper method to create an access control entry from a database record.<p>
2157     *
2158     * @param res resultset of the current query
2159     *
2160     * @return a new {@link CmsAccessControlEntry} initialized with the values from the current database record
2161     *
2162     * @throws SQLException if something goes wrong
2163     */
2164    protected CmsAccessControlEntry internalCreateAce(ResultSet res) throws SQLException {
2165
2166        return internalCreateAce(res, new CmsUUID(res.getString(m_sqlManager.readQuery("C_ACCESS_RESOURCE_ID_0"))));
2167    }
2168
2169    /**
2170     * Internal helper method to create an access control entry from a database record.<p>
2171     *
2172     * @param res resultset of the current query
2173     * @param newId the id of the new access control entry
2174     *
2175     * @return a new {@link CmsAccessControlEntry} initialized with the values from the current database record
2176     *
2177     * @throws SQLException if something goes wrong
2178     */
2179    protected CmsAccessControlEntry internalCreateAce(ResultSet res, CmsUUID newId) throws SQLException {
2180
2181        return new CmsAccessControlEntry(
2182            newId,
2183            new CmsUUID(res.getString(m_sqlManager.readQuery("C_ACCESS_PRINCIPAL_ID_0"))),
2184            res.getInt(m_sqlManager.readQuery("C_ACCESS_ACCESS_ALLOWED_0")),
2185            res.getInt(m_sqlManager.readQuery("C_ACCESS_ACCESS_DENIED_0")),
2186            res.getInt(m_sqlManager.readQuery("C_ACCESS_ACCESS_FLAGS_0")));
2187    }
2188
2189    /**
2190     * Creates the default groups and user for the given organizational unit.<p>
2191     *
2192     * @param dbc the database context
2193     * @param ouFqn the fully qualified name of the organizational unit to create the principals for
2194     * @param ouDescription the description of the given organizational unit
2195     * @param webuser the webuser ou flag
2196     *
2197     * @throws CmsException if something goes wrong
2198     */
2199    protected void internalCreateDefaultGroups(CmsDbContext dbc, String ouFqn, String ouDescription, boolean webuser)
2200    throws CmsException {
2201
2202        // create roles
2203        String rootAdminRole = CmsRole.ROOT_ADMIN.getGroupName();
2204        boolean isRootOu = CmsOrganizationalUnit.getParentFqn(ouFqn) == null;
2205        try {
2206            for (CmsRole role : CmsRole.getSystemRoles()) {
2207                if (webuser && (role != CmsRole.ACCOUNT_MANAGER)) {
2208                    // if webuser ou and not account manager role
2209                    continue;
2210                }
2211                if (role.isOrganizationalUnitIndependent() && !isRootOu) {
2212                    // if role is ou independent and not in the root ou
2213                    continue;
2214                }
2215                String groupName = ouFqn + role.getGroupName();
2216                int flags = I_CmsPrincipal.FLAG_ENABLED | I_CmsPrincipal.FLAG_GROUP_ROLE;
2217                if (!existsGroup(dbc, groupName)) {
2218                    createGroup(dbc, CmsUUID.getConstantUUID(groupName), groupName, "A system role group", flags, null);
2219                }
2220            }
2221            if (isRootOu && CmsLog.INIT.isInfoEnabled()) {
2222                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SYSTEM_ROLES_CREATED_0));
2223            }
2224        } catch (CmsException e) {
2225            if (isRootOu && CmsLog.INIT.isErrorEnabled()) {
2226                CmsLog.INIT.error(Messages.get().getBundle().key(Messages.INIT_SYSTEM_ROLES_CREATION_FAILED_0), e);
2227            }
2228            throw new CmsInitException(Messages.get().container(Messages.ERR_INITIALIZING_USER_DRIVER_0), e);
2229        }
2230
2231        if (dbc.getAttribute(CmsDriverManager.ATTR_INIT_OU) != null) {
2232            return;
2233        }
2234
2235        if (webuser) {
2236            // no default groups for webuser ou
2237            return;
2238        }
2239
2240        // create groups
2241        String administratorsGroup = ouFqn + OpenCms.getDefaultUsers().getGroupAdministrators();
2242        String guestGroup = ouFqn + OpenCms.getDefaultUsers().getGroupGuests();
2243        String usersGroup = ouFqn + OpenCms.getDefaultUsers().getGroupUsers();
2244        String guestUser = ouFqn + OpenCms.getDefaultUsers().getUserGuest();
2245        String adminUser = ouFqn + OpenCms.getDefaultUsers().getUserAdmin();
2246        String exportUser = ouFqn + OpenCms.getDefaultUsers().getUserExport();
2247        String deleteUser = ouFqn + OpenCms.getDefaultUsers().getUserDeletedResource();
2248
2249        if (existsGroup(dbc, administratorsGroup)) {
2250            if (isRootOu) {
2251                // check the flags of existing groups, for compatibility checks
2252                internalUpdateRoleGroup(dbc, administratorsGroup, CmsRole.ROOT_ADMIN);
2253                internalUpdateRoleGroup(dbc, usersGroup, CmsRole.ELEMENT_AUTHOR.forOrgUnit(ouFqn));
2254            }
2255            return;
2256        }
2257        String parentOu = CmsOrganizationalUnit.getParentFqn(ouFqn);
2258        String groupDescription = (CmsStringUtil.isNotEmptyOrWhitespaceOnly(ouDescription)
2259        ? CmsMacroResolver.localizedKeyMacro(
2260            Messages.GUI_DEFAULTGROUP_OU_USERS_DESCRIPTION_1,
2261            new String[] {ouDescription})
2262        : CmsMacroResolver.localizedKeyMacro(Messages.GUI_DEFAULTGROUP_ROOT_USERS_DESCRIPTION_0, null));
2263        createGroup(
2264            dbc,
2265            CmsUUID.getConstantUUID(usersGroup),
2266            usersGroup,
2267            groupDescription,
2268            I_CmsPrincipal.FLAG_ENABLED | CmsRole.ELEMENT_AUTHOR.getVirtualGroupFlags(),
2269            null);
2270
2271        if (parentOu != null) {
2272            // default users/groups(except the users group) are only for the root ou
2273            return;
2274        }
2275
2276        CmsGroup guests = createGroup(
2277            dbc,
2278            CmsUUID.getConstantUUID(guestGroup),
2279            guestGroup,
2280            CmsMacroResolver.localizedKeyMacro(Messages.GUI_DEFAULTGROUP_ROOT_GUESTS_DESCRIPTION_0, null),
2281            I_CmsPrincipal.FLAG_ENABLED,
2282            null);
2283
2284        int flags = CmsRole.ROOT_ADMIN.getVirtualGroupFlags();
2285        createGroup(
2286            dbc,
2287            CmsUUID.getConstantUUID(administratorsGroup),
2288            administratorsGroup,
2289            CmsMacroResolver.localizedKeyMacro(Messages.GUI_DEFAULTGROUP_ROOT_ADMINS_DESCRIPTION_0, null),
2290            I_CmsPrincipal.FLAG_ENABLED | flags,
2291            null);
2292
2293        CmsUser guest = createUser(
2294            dbc,
2295            CmsUUID.getConstantUUID(guestUser),
2296            guestUser,
2297            OpenCms.getPasswordHandler().digest((new CmsUUID()).toString()),
2298            " ",
2299            " ",
2300            " ",
2301            0,
2302            I_CmsPrincipal.FLAG_ENABLED,
2303            0,
2304            Collections.singletonMap(
2305                CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION,
2306                (Object)CmsMacroResolver.localizedKeyMacro(Messages.GUI_DEFAULTUSER_ROOT_GUEST_DESCRIPTION_0, null)));
2307        createUserInGroup(dbc, guest.getId(), guests.getId());
2308
2309        CmsUser admin = createUser(
2310            dbc,
2311            CmsUUID.getConstantUUID(adminUser),
2312            adminUser,
2313            OpenCms.getPasswordHandler().digest("admin"),
2314            " ",
2315            " ",
2316            " ",
2317            0,
2318            I_CmsPrincipal.FLAG_ENABLED,
2319            0,
2320            Collections.singletonMap(
2321                CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION,
2322                (Object)CmsMacroResolver.localizedKeyMacro(Messages.GUI_DEFAULTUSER_ROOT_ADMIN_DESCRIPTION_0, null)));
2323        createUserInGroup(dbc, admin.getId(), CmsUUID.getConstantUUID(CmsRole.ROOT_ADMIN.getGroupName()));
2324        createUserInGroup(dbc, admin.getId(), CmsUUID.getConstantUUID(administratorsGroup));
2325
2326        if (!OpenCms.getDefaultUsers().getUserExport().equals(OpenCms.getDefaultUsers().getUserAdmin())
2327            && !OpenCms.getDefaultUsers().getUserExport().equals(OpenCms.getDefaultUsers().getUserGuest())) {
2328
2329            CmsUser export = createUser(
2330                dbc,
2331                CmsUUID.getConstantUUID(exportUser),
2332                exportUser,
2333                OpenCms.getPasswordHandler().digest((new CmsUUID()).toString()),
2334                " ",
2335                " ",
2336                " ",
2337                0,
2338                I_CmsPrincipal.FLAG_ENABLED,
2339                0,
2340                Collections.singletonMap(
2341                    CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION,
2342                    (Object)CmsMacroResolver.localizedKeyMacro(
2343                        Messages.GUI_DEFAULTUSER_ROOT_EXPORT_DESCRIPTION_0,
2344                        null)));
2345            createUserInGroup(dbc, export.getId(), guests.getId());
2346        }
2347
2348        if (!OpenCms.getDefaultUsers().getUserDeletedResource().equals(OpenCms.getDefaultUsers().getUserAdmin())
2349            && !OpenCms.getDefaultUsers().getUserDeletedResource().equals(OpenCms.getDefaultUsers().getUserGuest())
2350            && !OpenCms.getDefaultUsers().getUserDeletedResource().equals(OpenCms.getDefaultUsers().getUserExport())) {
2351
2352            createUser(
2353                dbc,
2354                CmsUUID.getConstantUUID(deleteUser),
2355                deleteUser,
2356                OpenCms.getPasswordHandler().digest((new CmsUUID()).toString()),
2357                " ",
2358                " ",
2359                " ",
2360                0,
2361                I_CmsPrincipal.FLAG_ENABLED,
2362                0,
2363                Collections.singletonMap(
2364                    CmsUserSettings.ADDITIONAL_INFO_DESCRIPTION,
2365                    (Object)CmsMacroResolver.localizedKeyMacro(
2366                        Messages.GUI_DEFAULTUSER_ROOT_DELETED_DESCRIPTION_0,
2367                        null)));
2368        }
2369
2370        if (CmsLog.INIT.isInfoEnabled()) {
2371            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_DEFAULT_USERS_CREATED_0));
2372        }
2373    }
2374
2375    /**
2376     * Semi-constructor to create a {@link CmsGroup} instance from a JDBC result set.
2377     *
2378     * @param res the JDBC ResultSet
2379     * @return CmsGroup the new CmsGroup object
2380     *
2381     * @throws SQLException in case the result set does not include a requested table attribute
2382     */
2383    protected CmsGroup internalCreateGroup(ResultSet res) throws SQLException {
2384
2385        String ou = CmsOrganizationalUnit.removeLeadingSeparator(
2386            res.getString(m_sqlManager.readQuery("C_GROUPS_GROUP_OU_0")));
2387        String description = res.getString(m_sqlManager.readQuery("C_GROUPS_GROUP_DESCRIPTION_0"));
2388        return new CmsGroup(
2389            new CmsUUID(res.getString(m_sqlManager.readQuery("C_GROUPS_GROUP_ID_0"))),
2390            new CmsUUID(res.getString(m_sqlManager.readQuery("C_GROUPS_PARENT_GROUP_ID_0"))),
2391            ou + res.getString(m_sqlManager.readQuery("C_GROUPS_GROUP_NAME_0")),
2392            description,
2393            res.getInt(m_sqlManager.readQuery("C_GROUPS_GROUP_FLAGS_0")));
2394    }
2395
2396    /**
2397     * Returns the organizational unit represented by the given resource.<p>
2398     *
2399     * @param dbc the current db context
2400     * @param resource the resource that represents an organizational unit
2401     *
2402     * @return the organizational unit represented by the given resource
2403     *
2404     * @throws CmsException if something goes wrong
2405     */
2406    protected CmsOrganizationalUnit internalCreateOrgUnitFromResource(CmsDbContext dbc, CmsResource resource)
2407    throws CmsException {
2408
2409        if (!resource.getRootPath().startsWith(ORGUNIT_BASE_FOLDER)) {
2410            throw new CmsDataAccessException(
2411                Messages.get().container(Messages.ERR_READ_ORGUNIT_1, resource.getRootPath()));
2412        }
2413        // get the data
2414        String name = resource.getRootPath().substring(ORGUNIT_BASE_FOLDER.length());
2415        if ((name.length() > 0) && !name.endsWith(CmsOrganizationalUnit.SEPARATOR)) {
2416            name += CmsOrganizationalUnit.SEPARATOR;
2417        }
2418        String description = m_driverManager.readPropertyObject(
2419            dbc,
2420            resource,
2421            ORGUNIT_PROPERTY_DESCRIPTION,
2422            false).getStructureValue();
2423        int flags = (resource.getFlags() & ~CmsResource.FLAG_INTERNAL); // remove the internal flag
2424        String projectId = m_driverManager.readPropertyObject(
2425            dbc,
2426            resource,
2427            ORGUNIT_PROPERTY_PROJECTID,
2428            false).getStructureValue();
2429        // create the object
2430        return new CmsOrganizationalUnit(
2431            resource.getStructureId(),
2432            name,
2433            description,
2434            flags,
2435            (projectId == null ? null : new CmsUUID(projectId)));
2436    }
2437
2438    /**
2439     * Creates a folder with the given path an properties, offline AND online.<p>
2440     *
2441     * @param dbc the current database context
2442     * @param path the path to create the folder
2443     * @param flags the resource flags
2444     *
2445     * @return the new created offline folder
2446     *
2447     * @throws CmsException if something goes wrong
2448     */
2449    protected CmsResource internalCreateResourceForOrgUnit(CmsDbContext dbc, String path, int flags)
2450    throws CmsException {
2451
2452        // create the offline folder
2453        CmsResource resource = new CmsFolder(
2454            new CmsUUID(),
2455            new CmsUUID(),
2456            path,
2457            CmsResourceTypeFolder.RESOURCE_TYPE_ID,
2458            (CmsResource.FLAG_INTERNAL | flags),
2459            dbc.currentProject().getUuid(),
2460            CmsResource.STATE_NEW,
2461            0,
2462            dbc.currentUser().getId(),
2463            0,
2464            dbc.currentUser().getId(),
2465            CmsResource.DATE_RELEASED_DEFAULT,
2466            CmsResource.DATE_EXPIRED_DEFAULT,
2467            0);
2468
2469        CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID())
2470        ? dbc.currentProject().getUuid()
2471        : dbc.getProjectId();
2472
2473        m_driverManager.getVfsDriver(dbc).createResource(dbc, projectId, resource, null);
2474        resource.setState(CmsResource.STATE_UNCHANGED);
2475        m_driverManager.getVfsDriver(dbc).writeResource(dbc, projectId, resource, CmsDriverManager.NOTHING_CHANGED);
2476
2477        if (!dbc.currentProject().isOnlineProject() && dbc.getProjectId().isNullUUID()) {
2478            // online persistence
2479            CmsProject onlineProject = m_driverManager.readProject(dbc, CmsProject.ONLINE_PROJECT_ID);
2480            m_driverManager.getVfsDriver(dbc).createResource(dbc, onlineProject.getUuid(), resource, null);
2481        }
2482
2483        // clear the internal caches
2484        OpenCms.getMemoryMonitor().clearAccessControlListCache();
2485        OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PROPERTY);
2486        OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PROPERTY_LIST);
2487
2488        // fire an event that a new resource has been created
2489        OpenCms.fireCmsEvent(
2490            new CmsEvent(
2491                I_CmsEventListener.EVENT_RESOURCE_CREATED,
2492                Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, resource)));
2493
2494        return resource;
2495    }
2496
2497    /**
2498     * Semi-constructor to create a {@link CmsUser} instance from a JDBC result set.<p>
2499     *
2500     * @param dbc the current database context
2501     * @param res the JDBC ResultSet
2502     *
2503     * @return the new CmsUser object
2504     *
2505     * @throws SQLException in case the result set does not include a requested table attribute
2506     */
2507    protected CmsUser internalCreateUser(CmsDbContext dbc, ResultSet res) throws SQLException {
2508
2509        String userName = res.getString(m_sqlManager.readQuery("C_USERS_USER_NAME_0"));
2510        String ou = CmsOrganizationalUnit.removeLeadingSeparator(
2511            res.getString(m_sqlManager.readQuery("C_USERS_USER_OU_0")));
2512        CmsUUID userId = new CmsUUID(res.getString(m_sqlManager.readQuery("C_USERS_USER_ID_0")));
2513
2514        if (LOG.isDebugEnabled()) {
2515            LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_CREATE_USER_1, userName));
2516        }
2517
2518        return new CmsUser(
2519            userId,
2520            ou + userName,
2521            res.getString(m_sqlManager.readQuery("C_USERS_USER_PASSWORD_0")),
2522            res.getString(m_sqlManager.readQuery("C_USERS_USER_FIRSTNAME_0")),
2523            res.getString(m_sqlManager.readQuery("C_USERS_USER_LASTNAME_0")),
2524            res.getString(m_sqlManager.readQuery("C_USERS_USER_EMAIL_0")),
2525            res.getLong(m_sqlManager.readQuery("C_USERS_USER_LASTLOGIN_0")),
2526            res.getInt(m_sqlManager.readQuery("C_USERS_USER_FLAGS_0")),
2527            res.getLong(m_sqlManager.readQuery("C_USERS_USER_DATECREATED_0")),
2528            null);
2529    }
2530
2531    /**
2532     * Deletes a resource representing a organizational unit, offline AND online.<p>
2533     *
2534     * @param dbc the current database context
2535     * @param resource the resource to delete
2536     *
2537     * @throws CmsException if something goes wrong
2538     */
2539    protected void internalDeleteOrgUnitResource(CmsDbContext dbc, CmsResource resource) throws CmsException {
2540
2541        CmsRelationFilter filter = CmsRelationFilter.TARGETS;
2542
2543        // first the online version
2544        if (!dbc.currentProject().isOnlineProject()) {
2545            // online persistence
2546            CmsProject project = dbc.currentProject();
2547            dbc.getRequestContext().setCurrentProject(m_driverManager.readProject(dbc, CmsProject.ONLINE_PROJECT_ID));
2548
2549            try {
2550                // delete properties
2551                m_driverManager.getVfsDriver(dbc).deletePropertyObjects(
2552                    dbc,
2553                    CmsProject.ONLINE_PROJECT_ID,
2554                    resource,
2555                    CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
2556
2557                // remove the online folder only if it is really deleted offline
2558                m_driverManager.getVfsDriver(dbc).removeFolder(dbc, dbc.currentProject(), resource);
2559
2560                // remove ACL
2561                m_driverManager.getUserDriver(dbc).removeAccessControlEntries(
2562                    dbc,
2563                    dbc.currentProject(),
2564                    resource.getResourceId());
2565
2566                // delete relations
2567                m_driverManager.getVfsDriver(
2568                    dbc).deleteRelations(dbc, dbc.getRequestContext().getCurrentProject().getUuid(), resource, filter);
2569            } finally {
2570                dbc.getRequestContext().setCurrentProject(project);
2571            }
2572        }
2573        // delete properties
2574        m_driverManager.getVfsDriver(dbc).deletePropertyObjects(
2575            dbc,
2576            CmsProject.ONLINE_PROJECT_ID,
2577            resource,
2578            CmsProperty.DELETE_OPTION_DELETE_STRUCTURE_AND_RESOURCE_VALUES);
2579
2580        // remove the online folder only if it is really deleted offline
2581        m_driverManager.getVfsDriver(dbc).removeFolder(dbc, dbc.currentProject(), resource);
2582
2583        // remove ACL
2584        m_driverManager.getUserDriver(dbc).removeAccessControlEntries(
2585            dbc,
2586            dbc.currentProject(),
2587            resource.getResourceId());
2588
2589        // delete relations
2590        m_driverManager.getVfsDriver(
2591            dbc).deleteRelations(dbc, dbc.getRequestContext().getCurrentProject().getUuid(), resource, filter);
2592
2593        // flush all relevant caches
2594        OpenCms.getMemoryMonitor().clearAccessControlListCache();
2595        OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PROPERTY);
2596        OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PROPERTY_LIST);
2597        OpenCms.getMemoryMonitor().flushCache(CmsMemoryMonitor.CacheType.PROJECT_RESOURCES);
2598
2599        // fire events
2600        OpenCms.fireCmsEvent(
2601            new CmsEvent(
2602                I_CmsEventListener.EVENT_RESOURCE_DELETED,
2603                Collections.<String, Object> singletonMap(
2604                    I_CmsEventListener.KEY_RESOURCES,
2605                    Collections.singletonList(resource))));
2606        OpenCms.fireCmsEvent(
2607            new CmsEvent(
2608                I_CmsEventListener.EVENT_RESOURCE_AND_PROPERTIES_MODIFIED,
2609                Collections.<String, Object> singletonMap(I_CmsEventListener.KEY_RESOURCE, resource)));
2610    }
2611
2612    /**
2613     * Deletes an additional user info.<p>
2614     * @param dbc the current dbc
2615     * @param userId the user to delete additional info from
2616     * @param key the additional info to delete
2617     * @throws CmsDataAccessException if something goes wrong
2618     */
2619    protected void internalDeleteUserInfo(CmsDbContext dbc, CmsUUID userId, String key) throws CmsDataAccessException {
2620
2621        PreparedStatement stmt = null;
2622        Connection conn = null;
2623
2624        try {
2625            conn = getSqlManager().getConnection(dbc);
2626            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERDATA_DELETE_2");
2627            // write data to database
2628            stmt.setString(1, userId.toString());
2629            stmt.setString(2, key);
2630            stmt.executeUpdate();
2631        } catch (SQLException e) {
2632            throw new CmsDbSqlException(
2633                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2634                e);
2635        } finally {
2636            m_sqlManager.closeAll(dbc, conn, stmt, null);
2637        }
2638    }
2639
2640    /**
2641     * Internal implementation for reading users of an OU, with or without additional infos.<p>
2642     *
2643     * @param dbc the database context
2644     * @param orgUnit the OU
2645     * @param recursive if true, sub-OUs should be searched
2646     * @param readAdditionalInfos if true, additional infos should be read
2647     * @return the users which have been read
2648     * @throws CmsDataAccessException if something goes wrong
2649     */
2650    protected List<CmsUser> internalGetUsers(
2651        CmsDbContext dbc,
2652        CmsOrganizationalUnit orgUnit,
2653        boolean recursive,
2654        boolean readAdditionalInfos)
2655    throws CmsDataAccessException {
2656
2657        List<CmsUser> users = new ArrayList<CmsUser>();
2658        ResultSet res = null;
2659        PreparedStatement stmt = null;
2660        Connection conn = null;
2661        try {
2662            // create statement
2663            conn = m_sqlManager.getConnection(dbc);
2664            if (orgUnit.hasFlagWebuser()) {
2665                stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_GET_WEBUSERS_FOR_ORGUNIT_1");
2666            } else {
2667                stmt = m_sqlManager.getPreparedStatement(conn, "C_USERS_GET_USERS_FOR_ORGUNIT_1");
2668            }
2669
2670            String param = CmsOrganizationalUnit.SEPARATOR + orgUnit.getName();
2671            if (recursive) {
2672                param += "%";
2673            }
2674            stmt.setString(1, param);
2675            res = stmt.executeQuery();
2676            // create new Cms group objects
2677            while (res.next()) {
2678                users.add(internalCreateUser(dbc, res));
2679            }
2680        } catch (SQLException e) {
2681            throw new CmsDbSqlException(
2682                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2683                e);
2684        } finally {
2685            m_sqlManager.closeAll(dbc, conn, stmt, res);
2686        }
2687        if (readAdditionalInfos) {
2688            for (CmsUser user : users) {
2689                Map<String, Object> info = readUserInfos(dbc, user.getId());
2690                user.setAdditionalInfo(info);
2691            }
2692        }
2693        return users;
2694
2695    }
2696
2697    /**
2698     * Returns the folder for the given organizational units, or the base folder if <code>null</code>.<p>
2699     *
2700     * The base folder will be created if it does not exist.<p>
2701     *
2702     * @param dbc the current db context
2703     * @param orgUnit the organizational unit to get the folder for
2704     *
2705     * @return the base folder for organizational units
2706     *
2707     * @throws CmsException if something goes wrong
2708     */
2709    protected CmsResource internalOrgUnitFolder(CmsDbContext dbc, CmsOrganizationalUnit orgUnit) throws CmsException {
2710
2711        if (orgUnit != null) {
2712            return m_driverManager.readResource(
2713                dbc,
2714                ORGUNIT_BASE_FOLDER + orgUnit.getName(),
2715                CmsResourceFilter.DEFAULT);
2716        } else {
2717            return null;
2718        }
2719    }
2720
2721    /**
2722     * Returns the list of root paths associated to the organizational unit represented by the given resource.<p>
2723     *
2724     * @param dbc the current db context
2725     * @param ouResource the resource that represents the organizational unit to get the resources for
2726     *
2727     * @return the list of associated resource names
2728     *
2729     * @throws CmsException if something goes wrong
2730     */
2731    protected List<String> internalResourcesForOrgUnit(CmsDbContext dbc, CmsResource ouResource) throws CmsException {
2732
2733        List<CmsRelation> relations = m_driverManager.getRelationsForResource(
2734            dbc,
2735            ouResource,
2736            CmsRelationFilter.TARGETS);
2737        List<String> paths = new ArrayList<String>();
2738        Iterator<CmsRelation> it = relations.iterator();
2739        while (it.hasNext()) {
2740            CmsRelation relation = it.next();
2741            paths.add(relation.getTargetPath());
2742        }
2743        return paths;
2744    }
2745
2746    /**
2747     * Updates a group to a virtual group.<p>
2748     *
2749     * @param dbc the database context
2750     * @param groupName the name of the group to update
2751     * @param role the role for this group
2752     *
2753     * @throws CmsDataAccessException if something goes wrong
2754     */
2755    protected void internalUpdateRoleGroup(CmsDbContext dbc, String groupName, CmsRole role)
2756    throws CmsDataAccessException {
2757
2758        if (LOG.isDebugEnabled()) {
2759            LOG.debug(
2760                Messages.get().getBundle().key(Messages.LOG_DBG_UPDATE_ROLEGROUP_2, role.getRoleName(), groupName));
2761        }
2762
2763        CmsGroup group = readGroup(dbc, groupName);
2764        if ((CmsRole.valueOf(group) == null) || !CmsRole.valueOf(group).equals(role)) {
2765            CmsGroup roleGroup = readGroup(dbc, role.getGroupName());
2766
2767            if (LOG.isDebugEnabled()) {
2768                LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_UPDATE_ROLEGROUP_1, roleGroup));
2769            }
2770
2771            // copy all users from the group to the role
2772            Iterator<CmsUser> it;
2773            try {
2774                // read all users, also indirect assigned
2775                it = m_driverManager.getUsersOfGroup(dbc, groupName, false, false, false).iterator();
2776            } catch (CmsException e) {
2777                // should never happen
2778                LOG.error(e.getLocalizedMessage(), e);
2779                // read only direct assigned users
2780                it = readUsersOfGroup(dbc, groupName, false).iterator();
2781            }
2782            while (it.hasNext()) {
2783                CmsUser user = it.next();
2784
2785                if (LOG.isDebugEnabled()) {
2786                    LOG.debug(Messages.get().getBundle().key(Messages.LOG_DBG_UPDATE_ROLEGROUP_USER_1, user));
2787                }
2788                createUserInGroup(dbc, user.getId(), roleGroup.getId());
2789            }
2790            // set the right flags
2791            group.setFlags(role.getVirtualGroupFlags());
2792            try {
2793                writeGroup(dbc, group);
2794            } catch (Exception e) {
2795                LOG.error("Could not write group flags in internalUpdateRoleGroup: " + e.getLocalizedMessage(), e);
2796            }
2797        }
2798    }
2799
2800    /**
2801     * Updates additional user info.<p>
2802     * @param dbc the current dbc
2803     * @param userId the user id to add the user info for
2804     * @param key the name of the additional user info
2805     * @param value the value of the additional user info
2806     * @throws CmsDataAccessException if something goes wrong
2807     */
2808    protected void internalUpdateUserInfo(CmsDbContext dbc, CmsUUID userId, String key, Object value)
2809    throws CmsDataAccessException {
2810
2811        PreparedStatement stmt = null;
2812        Connection conn = null;
2813
2814        try {
2815            conn = getSqlManager().getConnection(dbc);
2816            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERDATA_UPDATE_4");
2817            // write data to database
2818            m_sqlManager.setBytes(stmt, 1, CmsDataTypeUtil.dataSerialize(value));
2819            stmt.setString(2, value.getClass().getName());
2820            stmt.setString(3, userId.toString());
2821            stmt.setString(4, key);
2822            stmt.executeUpdate();
2823        } catch (SQLException e) {
2824            throw new CmsDbSqlException(
2825                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2826                e);
2827        } catch (IOException e) {
2828            throw new CmsDbIoException(Messages.get().container(Messages.ERR_SERIALIZING_USER_DATA_1, userId), e);
2829        } finally {
2830            m_sqlManager.closeAll(dbc, conn, stmt, null);
2831        }
2832    }
2833
2834    /**
2835     * Validates the given root path to be in the scope of the resources of the given organizational unit.<p>
2836     *
2837     * @param dbc the current db context
2838     * @param orgUnit the organizational unit
2839     * @param rootPath the root path to check
2840     *
2841     * @throws CmsException if something goes wrong
2842     */
2843    protected void internalValidateResourceForOrgUnit(CmsDbContext dbc, CmsOrganizationalUnit orgUnit, String rootPath)
2844    throws CmsException {
2845
2846        CmsResource parentResource = m_driverManager.readResource(
2847            dbc,
2848            ORGUNIT_BASE_FOLDER + orgUnit.getName(),
2849            CmsResourceFilter.ALL);
2850        // assume not in scope
2851        boolean found = false;
2852        // iterate parent paths
2853        Iterator<String> itParentPaths = internalResourcesForOrgUnit(dbc, parentResource).iterator();
2854        // until the given resource is found in scope
2855        while (!found && itParentPaths.hasNext()) {
2856            String parentPath = itParentPaths.next();
2857            // check the scope
2858            if (rootPath.startsWith(parentPath)) {
2859                found = true;
2860            }
2861        }
2862        // if not in scope throw exception
2863        if (!found) {
2864            throw new CmsException(
2865                Messages.get().container(
2866                    Messages.ERR_PATH_NOT_IN_PARENT_ORGUNIT_SCOPE_2,
2867                    orgUnit.getName(),
2868                    dbc.removeSiteRoot(rootPath)));
2869        }
2870    }
2871
2872    /**
2873     * Checks if a user is member of a group.<p>
2874     *
2875     * @param dbc the database context
2876     * @param userId the id of the user to check
2877     * @param groupId the id of the group to check
2878     *
2879     * @return true if user is member of group
2880     *
2881     * @throws CmsDataAccessException if operation was not succesful
2882     */
2883    protected boolean internalValidateUserInGroup(CmsDbContext dbc, CmsUUID userId, CmsUUID groupId)
2884    throws CmsDataAccessException {
2885
2886        boolean userInGroup = false;
2887        PreparedStatement stmt = null;
2888        ResultSet res = null;
2889        Connection conn = null;
2890
2891        try {
2892            conn = getSqlManager().getConnection(dbc);
2893            stmt = m_sqlManager.getPreparedStatement(conn, "C_GROUPS_USER_IN_GROUP_2");
2894
2895            stmt.setString(1, groupId.toString());
2896            stmt.setString(2, userId.toString());
2897            res = stmt.executeQuery();
2898            if (res.next()) {
2899                userInGroup = true;
2900                while (res.next()) {
2901                    // do nothing only move through all rows because of mssql odbc driver
2902                }
2903            }
2904        } catch (SQLException e) {
2905            throw new CmsDbSqlException(
2906                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2907                e);
2908        } finally {
2909            m_sqlManager.closeAll(dbc, conn, stmt, res);
2910        }
2911
2912        return userInGroup;
2913    }
2914
2915    /**
2916     * Writes a property for an organizational unit resource, online AND offline.<p>
2917     *
2918     * @param dbc the current database context
2919     * @param resource the resource representing the organizational unit
2920     * @param property the property to write
2921     *
2922     * @throws CmsException if something goes wrong
2923     */
2924    protected void internalWriteOrgUnitProperty(CmsDbContext dbc, CmsResource resource, CmsProperty property)
2925    throws CmsException {
2926
2927        CmsUUID projectId = ((dbc.getProjectId() == null) || dbc.getProjectId().isNullUUID())
2928        ? dbc.currentProject().getUuid()
2929        : dbc.getProjectId();
2930        // write the property
2931        m_driverManager.writePropertyObject(dbc, resource, property);
2932        resource.setState(CmsResource.STATE_UNCHANGED);
2933        m_driverManager.getVfsDriver(dbc).writeResource(dbc, projectId, resource, CmsDriverManager.NOTHING_CHANGED);
2934
2935        // online persistence
2936        CmsProject project = dbc.currentProject();
2937        dbc.getRequestContext().setCurrentProject(m_driverManager.readProject(dbc, CmsProject.ONLINE_PROJECT_ID));
2938        try {
2939            m_driverManager.writePropertyObject(dbc, resource, property); // assume the resource is identical in both projects
2940            resource.setState(CmsResource.STATE_UNCHANGED);
2941            m_driverManager.getVfsDriver(
2942                dbc).writeResource(dbc, dbc.currentProject().getUuid(), resource, CmsDriverManager.NOTHING_CHANGED);
2943        } finally {
2944            dbc.getRequestContext().setCurrentProject(project);
2945        }
2946    }
2947
2948    /**
2949     * Writes a new additional user info.<p>
2950     * @param dbc the current dbc
2951     * @param userId the user id to add the user info for
2952     * @param key the name of the additional user info
2953     * @param value the value of the additional user info
2954     * @throws CmsDataAccessException if something goes wrong
2955     */
2956    protected void internalWriteUserInfo(CmsDbContext dbc, CmsUUID userId, String key, Object value)
2957    throws CmsDataAccessException {
2958
2959        PreparedStatement stmt = null;
2960        Connection conn = null;
2961
2962        try {
2963            conn = getSqlManager().getConnection(dbc);
2964            stmt = m_sqlManager.getPreparedStatement(conn, "C_USERDATA_WRITE_4");
2965            // write data to database
2966            stmt.setString(1, userId.toString());
2967            stmt.setString(2, key);
2968            m_sqlManager.setBytes(stmt, 3, CmsDataTypeUtil.dataSerialize(value));
2969            stmt.setString(4, value.getClass().getName());
2970            stmt.executeUpdate();
2971        } catch (SQLException e) {
2972            throw new CmsDbSqlException(
2973                Messages.get().container(Messages.ERR_GENERIC_SQL_1, CmsDbSqlException.getErrorQuery(stmt)),
2974                e);
2975        } catch (IOException e) {
2976            throw new CmsDbIoException(Messages.get().container(Messages.ERR_SERIALIZING_USER_DATA_1, userId), e);
2977        } finally {
2978            m_sqlManager.closeAll(dbc, conn, stmt, null);
2979        }
2980    }
2981
2982    /**
2983     * Updates the user additional information map.<p>
2984     *
2985     * @param dbc the current database context
2986     * @param userId the id of the user to update
2987     * @param additionalInfo the info to write
2988     *
2989     * @throws CmsDataAccessException if user data could not be written
2990     */
2991    protected void internalWriteUserInfos(CmsDbContext dbc, CmsUUID userId, Map<String, Object> additionalInfo)
2992    throws CmsDataAccessException {
2993
2994        Lock lock = USER_INFO_LOCKS.get(userId);
2995        try {
2996            lock.lock();
2997
2998            // get the map of existing additional infos to compare it new additional infos
2999            Map<String, Object> existingInfos = readUserInfos(dbc, userId);
3000
3001            // loop over all entries of the existing additional infos
3002            Iterator<Entry<String, Object>> itEntries = existingInfos.entrySet().iterator();
3003            while (itEntries.hasNext()) {
3004                Entry<String, Object> entry = itEntries.next();
3005                if ((entry.getKey() != null) && (entry.getValue() != null)) {
3006                    // entry does not exist or is null in new additional infos -> delete it
3007                    if (null == additionalInfo.get(entry.getKey())) {
3008                        dbc.setAttribute(ATTRIBUTE_USERADDINFO, ATTRIBUTE_USERADDINFO_VALUE_DELETE);
3009                        writeUserInfo(dbc, userId, entry.getKey(), entry.getValue());
3010                    } else {
3011                        Object newValue = additionalInfo.get(entry.getKey());
3012                        // entry does exist but has different value -> update it
3013                        if ((newValue != null) && !newValue.equals(entry.getValue())) {
3014                            dbc.setAttribute(ATTRIBUTE_USERADDINFO, ATTRIBUTE_USERADDINFO_VALUE_UPDATE);
3015                            writeUserInfo(dbc, userId, entry.getKey(), newValue);
3016                        }
3017                    }
3018                }
3019            }
3020
3021            // loop over all entries of the new additional infos
3022            Iterator<Entry<String, Object>> itNewEntries = additionalInfo.entrySet().iterator();
3023            while (itNewEntries.hasNext()) {
3024                Entry<String, Object> entry = itNewEntries.next();
3025                if ((entry.getKey() != null) && (entry.getValue() != null)) {
3026                    // entry doews not exist in the existing additional infos -> create a new one
3027                    if (!existingInfos.containsKey(entry.getKey())) {
3028                        dbc.setAttribute(ATTRIBUTE_USERADDINFO, ATTRIBUTE_USERADDINFO_VALUE_INSERT);
3029                        writeUserInfo(dbc, userId, entry.getKey(), entry.getValue());
3030                    }
3031                }
3032            }
3033
3034        } finally {
3035            lock.unlock();
3036        }
3037
3038    }
3039
3040}