/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
// www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; version 3 of the License.
//
// This community edition is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, see http://www.gnu.org/licenses/.
//
/////////////////////////////////////////////////////////////////////////////
package org.projectforge.database;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;
import org.projectforge.access.AccessException;
import org.projectforge.continuousdb.Table;
import org.projectforge.core.ConfigurationDO;
import org.projectforge.core.ConfigurationDOXmlDumpHook;
import org.projectforge.core.ConfigurationDao;
import org.projectforge.core.ConfigurationParam;
import org.projectforge.core.HibernateSearchReindexer;
import org.projectforge.database.xstream.XStreamSavingConverter;
import org.projectforge.task.TaskDO;
import org.projectforge.task.TaskNode;
import org.projectforge.task.TaskStatus;
import org.projectforge.task.TaskTree;
import org.projectforge.user.GroupDO;
import org.projectforge.user.GroupDao;
import org.projectforge.user.PFUserContext;
import org.projectforge.user.PFUserDO;
import org.projectforge.user.ProjectForgeGroup;
import org.projectforge.user.UserDao;
import org.projectforge.user.UserGroupCache;
import org.projectforge.user.UserPrefDOXmlDumpHook;
import org.projectforge.user.UserRightDO;
import org.projectforge.user.UserRightId;
import org.projectforge.user.UserRightValue;
import org.projectforge.user.UserXmlPreferencesXmlDumpHook;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* For initialization of a new ProjectForge system.
* @author Kai Reinhard (k.reinhard@micromata.de)
*
*/
@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
public class InitDatabaseDao extends HibernateDaoSupport
{
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(InitDatabaseDao.class);
static final String TEST_DATA_BASE_DUMP_FILE = "/data/init-test-data.xml.gz";
public static final String DEFAULT_ADMIN_USER = "admin";
private ConfigurationDao configurationDao;
private MyDatabaseUpdater myDatabaseUpdater;
private HibernateSearchReindexer hibernateSearchReindexer;
private UserGroupCache userGroupCache;
private GroupDao groupDao;
private TaskTree taskTree;
private XmlDump xmlDump;
private UserDao userDao;
/**
* @param configurationDao the configurationDao to set
* @return this for chaining.
*/
public void setConfigurationDao(final ConfigurationDao configurationDao)
{
this.configurationDao = configurationDao;
}
public void setMyDatabaseUpdater(final MyDatabaseUpdater myDatabaseUpdater)
{
this.myDatabaseUpdater = myDatabaseUpdater;
}
/**
* @param hibernateSearchReindexer the hibernateSearchReindexer to set
* @return this for chaining.
*/
public void setHibernateSearchReindexer(final HibernateSearchReindexer hibernateSearchReindexer)
{
this.hibernateSearchReindexer = hibernateSearchReindexer;
}
public void setUserDao(final UserDao userDao)
{
this.userDao = userDao;
}
public void setUserGroupCache(final UserGroupCache userGroupCache)
{
this.userGroupCache = userGroupCache;
}
public void setGroupDao(final GroupDao groupDao)
{
this.groupDao = groupDao;
}
public void setTaskTree(final TaskTree taskTree)
{
this.taskTree = taskTree;
}
public void setXmlDump(final XmlDump xmlDump)
{
this.xmlDump = xmlDump;
xmlDump.registerHook(new UserXmlPreferencesXmlDumpHook());
xmlDump.registerHook(new UserPrefDOXmlDumpHook());
xmlDump.registerHook(new ConfigurationDOXmlDumpHook());
}
/**
* If the database is empty (user list is empty) then a admin user and ProjectForge root task will be created.
* @param adminUser The admin user with the desired username and the salted password (salt string included). All other attributes and
* groups of the user are set by this method.
*/
public PFUserDO initializeEmptyDatabase(final PFUserDO user, final TimeZone adminUserTimezone)
{
log.fatal("User wants to initialize database.");
if (isEmpty() == false) {
databaseNotEmpty();
}
final TaskDO task = new TaskDO();
task.setTitle("Root");
task.setStatus(TaskStatus.N);
task.setShortDescription("ProjectForge root task");
task.setCreated();
task.setLastUpdate();
final Serializable id = getHibernateTemplate().save(task);
log.info("New object added (" + id + "): " + task.toString());
// Use of taskDao does not work with maven test case: Could not synchronize database state with session?
// Create Admin user
final PFUserDO adminUser = new PFUserDO();
adminUser.setUsername(user.getUsername());
adminUser.setPassword(user.getPassword());
adminUser.setPasswordSalt(user.getPasswordSalt());
adminUser.setLocalUser(true);
adminUser.setLastname("Administrator");
adminUser.setDescription("ProjectForge administrator");
adminUser.setTimeZone(adminUserTimezone);
adminUser.addRight(new UserRightDO(UserRightId.FIBU_AUSGANGSRECHNUNGEN, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.FIBU_COST_UNIT, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.FIBU_EINGANGSRECHNUNGEN, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.FIBU_DATEV_IMPORT, UserRightValue.TRUE));
adminUser.addRight(new UserRightDO(UserRightId.FIBU_EMPLOYEE, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.FIBU_EMPLOYEE_SALARY, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.FIBU_ACCOUNTS, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.ORGA_CONTRACTS, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.ORGA_INCOMING_MAIL, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.ORGA_OUTGOING_MAIL, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.PM_PROJECT, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.PM_ORDER_BOOK, UserRightValue.READWRITE));
adminUser.addRight(new UserRightDO(UserRightId.PM_HR_PLANNING, UserRightValue.READWRITE));
userDao.internalSave(adminUser);
PFUserContext.setUser(adminUser); // Need to login the admin user for avoiding following access exceptions.
final Set<PFUserDO> adminUsers = new HashSet<PFUserDO>();
adminUsers.add(adminUser);
addGroup(ProjectForgeGroup.ADMIN_GROUP, "Administrators of ProjectForge", adminUsers);
addGroup(ProjectForgeGroup.CONTROLLING_GROUP, "Users for having read access to the company's finances.", adminUsers);
addGroup(ProjectForgeGroup.FINANCE_GROUP, "Finance and Accounting", adminUsers);
addGroup(ProjectForgeGroup.MARKETING_GROUP, "Marketing users can download all addresses in excel format.", null);
addGroup(ProjectForgeGroup.ORGA_TEAM, "The organization team has access to post in- and outbound, contracts etc..", adminUsers);
addGroup(ProjectForgeGroup.PROJECT_MANAGER, "Project managers have access to assigned orders and resource planning.", null);
addGroup(ProjectForgeGroup.PROJECT_ASSISTANT, "Project assistants have access to assigned orders.", null);
taskTree.setExpired();
userGroupCache.setExpired();
log.fatal("Empty database successfully initialized.");
return adminUser;
}
private void addGroup(final ProjectForgeGroup projectForgeGroup, final String description, final Set<PFUserDO> users)
{
final GroupDO group = new GroupDO();
group.setName(projectForgeGroup.toString());
group.setDescription(description);
group.setAssignedUsers(users);
// group.setNestedGroupsAllowed(false);
group.setLocalGroup(true); // Do not synchronize group with external user management system by default.
groupDao.internalSave(group);
}
/**
* @param adminUser The admin user with the desired username and the salted password (salt string included). All other attributes and
* groups of the user are set by this method.
* @param adminUserTimezone
* @return
*/
public PFUserDO initializeEmptyDatabaseWithTestData(final PFUserDO adminUser, final TimeZone adminUserTimezone)
{
log.fatal("User wants to initialize database with test data.");
if (isEmpty() == false) {
databaseNotEmpty();
}
final XStreamSavingConverter xstreamSavingConverter = xmlDump.restoreDatabaseFromClasspathResource(TEST_DATA_BASE_DUMP_FILE, "utf-8");
xmlDump.verifyDump(xstreamSavingConverter);
final PFUserDO user = userDao.getInternalByName(DEFAULT_ADMIN_USER);
if (user == null) {
log.error("Initialization of database failed. Perhaps caused by corrupted init-test-data.xml.gz.");
} else {
user.setUsername(adminUser.getUsername());
user.setPassword(adminUser.getPassword());
user.setPasswordSalt(adminUser.getPasswordSalt());
user.setLocalUser(true);
user.setTimeZone(adminUserTimezone);
userDao.internalUpdate(user);
Integer taskId = null;
for (final TaskNode node : taskTree.getRootTaskNode().getChilds()) {
if ("ACME".equals(node.getTask().getTitle()) == true) {
taskId = node.getId();
break;
}
}
if (taskId != null) {
ConfigurationDO configuration = configurationDao.getEntry(ConfigurationParam.DEFAULT_TASK_ID_4_ADDRESSES);
configuration.setTaskId(taskId);
configurationDao.internalUpdate(configuration);
configuration = configurationDao.getEntry(ConfigurationParam.DEFAULT_TASK_ID_4_BOOKS);
configuration.setTaskId(taskId);
configurationDao.internalUpdate(configuration);
}
log.fatal("Database successfully initialized with test data.");
}
new Thread() {
@Override
public void run()
{
hibernateSearchReindexer.rebuildDatabaseSearchIndices();
}
}.start();
taskTree.setExpired();
userGroupCache.setExpired();
return user;
}
public boolean isEmpty()
{
try {
if (userGroupCache.internalGetNumberOfUsers() == 0) {
final Table userTable = new Table(PFUserDO.class);
final MyDatabaseUpdateDao databaseUpdateDao = myDatabaseUpdater.getDatabaseUpdateDao();
return databaseUpdateDao.internalDoesTableExist(userTable.getName()) == false
|| databaseUpdateDao.internalIsTableEmpty(userTable.getName()) == true;
}
} catch (final Exception ex) {
// In the case, that user table is not readable.
final Table userTable = new Table(PFUserDO.class);
final MyDatabaseUpdateDao databaseUpdateDao = myDatabaseUpdater.getDatabaseUpdateDao();
return databaseUpdateDao.internalDoesTableExist(userTable.getName()) == false
|| databaseUpdateDao.internalIsTableEmpty(userTable.getName()) == true;
}
return false;
}
private void databaseNotEmpty()
{
final String msg = "Database seems to be not empty. Initialization of database aborted.";
log.error(msg);
throw new AccessException(msg);
}
}