Merge branch 'master' into mpxj-import
Conflicts: libreplan-business/src/main/java/org/libreplan/business/orders/entities/Order.java libreplan-webapp/pom.xml pom.xml
This commit is contained in:
commit
cc246eedfa
113 changed files with 8658 additions and 710 deletions
|
|
@ -28,7 +28,9 @@ import org.libreplan.business.calendars.daos.ICalendarDataDAO;
|
|||
import org.libreplan.business.calendars.daos.ICalendarExceptionDAO;
|
||||
import org.libreplan.business.calendars.daos.ICalendarExceptionTypeDAO;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.daos.IEntitySequenceDAO;
|
||||
import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO;
|
||||
import org.libreplan.business.costcategories.daos.ICostCategoryDAO;
|
||||
import org.libreplan.business.costcategories.daos.IHourCostDAO;
|
||||
import org.libreplan.business.costcategories.daos.IResourcesCostCategoryAssignmentDAO;
|
||||
|
|
@ -44,6 +46,7 @@ import org.libreplan.business.materials.daos.IUnitTypeDAO;
|
|||
import org.libreplan.business.orders.daos.IHoursGroupDAO;
|
||||
import org.libreplan.business.orders.daos.IOrderDAO;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
|
||||
import org.libreplan.business.planner.daos.ITaskElementDAO;
|
||||
import org.libreplan.business.qualityforms.daos.IQualityFormDAO;
|
||||
import org.libreplan.business.resources.daos.ICriterionDAO;
|
||||
|
|
@ -203,6 +206,15 @@ public class Registry {
|
|||
@Autowired
|
||||
private IOrderAuthorizationDAO orderAuthorizationDAO;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Autowired
|
||||
private IOrderSyncInfoDAO orderSyncInfoDAO;
|
||||
|
||||
@Autowired
|
||||
private IJobSchedulerConfigurationDAO jobSchedulerConfigurationDAO;
|
||||
|
||||
@Autowired
|
||||
private IAdHocTransactionService transactionServiceDAO;
|
||||
|
||||
|
|
@ -379,4 +391,15 @@ public class Registry {
|
|||
return getInstance().orderAuthorizationDAO;
|
||||
}
|
||||
|
||||
public static IConnectorDAO getConnectorDAO() {
|
||||
return getInstance().connectorDAO;
|
||||
}
|
||||
|
||||
public static IOrderSyncInfoDAO getOrderSyncInfoDAO() {
|
||||
return getInstance().orderSyncInfoDAO;
|
||||
}
|
||||
|
||||
public static IJobSchedulerConfigurationDAO getJobSchedulerConfigurationDAO() {
|
||||
return getInstance().jobSchedulerConfigurationDAO;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* DAO for {@link Connector} entity.
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
@Repository
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class ConnectorDAO extends GenericDAOHibernate<Connector, Long>
|
||||
implements IConnectorDAO {
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<Connector> getAll() {
|
||||
return list(Connector.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Connector findUniqueByName(String name) {
|
||||
Criteria c = getSession().createCriteria(Connector.class).add(
|
||||
Restrictions.eq("name", name));
|
||||
return (Connector) c.uniqueResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
|
||||
public boolean existsByNameAnotherTransaction(Connector connector) {
|
||||
return existsOtherConnectorByName(connector);
|
||||
}
|
||||
|
||||
private boolean existsOtherConnectorByName(Connector connector) {
|
||||
Connector found = findUniqueByName(connector.getName());
|
||||
return found != null && found != connector;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
|
||||
public Connector findUniqueByNameAnotherTransaction(String name) {
|
||||
return findUniqueByName(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
|
||||
/**
|
||||
* Contract for {@link Conn}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface IConnectorDAO extends IGenericDAO<Connector, Long> {
|
||||
|
||||
List<Connector> getAll();
|
||||
|
||||
Connector findUniqueByName(String name);
|
||||
|
||||
boolean existsByNameAnotherTransaction(Connector connector);
|
||||
|
||||
Connector findUniqueByNameAnotherTransaction(String name);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
|
||||
/**
|
||||
* Contract for {@link JobSchedulerConfigurationDAO}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface IJobSchedulerConfigurationDAO extends
|
||||
IGenericDAO<JobSchedulerConfiguration, Long> {
|
||||
|
||||
/**
|
||||
* Returns all {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
List<JobSchedulerConfiguration> getAll();
|
||||
|
||||
/**
|
||||
* Searches and returns {@link JobSchedulerConfiguration} for the given
|
||||
* <code>connectorName</code>
|
||||
*
|
||||
* @param connectorName
|
||||
* the name of the connector
|
||||
*/
|
||||
List<JobSchedulerConfiguration> findByConnectorName(String connectorName);
|
||||
|
||||
/**
|
||||
* Searches and returns {@link JobSchedulerConfiguration} for the given
|
||||
* <code>jobGroup</code> and <code>jobName</code>
|
||||
*
|
||||
* @param jobGroup
|
||||
* @param jobName
|
||||
*/
|
||||
JobSchedulerConfiguration findByJobGroupAndJobName(String jobGroup,
|
||||
String jobName);
|
||||
|
||||
/**
|
||||
* Returns true if there exists other @{link JobSchedulerConfiguration} with
|
||||
* the same <code>{@link JobSchedulerConfiguration#getJobGroup()}</code> and
|
||||
* <code>{@link JobSchedulerConfiguration#getJobName()</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the <code>{@link JobSchedulerConfiguration}</code>
|
||||
*/
|
||||
boolean existsByJobGroupAndJobNameAnotherTransaction(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
/**
|
||||
* Returns unique {@link JobSchedulerConfiguration} for the specified
|
||||
* <code>JobGroup</code> and <code>JobName</code>
|
||||
*
|
||||
* @param jobGroup
|
||||
* the jobGroup
|
||||
* @param jobName
|
||||
* the jobName
|
||||
*/
|
||||
JobSchedulerConfiguration findUniqueByJobGroupAndJobNameAnotherTransaction(
|
||||
String jobGroup, String jobName);
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* DAO for {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Repository
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class JobSchedulerConfigurationDAO extends
|
||||
GenericDAOHibernate<JobSchedulerConfiguration, Long> implements
|
||||
IJobSchedulerConfigurationDAO {
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<JobSchedulerConfiguration> getAll() {
|
||||
return list(JobSchedulerConfiguration.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public JobSchedulerConfiguration findByJobGroupAndJobName(String jobGroup,
|
||||
String jobName) {
|
||||
return (JobSchedulerConfiguration) getSession()
|
||||
.createCriteria(JobSchedulerConfiguration.class)
|
||||
.add(Restrictions.eq("jobGroup", jobGroup))
|
||||
.add(Restrictions.eq("jobName", jobName)).uniqueResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<JobSchedulerConfiguration> findByConnectorName(
|
||||
String connectorName) {
|
||||
Criteria c = getSession().createCriteria(
|
||||
JobSchedulerConfiguration.class).add(
|
||||
Restrictions.eq("connectorName", connectorName));
|
||||
return ((List<JobSchedulerConfiguration>) c.list());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
|
||||
public boolean existsByJobGroupAndJobNameAnotherTransaction(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
return existsOtherJobByGroupAndName(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if other {@link JobSchedulerConfiguration} which is the same
|
||||
* as the given <code>{@link OrderSyncInfo} already exists
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
private boolean existsOtherJobByGroupAndName(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
JobSchedulerConfiguration found = findByJobGroupAndJobName(
|
||||
jobSchedulerConfiguration.getJobGroup(),
|
||||
jobSchedulerConfiguration.getJobName());
|
||||
return found != null && found != jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
|
||||
public JobSchedulerConfiguration findUniqueByJobGroupAndJobNameAnotherTransaction(
|
||||
String jobGroup, String jobName) {
|
||||
return findByJobGroupAndJobName(jobGroup, jobName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -104,8 +104,6 @@ public class Configuration extends BaseEntity {
|
|||
|
||||
private Boolean generateCodeForExpenseSheets = true;
|
||||
|
||||
private JiraConfiguration jiraConfiguration;
|
||||
|
||||
/**
|
||||
* Currency code according to ISO-4217 (3 letters)
|
||||
*/
|
||||
|
|
@ -505,12 +503,4 @@ public class Configuration extends BaseEntity {
|
|||
this.secondsPlanningWarning = secondsPlanningWarning;
|
||||
}
|
||||
|
||||
public JiraConfiguration getJiraConfiguration() {
|
||||
return jiraConfiguration;
|
||||
}
|
||||
|
||||
public void setJiraConfiguration(JiraConfiguration jiraConfiguration) {
|
||||
this.jiraConfiguration = jiraConfiguration;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,13 +81,6 @@ public class ConfigurationBootstrap implements IConfigurationBootstrap {
|
|||
}
|
||||
configuration.setLdapConfiguration(ldapConfiguration);
|
||||
|
||||
JiraConfiguration jiraConfiguration = configuration
|
||||
.getJiraConfiguration();
|
||||
if (jiraConfiguration == null) {
|
||||
jiraConfiguration = JiraConfiguration.create();
|
||||
}
|
||||
configuration.setJiraConfiguration(jiraConfiguration);
|
||||
|
||||
configurationDAO.save(configuration);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,8 +75,6 @@ public class ConfigurationTypeOfWorkHoursBootstrap implements
|
|||
}
|
||||
|
||||
configuration.setPersonalTimesheetsTypeOfWorkHours(typeOfWorkHours);
|
||||
configuration.getJiraConfiguration().setJiraConnectorTypeOfWorkHours(
|
||||
typeOfWorkHours);
|
||||
configurationDAO.save(configuration);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.validator.AssertTrue;
|
||||
import org.hibernate.validator.NotEmpty;
|
||||
import org.hibernate.validator.Valid;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
|
||||
/**
|
||||
* Connector entity, represents a connector in order that LibrePlan interchange
|
||||
* some data with other application.
|
||||
*
|
||||
* A connector is identified by a <code>name</code> and it has a list of pairs
|
||||
* key-value in order to store the configuration parameters of the connector.
|
||||
*
|
||||
* This entity should be used to create new connectors in LibrePlan.
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class Connector extends BaseEntity {
|
||||
|
||||
public static Connector create(String name) {
|
||||
return create(new Connector(name));
|
||||
}
|
||||
|
||||
private String name;
|
||||
|
||||
private List<ConnectorProperty> properties = new ArrayList<ConnectorProperty>();
|
||||
|
||||
/**
|
||||
* Constructor for Hibernate. Do not use!
|
||||
*/
|
||||
protected Connector() {
|
||||
}
|
||||
|
||||
private Connector(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@NotEmpty(message = "name not specified")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Valid
|
||||
public List<ConnectorProperty> getProperties() {
|
||||
return Collections.unmodifiableList(properties);
|
||||
}
|
||||
|
||||
public void setProperties(List<ConnectorProperty> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public void addProperty(ConnectorProperty property) {
|
||||
properties.add(property);
|
||||
}
|
||||
|
||||
public Map<String, String> getPropertiesAsMap() {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
for (ConnectorProperty property : properties) {
|
||||
map.put(property.getKey(), property.getValue());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@AssertTrue(message = "connector name is already being used")
|
||||
public boolean checkConstraintUniqueConnectorName() {
|
||||
if (StringUtils.isBlank(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
IConnectorDAO connectorDAO = Registry.getConnectorDAO();
|
||||
if (isNewObject()) {
|
||||
return !connectorDAO.existsByNameAnotherTransaction(this);
|
||||
} else {
|
||||
Connector found = connectorDAO
|
||||
.findUniqueByNameAnotherTransaction(name);
|
||||
return found == null || found.getId().equals(getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isActivated() {
|
||||
return getPropertiesAsMap()
|
||||
.get(PredefinedConnectorProperties.ACTIVATED).equalsIgnoreCase(
|
||||
"Y");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if connector's connections values are valid
|
||||
*
|
||||
* @return true if connection values are valid
|
||||
*/
|
||||
public boolean areConnectionValuesValid() {
|
||||
String serverUrl = getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.SERVER_URL);
|
||||
try {
|
||||
new URL(serverUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.USERNAME))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.PASSWORD))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Creates the LibrePlan {@link Connector Connectors} with its configuration
|
||||
* properties and default values.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope("singleton")
|
||||
public class ConnectorBootstrap implements IConnectorBootstrap {
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void loadRequiredData() {
|
||||
for (PredefinedConnectors predefinedConnector : PredefinedConnectors
|
||||
.values()) {
|
||||
String name = predefinedConnector.getName();
|
||||
|
||||
Connector connector = connectorDAO.findUniqueByName(name);
|
||||
if (connector == null) {
|
||||
connector = Connector.create(name);
|
||||
connector.setProperties(predefinedConnector.getProperties());
|
||||
connectorDAO.save(connector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
/**
|
||||
* Exception to ecapsulate connector(values) exceptions
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class ConnectorException extends Exception {
|
||||
|
||||
public ConnectorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import org.hibernate.validator.NotEmpty;
|
||||
|
||||
/**
|
||||
* This class is intended to work as a Hibernate component. It's formed by two
|
||||
* attributes, the key and the value of the property. It represents the
|
||||
* different configuration parameters of a {@link Connector}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
public class ConnectorProperty {
|
||||
|
||||
public static ConnectorProperty create(String key, String value) {
|
||||
return new ConnectorProperty(key, value);
|
||||
}
|
||||
|
||||
private String key;
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Default constructor for Hibernate. Do not use!
|
||||
*/
|
||||
protected ConnectorProperty() {
|
||||
}
|
||||
|
||||
private ConnectorProperty(String key, String value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@NotEmpty(message = "property key not specified")
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import org.libreplan.business.IDataBootstrap;
|
||||
|
||||
/**
|
||||
* Contract for {@link ConnectorBootstrap}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface IConnectorBootstrap extends IDataBootstrap {
|
||||
|
||||
void loadRequiredData();
|
||||
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
|
||||
|
||||
/**
|
||||
* JiraConfiguration entity
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JiraConfiguration extends BaseEntity {
|
||||
|
||||
/**
|
||||
* Code prefix for different entities integrated with JIRA.
|
||||
*/
|
||||
public static final String CODE_PREFIX = "JIRA-";
|
||||
|
||||
public static JiraConfiguration create() {
|
||||
return create(new JiraConfiguration());
|
||||
}
|
||||
|
||||
private boolean jiraActivated;
|
||||
|
||||
private String jiraUrl;
|
||||
|
||||
/**
|
||||
* Stores one of the next 2 options:
|
||||
* <ul>
|
||||
* <li>A comma-separated list of labels</li>
|
||||
* <li>A URL that will return a comma-separated list of labels</li>
|
||||
* </ul>
|
||||
*/
|
||||
private String jiraLabels;
|
||||
|
||||
private String jiraUserId;
|
||||
|
||||
private String jiraPassword;
|
||||
|
||||
private TypeOfWorkHours jiraConnectorTypeOfWorkHours;
|
||||
|
||||
/**
|
||||
* Constructor for Hibernate. Do not use!
|
||||
*/
|
||||
protected JiraConfiguration() {
|
||||
}
|
||||
|
||||
public boolean isJiraActivated() {
|
||||
return jiraActivated;
|
||||
}
|
||||
|
||||
public void setJiraActivated(boolean jiraActivated) {
|
||||
this.jiraActivated = jiraActivated;
|
||||
}
|
||||
|
||||
public String getJiraUrl() {
|
||||
return jiraUrl;
|
||||
}
|
||||
|
||||
public void setJiraUrl(String jiraUrl) {
|
||||
this.jiraUrl = jiraUrl;
|
||||
}
|
||||
|
||||
public String getJiraLabels() {
|
||||
return jiraLabels;
|
||||
}
|
||||
|
||||
public void setJiraLabels(String jiraLabels) {
|
||||
this.jiraLabels = jiraLabels;
|
||||
}
|
||||
|
||||
public String getJiraUserId() {
|
||||
return jiraUserId;
|
||||
}
|
||||
|
||||
public void setJiraUserId(String jiraUserId) {
|
||||
this.jiraUserId = jiraUserId;
|
||||
}
|
||||
|
||||
public String getJiraPassword() {
|
||||
return jiraPassword;
|
||||
}
|
||||
|
||||
public void setJiraPassword(String jiraPassword) {
|
||||
this.jiraPassword = jiraPassword;
|
||||
}
|
||||
|
||||
public TypeOfWorkHours getJiraConnectorTypeOfWorkHours() {
|
||||
return jiraConnectorTypeOfWorkHours;
|
||||
}
|
||||
|
||||
public void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
|
||||
jiraConnectorTypeOfWorkHours = typeOfWorkHours;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
|
||||
/**
|
||||
* Defines the job class package and name to be used as data type in
|
||||
* {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public enum JobClassNameEnum {
|
||||
|
||||
IMPORT_ROSTER_FROM_TIM_JOB("org.libreplan.importers", "ImportRosterFromTimJob"),
|
||||
EXPORT_TIMESHEET_TO_TIM_JOB("org.libreplan.importers","ExportTimesheetToTimJob"),
|
||||
SYNC_ORDERELEMENTS_WITH_JIRA_ISSUES_JOB("org.libreplan.importers","JiraOrderElementSynchronizerJob");
|
||||
|
||||
private String packageName;
|
||||
private String name;
|
||||
|
||||
private JobClassNameEnum(String packageName, String name) {
|
||||
this.packageName = packageName;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.validator.AssertTrue;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.common.IHumanIdentifiable;
|
||||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO;
|
||||
|
||||
/**
|
||||
* JobSchedulerConfiguration entity, represents parameters for the jobs to be
|
||||
* scheduled. This entity is used by the <code>SchedulerManager</code> to
|
||||
* schedule jobs and in UI to show the scheduler status.
|
||||
*
|
||||
* The <code>jobGroup</code> and <code>jobName</code> together forms a job key
|
||||
* and non of the fields must be null. Moreover it should contain a valid
|
||||
* <code>cronExpression</code>
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JobSchedulerConfiguration extends BaseEntity implements
|
||||
IHumanIdentifiable {
|
||||
|
||||
public static JobSchedulerConfiguration create() {
|
||||
return create(new JobSchedulerConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Hibernate. Do not use!
|
||||
*/
|
||||
protected JobSchedulerConfiguration() {
|
||||
}
|
||||
|
||||
private String jobGroup;
|
||||
|
||||
private String jobName;
|
||||
|
||||
private String cronExpression;
|
||||
|
||||
private JobClassNameEnum jobClassName;
|
||||
|
||||
private boolean schedule;
|
||||
|
||||
private String connectorName;
|
||||
|
||||
@NotNull(message = "job group not specified")
|
||||
public String getJobGroup() {
|
||||
return jobGroup;
|
||||
}
|
||||
|
||||
public void setJobGroup(String jobGroup) {
|
||||
this.jobGroup = jobGroup;
|
||||
}
|
||||
|
||||
@NotNull(message = "job name not specified")
|
||||
public String getJobName() {
|
||||
return jobName;
|
||||
}
|
||||
|
||||
public void setJobName(String jobName) {
|
||||
this.jobName = jobName;
|
||||
}
|
||||
|
||||
@NotNull(message = "cron expression not specified")
|
||||
public String getCronExpression() {
|
||||
return cronExpression;
|
||||
}
|
||||
|
||||
public void setCronExpression(String cronExpression) {
|
||||
this.cronExpression = cronExpression;
|
||||
}
|
||||
|
||||
@NotNull(message = "job class name not specified")
|
||||
public JobClassNameEnum getJobClassName() {
|
||||
return jobClassName;
|
||||
}
|
||||
|
||||
public void setJobClassName(JobClassNameEnum jobClassName) {
|
||||
this.jobClassName = jobClassName;
|
||||
}
|
||||
|
||||
public boolean isSchedule() {
|
||||
return schedule;
|
||||
}
|
||||
|
||||
public void setSchedule(boolean schedule) {
|
||||
this.schedule = schedule;
|
||||
}
|
||||
|
||||
public String getConnectorName() {
|
||||
return connectorName;
|
||||
}
|
||||
|
||||
public void setConnectorName(String connectorName) {
|
||||
this.connectorName = connectorName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHumanId() {
|
||||
return jobGroup == null ? "" : jobGroup;
|
||||
}
|
||||
|
||||
@AssertTrue(message = "job group and name are already being used")
|
||||
public boolean checkConstraintUniqueJobGroupAndName() {
|
||||
if (StringUtils.isBlank(jobGroup) && StringUtils.isBlank(jobName)) {
|
||||
return true;
|
||||
}
|
||||
IJobSchedulerConfigurationDAO jobSchedulerConfigurationDAO = Registry
|
||||
.getJobSchedulerConfigurationDAO();
|
||||
if (isNewObject()) {
|
||||
return !jobSchedulerConfigurationDAO
|
||||
.existsByJobGroupAndJobNameAnotherTransaction(this);
|
||||
} else {
|
||||
JobSchedulerConfiguration found = jobSchedulerConfigurationDAO
|
||||
.findUniqueByJobGroupAndJobNameAnotherTransaction(jobGroup,
|
||||
jobName);
|
||||
return found == null || found.getId().equals(getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import static org.libreplan.business.i18n.I18nHelper._;
|
||||
|
||||
/**
|
||||
* Simply class to keep constants of {@link ConnectorProperty properties} for
|
||||
* LibrePlan {@link Connector connectors}.
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class PredefinedConnectorProperties {
|
||||
|
||||
// Generic
|
||||
public static String ACTIVATED = _("Activated");
|
||||
public static String SERVER_URL = _("Server URL");
|
||||
public static String USERNAME = _("Username");
|
||||
public static String PASSWORD = _("Password");
|
||||
|
||||
// Specific for Tim
|
||||
public static String TIM_NR_DAYS_TIMESHEET = _("Number of days timesheet to Tim");
|
||||
public static String TIM_NR_DAYS_ROSTER = _("Number of days roster from Tim");
|
||||
public static String TIM_PRODUCTIVITY_FACTOR = _("Productivity factor");
|
||||
public static String TIM_DEPARTAMENTS_IMPORT_ROSTER = _("Department IDs to import toster");
|
||||
|
||||
// Specific for JIRA
|
||||
public static String JIRA_LABELS = _("JIRA labels: comma-separated list of labels or URL");
|
||||
public static String JIRA_HOURS_TYPE = _("Hours type");
|
||||
|
||||
/**
|
||||
* Code prefix for different entities integrated with JIRA.
|
||||
*/
|
||||
public static final String JIRA_CODE_PREFIX = "JIRA-";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.common.entities;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Defines the LibrePlan {@link Connector Connectors} together with its
|
||||
* configuration properties.
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public enum PredefinedConnectors {
|
||||
|
||||
TIM("Tim",
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.ACTIVATED, "N"),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.SERVER_URL, ""),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.USERNAME, ""),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.PASSWORD, ""),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.TIM_NR_DAYS_TIMESHEET, "7"),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.TIM_NR_DAYS_ROSTER, "90"),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.TIM_PRODUCTIVITY_FACTOR, "100"),
|
||||
ConnectorProperty.create(
|
||||
PredefinedConnectorProperties.TIM_DEPARTAMENTS_IMPORT_ROSTER,
|
||||
"0")),
|
||||
JIRA("Jira",
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.ACTIVATED, "N"),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.SERVER_URL, ""),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.USERNAME, ""),
|
||||
ConnectorProperty.create(PredefinedConnectorProperties.PASSWORD, ""),
|
||||
ConnectorProperty
|
||||
.create(PredefinedConnectorProperties.JIRA_LABELS, ""),
|
||||
ConnectorProperty.create(
|
||||
PredefinedConnectorProperties.JIRA_HOURS_TYPE, "Default"));
|
||||
|
||||
private String name;
|
||||
private List<ConnectorProperty> properties;
|
||||
|
||||
private PredefinedConnectors(String name,
|
||||
ConnectorProperty... properties) {
|
||||
this.name = name;
|
||||
this.properties = Arrays.asList(properties);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public List<ConnectorProperty> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,8 +29,12 @@ import org.hibernate.Criteria;
|
|||
import org.hibernate.criterion.Order;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.daos.IntegrationEntityDAO;
|
||||
import org.libreplan.business.common.entities.Configuration;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.costcategories.entities.HourCost;
|
||||
|
|
@ -56,6 +60,9 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO<TypeOfWorkHours>
|
|||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Override
|
||||
public TypeOfWorkHours findUniqueByCode(TypeOfWorkHours typeOfWorkHours)
|
||||
throws InstanceNotFoundException {
|
||||
|
|
@ -194,13 +201,17 @@ public class TypeOfWorkHoursDAO extends IntegrationEntityDAO<TypeOfWorkHours>
|
|||
}
|
||||
|
||||
private void checkIsJiraConnectorTypeOfWorkHours(TypeOfWorkHours type) {
|
||||
Configuration configuration = configurationDAO.getConfiguration();
|
||||
if (configuration.getJiraConfiguration()
|
||||
.getJiraConnectorTypeOfWorkHours().getId().equals(type.getId())) {
|
||||
throw ValidationException
|
||||
.invalidValue(
|
||||
"Cannot delete the type of work hours. It is configured as type of work hours for JIRA connector.",
|
||||
type);
|
||||
Connector connector = connectorDAO
|
||||
.findUniqueByName(PredefinedConnectors.JIRA.getName());
|
||||
if (connector != null) {
|
||||
String name = connector.getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.JIRA_HOURS_TYPE);
|
||||
if (name.equals(type.getName())) {
|
||||
throw ValidationException
|
||||
.invalidValue(
|
||||
"Cannot delete the type of work hours. It is configured as type of work hours for JIRA connector.",
|
||||
type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ import org.hibernate.validator.NotNull;
|
|||
import org.libreplan.business.common.IHumanIdentifiable;
|
||||
import org.libreplan.business.common.IntegrationEntity;
|
||||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO;
|
||||
|
||||
|
|
@ -168,11 +171,13 @@ public class TypeOfWorkHours extends IntegrationEntity implements IHumanIdentifi
|
|||
@AssertTrue(message = "type of work hours for JIRA connector cannot be disabled")
|
||||
public boolean checkJiraConnectorTypeOfWorkHoursNotDisabled() {
|
||||
if (!isNewObject() && !getEnabled()) {
|
||||
TypeOfWorkHours typeOfWorkHours = Registry.getConfigurationDAO()
|
||||
.getConfiguration().getJiraConfiguration()
|
||||
.getJiraConnectorTypeOfWorkHours();
|
||||
if (typeOfWorkHours.getId().equals(getId())) {
|
||||
return false;
|
||||
Connector connector = Registry.getConnectorDAO().findUniqueByName(
|
||||
PredefinedConnectors.JIRA.getName());
|
||||
if (connector != null) {
|
||||
if (this.name.equals(connector.getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.JIRA_HOURS_TYPE))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.orders.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.daos.IGenericDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
|
||||
/**
|
||||
* Contract for {@link OrderSyncInfoDAO}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface IOrderSyncInfoDAO extends IGenericDAO<OrderSyncInfo, Long> {
|
||||
|
||||
/**
|
||||
* Search last synchronized info for the specified
|
||||
* <code>{@link Order}</code> and <code>connectorName</code>
|
||||
*
|
||||
* @param order
|
||||
* the order to search for
|
||||
* @param connectorName
|
||||
* the connector name
|
||||
*
|
||||
* @return Last synchronized info
|
||||
*/
|
||||
OrderSyncInfo findLastSynchronizedInfoByOrderAndConnectorName(Order order,
|
||||
String connectorName);
|
||||
|
||||
/**
|
||||
* Search last synchronized infos for the specified
|
||||
* <code>{@link Order}</code> and <code>connectorName</code>
|
||||
*
|
||||
* @param order
|
||||
* the order to search for
|
||||
* @param connectorName
|
||||
* the connector name
|
||||
* @return list of last synchronized infos
|
||||
*/
|
||||
List<OrderSyncInfo> findLastSynchronizedInfosByOrderAndConnectorName(
|
||||
Order order, String connectorName);
|
||||
|
||||
/**
|
||||
* Searches and returns <code>{@link OrderSyncInfo}</code> for the specified
|
||||
* <code>key</code> and <code>connectorName</code>
|
||||
*
|
||||
* @param key
|
||||
* the unique key with in connector id
|
||||
* @param order
|
||||
* the order
|
||||
* @param connectorName
|
||||
* the connector name
|
||||
*/
|
||||
OrderSyncInfo findByKeyOrderAndConnectorName(String key, Order order,
|
||||
String connectorName);
|
||||
|
||||
/**
|
||||
* Finds the {@link OrderSyncInfo}s for the specified
|
||||
* <code>connectorName</code>
|
||||
*
|
||||
* @param connectorName
|
||||
* the connector name
|
||||
* @return a list of OrderSyncInfo if found and null if not
|
||||
*/
|
||||
List<OrderSyncInfo> findByConnectorName(String connectorName);
|
||||
|
||||
/**
|
||||
* Returns true if there exists other {@link OrderSyncInfo} with the same
|
||||
* <code>{@link OrderSyncInfo#getKey()}</code>,
|
||||
* <code>{@link OrderSyncInfo#getOrder()}</code> and
|
||||
* <code>{@link OrderSyncInfo#getConnectorName()}</code>
|
||||
*
|
||||
* @param orderSyncInfo
|
||||
* the <code>{@link OrderSyncInfo}</code>
|
||||
*/
|
||||
boolean existsByKeyOrderAndConnectorNameAnotherTransaction(
|
||||
OrderSyncInfo orderSyncInfo);
|
||||
|
||||
/**
|
||||
* Returns unique {@link OrderSyncInfo} for the specified <code>key</code>,
|
||||
* <code>order</code> and <code>connectorName</code>
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param order
|
||||
* an order
|
||||
* @param connectorName
|
||||
* the name of the connector
|
||||
*/
|
||||
OrderSyncInfo findUniqueByKeyOrderAndConnectorNameAnotherTransaction(
|
||||
String key, Order order, String connectorName);
|
||||
}
|
||||
|
|
@ -442,12 +442,16 @@ public class OrderDAO extends IntegrationEntityDAO<Order> implements
|
|||
} else {
|
||||
String strQuery = "SELECT oa.order.id "
|
||||
+ "FROM OrderAuthorization oa "
|
||||
+ "WHERE oa.user = :user "
|
||||
+ "OR oa.profile IN (:profiles) ";
|
||||
+ "WHERE oa.user = :user ";
|
||||
if (!user.getProfiles().isEmpty()) {
|
||||
strQuery += "OR oa.profile IN (:profiles) ";
|
||||
}
|
||||
|
||||
Query query = getSession().createQuery(strQuery);
|
||||
query.setParameter("user", user);
|
||||
query.setParameterList("profiles", user.getProfiles());
|
||||
if (!user.getProfiles().isEmpty()) {
|
||||
query.setParameterList("profiles", user.getProfiles());
|
||||
}
|
||||
|
||||
return query.list();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.orders.daos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.libreplan.business.common.daos.GenericDAOHibernate;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* DAO for {@link OrderSyncInfo}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Repository
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class OrderSyncInfoDAO extends GenericDAOHibernate<OrderSyncInfo, Long>
|
||||
implements IOrderSyncInfoDAO {
|
||||
|
||||
@Override
|
||||
public OrderSyncInfo findLastSynchronizedInfoByOrderAndConnectorName(
|
||||
Order order, String connectorName) {
|
||||
List<OrderSyncInfo> orderSyncInfoList = findLastSynchronizedInfosByOrderAndConnectorName(
|
||||
order, connectorName);
|
||||
if (orderSyncInfoList == null || orderSyncInfoList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return orderSyncInfoList.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<OrderSyncInfo> findLastSynchronizedInfosByOrderAndConnectorName(
|
||||
Order order, String connectorName) {
|
||||
Criteria criteria = getSession().createCriteria(OrderSyncInfo.class);
|
||||
criteria.add(Restrictions.eq("order", order));
|
||||
criteria.add(Restrictions.eq("connectorName", connectorName));
|
||||
criteria.addOrder(org.hibernate.criterion.Order.desc("lastSyncDate"));
|
||||
return criteria.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrderSyncInfo findByKeyOrderAndConnectorName(String key,
|
||||
Order order, String connectorName) {
|
||||
Criteria criteria = getSession().createCriteria(OrderSyncInfo.class);
|
||||
criteria.add(Restrictions.eq("key", key));
|
||||
criteria.add(Restrictions.eq("order", order));
|
||||
criteria.add(Restrictions.eq("connectorName", connectorName));
|
||||
return (OrderSyncInfo) criteria.uniqueResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrderSyncInfo> findByConnectorName(String connectorName) {
|
||||
Criteria criteria = getSession().createCriteria(OrderSyncInfo.class);
|
||||
criteria.add(Restrictions.eq("connectorName", connectorName));
|
||||
return criteria.list();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
|
||||
public boolean existsByKeyOrderAndConnectorNameAnotherTransaction(
|
||||
OrderSyncInfo orderSyncInfo) {
|
||||
return existsOtherOrderSyncInfoByKeyOrderAndConnectorName(orderSyncInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if other {@link OrderSyncInfo} which is the same
|
||||
* as the given <code>{@link OrderSyncInfo}</code> already exists
|
||||
*
|
||||
* @param orderSyncInfo
|
||||
* the {@link OrderSyncInfo}
|
||||
*/
|
||||
private boolean existsOtherOrderSyncInfoByKeyOrderAndConnectorName(
|
||||
OrderSyncInfo orderSyncInfo) {
|
||||
OrderSyncInfo found = findByKeyOrderAndConnectorName(
|
||||
orderSyncInfo.getKey(), orderSyncInfo.getOrder(),
|
||||
orderSyncInfo.getConnectorName());
|
||||
return found != null && found != orderSyncInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
|
||||
public OrderSyncInfo findUniqueByKeyOrderAndConnectorNameAnotherTransaction(
|
||||
String key, Order order, String connectorName) {
|
||||
return findByKeyOrderAndConnectorName(key, order, connectorName);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -120,8 +120,6 @@ public class Order extends OrderLineGroup implements Comparable {
|
|||
|
||||
private Set<CustomerCommunication> customerCommunications = new HashSet<CustomerCommunication>();
|
||||
|
||||
private String importedLabel;
|
||||
|
||||
@Valid
|
||||
private SortedSet<DeadlineCommunication> deliveringDates = new TreeSet<DeadlineCommunication>(
|
||||
new DeliverDateComparator());
|
||||
|
|
@ -693,14 +691,6 @@ public class Order extends OrderLineGroup implements Comparable {
|
|||
return true;
|
||||
}
|
||||
|
||||
public String getImportedLabel() {
|
||||
return importedLabel;
|
||||
}
|
||||
|
||||
public void setImportedLabel(String importedLabel) {
|
||||
this.importedLabel = importedLabel;
|
||||
}
|
||||
|
||||
public void calculateAndSetTotalHours() {
|
||||
int result = 0;
|
||||
for (OrderElement orderElement : this.getChildren()) {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalA
|
|||
import org.libreplan.business.common.IntegrationEntity;
|
||||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
|
||||
import org.libreplan.business.common.entities.JiraConfiguration;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.labels.entities.Label;
|
||||
import org.libreplan.business.materials.entities.MaterialAssignment;
|
||||
|
|
@ -1568,6 +1568,24 @@ public abstract class OrderElement extends IntegrationEntity implements
|
|||
return workReportLineDAO.findByOrderElementAndChildren(this, sortedByDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets workReportLines of this order-element between the specified
|
||||
* <code>startDate</code> and <code>endDate</code>
|
||||
*
|
||||
* @param startDate
|
||||
* the startDate
|
||||
* @param endDate
|
||||
* the endDate
|
||||
* @param sortedByDate
|
||||
* @return list of workReportLines
|
||||
*/
|
||||
public List<WorkReportLine> getWorkReportLines(Date startDate,
|
||||
Date endDate, boolean sortedByDate) {
|
||||
IWorkReportLineDAO workReportLineDAO = Registry.getWorkReportLineDAO();
|
||||
return workReportLineDAO.findByOrderElementAndChildrenFilteredByDate(
|
||||
this, startDate, endDate, sortedByDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it has nay consolidated advance, if not checks if any parent
|
||||
* has it
|
||||
|
|
@ -1668,7 +1686,7 @@ public abstract class OrderElement extends IntegrationEntity implements
|
|||
if (code == null) {
|
||||
return false;
|
||||
}
|
||||
return code.startsWith(JiraConfiguration.CODE_PREFIX);
|
||||
return code.startsWith(PredefinedConnectorProperties.JIRA_CODE_PREFIX);
|
||||
}
|
||||
|
||||
public boolean isConvertedToContainer() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.business.orders.entities;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.validator.AssertTrue;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.libreplan.business.common.BaseEntity;
|
||||
import org.libreplan.business.common.Registry;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
|
||||
|
||||
/**
|
||||
* OrderSyncInfo entity. This entity holds order synchronization info. Each time
|
||||
* that order synchronization is successfully completed, an instance of this
|
||||
* entity is created or updated and saved to DB to hold the synchronized info.
|
||||
* This info is then displayed in UI.
|
||||
*
|
||||
* This entity contains the following fields:
|
||||
* <ul>
|
||||
* <li>lastSyncDate: last date where synchronization took place</li>
|
||||
* <li>key: an identifier, which connector's key is last synchronized</li>
|
||||
* <li>connectorName: the name of the {@link Connector} that has running the
|
||||
* synchronization</li>
|
||||
* <li>order: order that is synchronized</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class OrderSyncInfo extends BaseEntity {
|
||||
|
||||
private Date lastSyncDate;
|
||||
private String key;
|
||||
private String connectorName;
|
||||
private Order order;
|
||||
|
||||
public static OrderSyncInfo create(String key, Order order,
|
||||
String connectorName) {
|
||||
Validate.notEmpty(key);
|
||||
Validate.notNull(order);
|
||||
Validate.notEmpty(connectorName);
|
||||
return create(new OrderSyncInfo(key, order, connectorName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for Hibernate. Do not use!
|
||||
*/
|
||||
protected OrderSyncInfo() {
|
||||
}
|
||||
|
||||
private OrderSyncInfo(String key, Order order, String connectorName) {
|
||||
this.lastSyncDate = new Date();
|
||||
this.key = key;
|
||||
this.order = order;
|
||||
this.connectorName = connectorName;
|
||||
}
|
||||
|
||||
@NotNull(message = "last synchronized date not specified")
|
||||
public Date getLastSyncDate() {
|
||||
return lastSyncDate;
|
||||
}
|
||||
|
||||
public void setLastSyncDate(Date lastSyncDate) {
|
||||
this.lastSyncDate = lastSyncDate;
|
||||
}
|
||||
|
||||
@NotNull(message = "key not specified")
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@NotNull(message = "connector name not specified")
|
||||
public String getConnectorName() {
|
||||
return connectorName;
|
||||
}
|
||||
|
||||
public void setConnectorName(String connectorName) {
|
||||
this.connectorName = connectorName;
|
||||
}
|
||||
|
||||
public Order getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(Order order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
@AssertTrue(message = "project sync info is already being used")
|
||||
public boolean checkConstraintUniqueOrderSyncInfo() {
|
||||
if (StringUtils.isBlank(key) && order == null
|
||||
&& StringUtils.isBlank(connectorName)) {
|
||||
return true;
|
||||
}
|
||||
IOrderSyncInfoDAO orderSyncInfoDAO = Registry.getOrderSyncInfoDAO();
|
||||
if (isNewObject()) {
|
||||
return !orderSyncInfoDAO
|
||||
.existsByKeyOrderAndConnectorNameAnotherTransaction(this);
|
||||
} else {
|
||||
OrderSyncInfo found = orderSyncInfoDAO
|
||||
.findUniqueByKeyOrderAndConnectorNameAnotherTransaction(
|
||||
key, order, connectorName);
|
||||
return found == null || found.getId().equals(getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ import static org.libreplan.business.users.entities.UserRole.ROLE_ESTIMATED_PLAN
|
|||
import static org.libreplan.business.users.entities.UserRole.ROLE_EXPENSES;
|
||||
import static org.libreplan.business.users.entities.UserRole.ROLE_HOURS_TYPES;
|
||||
import static org.libreplan.business.users.entities.UserRole.ROLE_HOURS_WORKED_PER_RESOURCE_REPORT;
|
||||
import static org.libreplan.business.users.entities.UserRole.ROLE_JOB_SCHEDULING;
|
||||
import static org.libreplan.business.users.entities.UserRole.ROLE_LABELS;
|
||||
import static org.libreplan.business.users.entities.UserRole.ROLE_MACHINES;
|
||||
import static org.libreplan.business.users.entities.UserRole.ROLE_MAIN_SETTINGS;
|
||||
|
|
@ -74,7 +75,7 @@ import org.libreplan.business.users.entities.UserRole;
|
|||
public enum PredefinedProfiles {
|
||||
|
||||
SYSTEMS_ADMINISTRATOR("Systems Administrator", ROLE_MAIN_SETTINGS,
|
||||
ROLE_USER_ACCOUNTS, ROLE_PROFILES),
|
||||
ROLE_USER_ACCOUNTS, ROLE_PROFILES, ROLE_JOB_SCHEDULING),
|
||||
|
||||
PROJECT_MANAGER("Project Manager", ROLE_READ_ALL_PROJECTS,
|
||||
ROLE_EDIT_ALL_PROJECTS, ROLE_CREATE_PROJECTS, ROLE_PLANNING,
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ public enum UserRole {
|
|||
ROLE_MAIN_SETTINGS(_("Main Settings")),
|
||||
ROLE_USER_ACCOUNTS(_("User Accounts")),
|
||||
ROLE_PROFILES(_("Profiles")),
|
||||
ROLE_JOB_SCHEDULING(_("Job Scheduling")),
|
||||
ROLE_COMPANIES(_("Companies")),
|
||||
ROLE_SEND_TO_SUBCONTRACTORS(_("Send To Subcontractors")),
|
||||
ROLE_RECEIVED_FROM_SUBCONTRACTORS(_("Received From Subcontractors")),
|
||||
|
|
|
|||
|
|
@ -76,5 +76,12 @@ public interface IWorkReportLineDAO extends
|
|||
|
||||
List<WorkReportLine> findByOrderElementAndWorkReports(
|
||||
OrderElement orderElement, List<WorkReport> workReports);
|
||||
/**
|
||||
* Returns the {@link WorkReportLine}s of the specified
|
||||
* <code>orderElement</code> specified between <code>start</code> date and
|
||||
* <code>end</code> date
|
||||
*/
|
||||
List<WorkReportLine> findByOrderElementAndChildrenFilteredByDate(
|
||||
OrderElement orderElement, Date start, Date end, boolean sortByDate);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,4 +216,33 @@ public class WorkReportLineDAO extends IntegrationEntityDAO<WorkReportLine>
|
|||
return (List<WorkReportLine>) criteria.list();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<WorkReportLine> findByOrderElementAndChildrenFilteredByDate(
|
||||
OrderElement orderElement, Date start, Date end, boolean sortByDate) {
|
||||
|
||||
if (orderElement.isNewObject()) {
|
||||
return new ArrayList<WorkReportLine>();
|
||||
}
|
||||
|
||||
Collection<OrderElement> orderElements = orderElement.getAllChildren();
|
||||
orderElements.add(orderElement);
|
||||
|
||||
// Prepare criteria
|
||||
final Criteria criteria = getSession().createCriteria(
|
||||
WorkReportLine.class);
|
||||
criteria.add(Restrictions.in("orderElement", orderElements));
|
||||
|
||||
if (start != null) {
|
||||
criteria.add(Restrictions.ge("date", start));
|
||||
}
|
||||
if (end != null) {
|
||||
criteria.add(Restrictions.le("date", end));
|
||||
}
|
||||
if (sortByDate) {
|
||||
criteria.addOrder(org.hibernate.criterion.Order.asc("date"));
|
||||
}
|
||||
return criteria.list();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,106 +221,100 @@
|
|||
columnDataType="INTEGER" />
|
||||
</changeSet>
|
||||
|
||||
<!-- Jira configuration-->
|
||||
<changeSet id="add-new-column-jira_activated" author="miciele">
|
||||
<comment>
|
||||
Add new column jira_activated with default value FALSE to configuration table
|
||||
</comment>
|
||||
<addColumn tableName="configuration">
|
||||
<column name="jira_activated" type="BOOLEAN" />
|
||||
</addColumn>
|
||||
<addDefaultValue tableName="configuration" columnName="jira_activated"
|
||||
defaultValueBoolean="FALSE" />
|
||||
<addNotNullConstraint tableName="configuration"
|
||||
columnName="jira_activated"
|
||||
defaultNullValue="FALSE"
|
||||
columnDataType="BOOLEAN" />
|
||||
<!-- order sync info -->
|
||||
<changeSet author="miciele" id="create-table-order-sync-info">
|
||||
<comment>Create new table order_sync_info</comment>
|
||||
<createTable tableName="order_sync_info">
|
||||
<column name="id" type="BIGINT">
|
||||
<constraints nullable="false" primaryKey="true"/>
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="last_sync_date" type="DATETIME" >
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="key" type="VARCHAR(255)" >
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="connector_name" type="VARCHAR(255)" >
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="order_element_id" type="BIGINT" />
|
||||
</createTable>
|
||||
<addForeignKeyConstraint constraintName="order_sync_info_order_table_fkey"
|
||||
baseTableName="order_sync_info" baseColumnNames="order_element_id"
|
||||
referencedTableName="order_table" referencedColumnNames="order_element_id" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-new-column-jira_url" author="miciele">
|
||||
<comment>
|
||||
Add new column jira_url in table configuration
|
||||
</comment>
|
||||
<addColumn tableName="configuration">
|
||||
<column name="jira_url" type="VARCHAR(255)" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<!-- connector -->
|
||||
<changeSet author="rego" id="create-tables-related-to-connector-entity">
|
||||
<comment>Create tables related to Connector entity</comment>
|
||||
<createTable tableName="connector">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints nullable="false" primaryKey="true" primaryKeyName="connector_pkey" />
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="name" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<changeSet id="add-new-column-jira_label_url" author="miciele">
|
||||
<comment>
|
||||
Add new column jira_label_url in table configuration
|
||||
</comment>
|
||||
<addColumn tableName="configuration">
|
||||
<column name="jira_label_url" type="VARCHAR(255)" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<createTable tableName="connector_property">
|
||||
<column name="connector_id" type="BIGINT">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="connector_property_position" type="INTEGER">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="key" type="VARCHAR(255)">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="value" type="VARCHAR(255)" />
|
||||
</createTable>
|
||||
|
||||
<changeSet id="add-new-column-jira_user_id" author="miciele">
|
||||
<comment>
|
||||
Add new column jira_user_id in table configuration
|
||||
</comment>
|
||||
<addColumn tableName="configuration">
|
||||
<column name="jira_user_id" type="VARCHAR(255)" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<addPrimaryKey
|
||||
columnNames="connector_id,connector_property_position"
|
||||
constraintName="connector_property_pkey"
|
||||
tableName="connector_property"/>
|
||||
|
||||
<changeSet id="add-new-column-jira_password" author="miciele">
|
||||
<comment>
|
||||
Add new column jira_user_id in table configuration
|
||||
</comment>
|
||||
<addColumn tableName="configuration">
|
||||
<column name="jira_password" type="VARCHAR(255)" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-new-column-imported-label" author="miciele">
|
||||
<comment>
|
||||
Add new column imported_label in table order_table
|
||||
</comment>
|
||||
<addColumn tableName="order_table">
|
||||
<column name="imported_label" type="VARCHAR(255)" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-jira_connector_type_of_work_hours-to-configuration"
|
||||
author="mrego">
|
||||
<comment>
|
||||
Add new column jira_connector_type_of_work_hours to configuration
|
||||
table.
|
||||
</comment>
|
||||
<addColumn tableName="configuration">
|
||||
<column name="jira_connector_type_of_work_hours" type="BIGINT" />
|
||||
</addColumn>
|
||||
<addForeignKeyConstraint
|
||||
constraintName="configuration_jira_connector_type_of_work_hours_fkey"
|
||||
baseTableName="configuration"
|
||||
baseColumnNames="jira_connector_type_of_work_hours"
|
||||
referencedTableName="type_of_work_hours"
|
||||
referencedColumnNames="id" />
|
||||
baseColumnNames="connector_id"
|
||||
baseTableName="connector_property"
|
||||
constraintName="connector_property_connector_id_fkey"
|
||||
deferrable="false" initiallyDeferred="false"
|
||||
onDelete="NO ACTION" onUpdate="NO ACTION"
|
||||
referencedColumnNames="id"
|
||||
referencedTableName="connector"
|
||||
referencesUniqueColumn="false"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="rename-column-jira_label_url-in-configuration"
|
||||
author="mrego">
|
||||
<comment>
|
||||
Rename column jira_label_url to jira_labels in configuration table
|
||||
</comment>
|
||||
<renameColumn tableName="configuration"
|
||||
oldColumnName="jira_label_url"
|
||||
newColumnName="jira_labels"
|
||||
columnDataType="VARCHAR(255)" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="change-column-jira_labels-in-configuration-to-text"
|
||||
author="mrego" dbms="postgresql">
|
||||
<comment>Change column jira_labels in configuration to TEXT</comment>
|
||||
<modifyDataType tableName="configuration" columnName="jira_labels"
|
||||
newDataType="TEXT" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="change-column-jira_labels-in-configuration-to-text-in-mysql"
|
||||
author="mrego" dbms="mysql">
|
||||
<comment>Change column jira_labels in configuration to TEXT in MySQL</comment>
|
||||
<sql>ALTER TABLE configuration MODIFY jira_labels TEXT</sql>
|
||||
<!-- scheduler configuration -->
|
||||
<changeSet author="miciele" id="create-table-job-scheduler-configuration">
|
||||
<comment>Create new table job_scheduler_configuration</comment>
|
||||
<createTable tableName="job_scheduler_configuration">
|
||||
<column name="id" type="BIGINT" autoIncrement="true">
|
||||
<constraints nullable="false" primaryKey="true" />
|
||||
</column>
|
||||
<column name="version" type="BIGINT">
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="job_group" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="job_name" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="cron_expression" type="VARCHAR(255)" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="job_class_name" type="INTEGER" >
|
||||
<constraints nullable="false" />
|
||||
</column>
|
||||
<column name="connector_name" type="VARCHAR(255)" />
|
||||
<column name="schedule" type="BOOLEAN" />
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-projects_filter_period_since-column-to-user_table"
|
||||
|
|
@ -387,4 +381,4 @@
|
|||
onDelete="SET NULL"/>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
</databaseChangeLog>
|
||||
|
|
|
|||
|
|
@ -90,7 +90,13 @@
|
|||
<value>
|
||||
org/libreplan/business/expensesheets/entities/ExpenseSheets.hbm.xml
|
||||
</value>
|
||||
</list>
|
||||
<value>
|
||||
org/libreplan/business/common/entities/Connector.hbm.xml
|
||||
</value>
|
||||
<value>
|
||||
org/libreplan/business/common/entities/JobSchedulerConfiguration.hbm.xml
|
||||
</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="eventListeners">
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -120,18 +120,6 @@
|
|||
</set>
|
||||
|
||||
</component>
|
||||
|
||||
<!-- Jira configuration-->
|
||||
<component name="jiraConfiguration" class="org.libreplan.business.common.entities.JiraConfiguration">
|
||||
<property name="jiraActivated" column="jira_activated" not-null="true"/>
|
||||
<property name="jiraUrl" column="jira_url"/>
|
||||
<property name="jiraLabels" column="jira_labels" type="text"/>
|
||||
<property name="jiraUserId" column="jira_user_id"/>
|
||||
<property name="jiraPassword" column="jira_password"/>
|
||||
<many-to-one name="jiraConnectorTypeOfWorkHours" cascade="none"
|
||||
column="jira_connector_type_of_work_hours" />
|
||||
</component>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
<hibernate-mapping default-access="field"
|
||||
package="org.libreplan.business.common.entities">
|
||||
|
||||
<class name="Connector" table="connector">
|
||||
<id name="id" column="id" type="long" access="property">
|
||||
<generator class="hilo">
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
|
||||
<version name="version" access="property" type="long" />
|
||||
|
||||
<property name="name" column="name" not-null="true" />
|
||||
|
||||
<list name="properties" table="connector_property" lazy="false">
|
||||
<key column="connector_id" />
|
||||
<list-index column="connector_property_position" />
|
||||
|
||||
<composite-element class="ConnectorProperty">
|
||||
<property name="key" column="key"
|
||||
not-null="true" />
|
||||
<property name="value" column="value" />
|
||||
</composite-element>
|
||||
</list>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
<hibernate-mapping default-access="field"
|
||||
package="org.libreplan.business.common.entities">
|
||||
|
||||
<class name="JobSchedulerConfiguration" table="job_scheduler_configuration">
|
||||
<id name="id" column="id" type="long" access="property">
|
||||
<generator class="hilo">
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
|
||||
<version name="version" access="property" type="long" />
|
||||
|
||||
<property name="jobGroup" column="job_group" not-null="true" />
|
||||
<property name="jobName" column="job_name" not-null="true" />
|
||||
<property name="cronExpression" column="cron_expression" not-null="true" />
|
||||
<property name="jobClassName" access="field" column="job_class_name" not-null="true">
|
||||
<type name="org.hibernate.type.EnumType">
|
||||
<param name="enumClass">org.libreplan.business.common.entities.JobClassNameEnum</param>
|
||||
</type>
|
||||
</property>
|
||||
<property name="connectorName" column="connector_name" />
|
||||
<property name="schedule" column="schedule" />
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
|
@ -126,9 +126,6 @@
|
|||
</type>
|
||||
</property>
|
||||
|
||||
<!-- extra column to hold imported label -->
|
||||
<property name="importedLabel" column="imported_label"/>
|
||||
|
||||
<!-- Not indexed -->
|
||||
<many-to-one name="customer" access="field" class="org.libreplan.business.externalcompanies.entities.ExternalCompany"/>
|
||||
|
||||
|
|
@ -300,4 +297,20 @@
|
|||
<property name="totalIndirectExpenses" access="field" column="total_indirect_expenses"/>
|
||||
</class>
|
||||
|
||||
<class name="OrderSyncInfo" table="order_sync_info">
|
||||
<id name="id" access="property" type="long">
|
||||
<generator class="hilo" >
|
||||
<param name="max_lo">100</param>
|
||||
</generator>
|
||||
</id>
|
||||
<version name="version" access="property" type="long" />
|
||||
<property name="lastSyncDate" column="last_sync_date" access="field" not-null="true"/>
|
||||
<property name="key" access="field" not-null="true"/>
|
||||
<property name="connectorName" column="connector_name" access="field" not-null="true"/>
|
||||
|
||||
<many-to-one name="order" class="Order">
|
||||
<column name="order_element_id" not-null="true"/>
|
||||
</many-to-one>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
|
|
|
|||
|
|
@ -330,6 +330,11 @@
|
|||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
</dependency>
|
||||
<!-- QuartzJobBean in spring-context-support.jar -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<!-- Spring security -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
|
|
@ -481,5 +486,10 @@
|
|||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
<!-- Quartz framework -->
|
||||
<dependency>
|
||||
<groupId>org.quartz-scheduler</groupId>
|
||||
<artifactId>quartz</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
|
||||
/**
|
||||
* A job that exports time sheets to Tim SOAP server
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class ExportTimesheetToTimJob extends QuartzJobBean {
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(ExportTimesheetToTimJob.class);
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext context)
|
||||
throws JobExecutionException {
|
||||
ApplicationContext applicationContext = (ApplicationContext) context
|
||||
.getJobDetail().getJobDataMap().get("applicationContext");
|
||||
|
||||
IExportTimesheetsToTim exportTimesheetsToTim = (IExportTimesheetsToTim) applicationContext
|
||||
.getBean("exportTimesheetsToTim");
|
||||
|
||||
try {
|
||||
List<SynchronizationInfo> syncInfos = exportTimesheetsToTim
|
||||
.exportTimesheets();
|
||||
|
||||
LOG.info("Export scuccessful: "
|
||||
+ (syncInfos == null || syncInfos.isEmpty()));
|
||||
|
||||
} catch (ConnectorException e) {
|
||||
LOG.error("Export timesheet to Tim failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,341 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.IOnTransaction;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.libreplan.business.resources.daos.IWorkerDAO;
|
||||
import org.libreplan.business.resources.entities.Worker;
|
||||
import org.libreplan.business.workreports.entities.WorkReportLine;
|
||||
import org.libreplan.importers.tim.DurationDTO;
|
||||
import org.libreplan.importers.tim.PersonDTO;
|
||||
import org.libreplan.importers.tim.ProductDTO;
|
||||
import org.libreplan.importers.tim.RegistrationDateDTO;
|
||||
import org.libreplan.importers.tim.TimOptions;
|
||||
import org.libreplan.importers.tim.TimeRegistrationDTO;
|
||||
import org.libreplan.importers.tim.TimeRegistrationRequestDTO;
|
||||
import org.libreplan.importers.tim.TimeRegistrationResponseDTO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Implementation of export timesheets to tim
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public class ExportTimesheetsToTim implements IExportTimesheetsToTim {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(ExportTimesheetsToTim.class);
|
||||
|
||||
@Autowired
|
||||
private IWorkerDAO workerDAO;
|
||||
|
||||
@Autowired
|
||||
IOrderSyncInfoDAO orderSyncInfoDAO;
|
||||
|
||||
@Autowired
|
||||
private IAdHocTransactionService adHocTransactionService;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
private SynchronizationInfo synchronizationInfo;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<SynchronizationInfo> exportTimesheets() throws ConnectorException {
|
||||
Connector connector = getTimConnector();
|
||||
if (connector == null) {
|
||||
throw new ConnectorException(_("Tim connector not found"));
|
||||
}
|
||||
if (!connector.areConnectionValuesValid()) {
|
||||
throw new ConnectorException(
|
||||
_("Connection values of Tim connector are invalid"));
|
||||
}
|
||||
|
||||
synchronizationInfo = new SynchronizationInfo(_("Export"));
|
||||
|
||||
List<SynchronizationInfo> syncInfos = new ArrayList<SynchronizationInfo>();
|
||||
|
||||
List<OrderSyncInfo> orderSyncInfos = orderSyncInfoDAO.findByConnectorName(PredefinedConnectors.TIM.getName());
|
||||
if (orderSyncInfos == null || orderSyncInfos.isEmpty()) {
|
||||
LOG.warn("No items found in 'OrderSyncInfo' to export to Tim");
|
||||
synchronizationInfo.addFailedReason(_("No items found in 'OrderSyncInfo' to export to Tim"));
|
||||
syncInfos.add(synchronizationInfo);
|
||||
return syncInfos;
|
||||
}
|
||||
|
||||
for (OrderSyncInfo orderSyncInfo : orderSyncInfos) {
|
||||
LOG.info("Exporting '" + orderSyncInfo.getOrder().getName() + "'");
|
||||
exportTimesheets(orderSyncInfo.getKey(), orderSyncInfo.getOrder(),
|
||||
connector);
|
||||
if (!synchronizationInfo.isSuccessful()) {
|
||||
syncInfos.add(synchronizationInfo);
|
||||
}
|
||||
}
|
||||
return syncInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public void exportTimesheets(String productCode, Order order)
|
||||
throws ConnectorException {
|
||||
if (productCode == null || productCode.isEmpty()) {
|
||||
throw new ConnectorException(_("Product code should not be empty"));
|
||||
}
|
||||
if (order == null) {
|
||||
throw new ConnectorException(_("Order should not be empty"));
|
||||
}
|
||||
|
||||
Connector connector = getTimConnector();
|
||||
if (connector == null) {
|
||||
throw new ConnectorException(_("Tim connector not found"));
|
||||
}
|
||||
|
||||
if (!connector.areConnectionValuesValid()) {
|
||||
throw new ConnectorException(
|
||||
_("Connection values of Tim connector are invalid"));
|
||||
}
|
||||
|
||||
exportTimesheets(productCode, order, connector);
|
||||
}
|
||||
|
||||
/**
|
||||
* exports time sheets to Tim
|
||||
*
|
||||
* @param productCode
|
||||
* the product code
|
||||
* @param order
|
||||
* the order
|
||||
* @param connector
|
||||
* the connector
|
||||
*
|
||||
* @return true if export is succeeded, false otherwise
|
||||
*/
|
||||
private void exportTimesheets(String productCode, Order order,
|
||||
Connector connector) {
|
||||
|
||||
synchronizationInfo = new SynchronizationInfo(_(
|
||||
"Export product code {0}, project {1}", productCode,
|
||||
order.getName()));
|
||||
|
||||
Map<String, String> properties = connector.getPropertiesAsMap();
|
||||
|
||||
String url = properties.get(PredefinedConnectorProperties.SERVER_URL);
|
||||
String userName = properties
|
||||
.get(PredefinedConnectorProperties.USERNAME);
|
||||
String password = properties
|
||||
.get(PredefinedConnectorProperties.PASSWORD);
|
||||
int nrDaysTimesheetToTim = Integer.parseInt(properties
|
||||
.get(PredefinedConnectorProperties.TIM_NR_DAYS_TIMESHEET));
|
||||
|
||||
LocalDate dateNrOfDaysBack = new LocalDate()
|
||||
.minusDays(nrDaysTimesheetToTim);
|
||||
|
||||
List<WorkReportLine> workReportLines = order.getWorkReportLines(
|
||||
dateNrOfDaysBack.toDateTimeAtStartOfDay().toDate(), new Date(),
|
||||
true);
|
||||
if (workReportLines == null || workReportLines.isEmpty()) {
|
||||
LOG.warn("No work reportlines are found for order: '"
|
||||
+ order.getName() + "'");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"No work reportlines are found for order: \"{0}\"",
|
||||
order.getName()));
|
||||
return;
|
||||
}
|
||||
|
||||
List<TimeRegistrationDTO> timeRegistrationDTOs = new ArrayList<TimeRegistrationDTO>();
|
||||
|
||||
for (WorkReportLine workReportLine : workReportLines) {
|
||||
TimeRegistrationDTO timeRegistrationDTO = createExportTimeRegistration(
|
||||
productCode, workReportLine);
|
||||
if (timeRegistrationDTO != null) {
|
||||
timeRegistrationDTOs.add(timeRegistrationDTO);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeRegistrationDTOs.isEmpty()) {
|
||||
LOG.warn("Unable to crate timeregistration for request");
|
||||
synchronizationInfo
|
||||
.addFailedReason(_("Unable to crate time registration for request"));
|
||||
return;
|
||||
}
|
||||
|
||||
TimeRegistrationRequestDTO timeRegistrationRequestDTO = new TimeRegistrationRequestDTO();
|
||||
timeRegistrationRequestDTO.setTimeRegistrations(timeRegistrationDTOs);
|
||||
|
||||
TimeRegistrationResponseDTO timeRegistrationResponseDTO = TimSoapClient
|
||||
.sendRequestReceiveResponse(url, userName, password,
|
||||
timeRegistrationRequestDTO, TimeRegistrationResponseDTO.class);
|
||||
|
||||
if (timeRegistrationResponseDTO == null) {
|
||||
LOG.error("No response or exception in response");
|
||||
synchronizationInfo
|
||||
.addFailedReason(_("No response or exception in response"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRefsListEmpty(timeRegistrationResponseDTO.getRefs())) {
|
||||
LOG.warn("Registration response with empty refs");
|
||||
synchronizationInfo
|
||||
.addFailedReason(_("Registration response with empty refs"));
|
||||
return;
|
||||
}
|
||||
saveSyncInfoOnAnotherTransaction(productCode, order);
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if list of refs is empty
|
||||
*
|
||||
* @param refs
|
||||
* the list of refs
|
||||
* @return true if list is empty otherwise false
|
||||
*/
|
||||
private boolean isRefsListEmpty(List<Integer> refs) {
|
||||
if (refs == null) {
|
||||
return true;
|
||||
}
|
||||
refs.removeAll(Collections.singleton(0));
|
||||
return refs.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves synchronization info
|
||||
*
|
||||
* @param productCode
|
||||
* the productcode
|
||||
* @param order
|
||||
* the order
|
||||
*/
|
||||
private void saveSyncInfoOnAnotherTransaction(final String productCode,
|
||||
final Order order) {
|
||||
adHocTransactionService
|
||||
.runOnAnotherTransaction(new IOnTransaction<Void>() {
|
||||
@Override
|
||||
public Void execute() {
|
||||
OrderSyncInfo orderSyncInfo = orderSyncInfoDAO
|
||||
.findByKeyOrderAndConnectorName(productCode,
|
||||
order,
|
||||
PredefinedConnectors.TIM.getName());
|
||||
if (orderSyncInfo == null) {
|
||||
orderSyncInfo = OrderSyncInfo.create(productCode,
|
||||
order, PredefinedConnectors.TIM.getName());
|
||||
}
|
||||
orderSyncInfo.setLastSyncDate(new Date());
|
||||
orderSyncInfoDAO.save(orderSyncInfo);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates export time registration
|
||||
*
|
||||
* @param productCode
|
||||
* the product code
|
||||
* @param workReportLine
|
||||
* the workreportLine
|
||||
* @return timeRegistration DTO
|
||||
*/
|
||||
private TimeRegistrationDTO createExportTimeRegistration(String productCode,
|
||||
WorkReportLine workReportLine) {
|
||||
Worker worker;
|
||||
String workerCode = workReportLine.getResource().getCode();
|
||||
try {
|
||||
worker = workerDAO.findByCode(workerCode);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
LOG.warn("Worker '" + workerCode + "' not found");
|
||||
synchronizationInfo.addFailedReason(_("Worker \"{0}\" not found",
|
||||
workerCode));
|
||||
return null;
|
||||
}
|
||||
|
||||
PersonDTO personDTO = new PersonDTO();
|
||||
personDTO.setName(worker.getName());
|
||||
personDTO.setOptions(TimOptions.UPDATE_OR_INSERT);
|
||||
|
||||
ProductDTO productDTO = new ProductDTO();
|
||||
productDTO.setOptions(TimOptions.UPDATE_OR_INSERT);
|
||||
productDTO.setCode(productCode);
|
||||
|
||||
RegistrationDateDTO registrationDTO = new RegistrationDateDTO();
|
||||
registrationDTO.setOptions(TimOptions.UPDATE_OR_INSERT);
|
||||
registrationDTO.setDate(workReportLine.getLocalDate());
|
||||
|
||||
DurationDTO durationDTO = new DurationDTO();
|
||||
durationDTO.setOptions(TimOptions.DECIMAL);
|
||||
durationDTO.setDuration(workReportLine.getEffort()
|
||||
.toHoursAsDecimalWithScale(2).doubleValue());
|
||||
|
||||
TimeRegistrationDTO timeRegistrationDTO = new TimeRegistrationDTO();
|
||||
timeRegistrationDTO.setPerson(personDTO);
|
||||
timeRegistrationDTO.setProduct(productDTO);
|
||||
timeRegistrationDTO.setRegistrationDate(registrationDTO);
|
||||
timeRegistrationDTO.setDuration(durationDTO);
|
||||
return timeRegistrationDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public OrderSyncInfo getOrderLastSyncInfo(Order order) {
|
||||
return orderSyncInfoDAO.findLastSynchronizedInfoByOrderAndConnectorName(
|
||||
order, PredefinedConnectors.TIM.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* finds and returns a Tim connector
|
||||
*/
|
||||
private Connector getTimConnector() {
|
||||
return connectorDAO
|
||||
.findUniqueByName(PredefinedConnectors.TIM.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynchronizationInfo getSynchronizationInfo() {
|
||||
return synchronizationInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
|
||||
/**
|
||||
* Export time sheets of an existing order to Tim SOAP server using
|
||||
* {@link TimSoapClient}.
|
||||
*
|
||||
* It exports the time sheets between periods current-date minus
|
||||
* <code>NrDaysTimesheetToTim</code> specified in the Tim {@link Connector} and
|
||||
* the current-date
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface IExportTimesheetsToTim {
|
||||
|
||||
/**
|
||||
* Exports time sheets of the specified <code>productCode</code> and
|
||||
* <code>{@link Order}</code> to Tim SOAP server
|
||||
*
|
||||
* @param productCode
|
||||
* the Tim's productCode
|
||||
* @param order
|
||||
* an existing order
|
||||
* @throws ConnectorException
|
||||
* if connector is not valid
|
||||
*/
|
||||
void exportTimesheets(String productCode, Order order) throws ConnectorException;
|
||||
|
||||
/**
|
||||
* Exporting the time sheets to Tim SOAP server, if they are already
|
||||
* exported using
|
||||
* {@link IExportTimesheetsToTim#exportTimesheets(String, Order)}.
|
||||
*
|
||||
* It gets then an already exported time sheets from {@link OrderSyncInfo}
|
||||
* and re-exporting them.
|
||||
*
|
||||
* @return a list of {@link SynchronizationInfo}
|
||||
*
|
||||
* @throws ConnectorException
|
||||
* if connector is not valid
|
||||
*/
|
||||
List<SynchronizationInfo> exportTimesheets() throws ConnectorException;
|
||||
|
||||
/**
|
||||
* Gets the most recent synchronized time sheet info
|
||||
*
|
||||
* @param order
|
||||
* the order
|
||||
* @return recent synchronized time sheet info
|
||||
*/
|
||||
OrderSyncInfo getOrderLastSyncInfo(Order order);
|
||||
|
||||
/**
|
||||
* Returns synchronization info, success of fail info
|
||||
*/
|
||||
SynchronizationInfo getSynchronizationInfo();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.calendars.entities.CalendarException;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
|
||||
/**
|
||||
* Import Rosters from Tim SOAP server using {@link TimSoapClient} and updates
|
||||
* worker's Exception calendar accordingly
|
||||
*
|
||||
* It imports the Rosters between periods current-date and current-date plus
|
||||
* <code>NrDaysRosterFromTim</code> specified in Tim {@link Connector}.
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface IImportRosterFromTim {
|
||||
|
||||
/**
|
||||
* Import rosters from Tim and update workers {@link CalendarException}
|
||||
*
|
||||
* If worker calendar exception already exists it will be removed and added
|
||||
* new one, in other cases a new calendar exception will be created
|
||||
*
|
||||
* @return a list of {@link SynchronizationInfo}
|
||||
*
|
||||
* @throws ConnectorException
|
||||
* if connector is not valid
|
||||
*/
|
||||
List<SynchronizationInfo> importRosters() throws ConnectorException;
|
||||
|
||||
/**
|
||||
* Returns synchronization info, success of fail info
|
||||
*/
|
||||
SynchronizationInfo getSynchronizationInfo();
|
||||
}
|
||||
|
|
@ -23,8 +23,10 @@ import java.util.List;
|
|||
|
||||
import org.libreplan.business.advance.entities.AdvanceMeasurement;
|
||||
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.libreplan.importers.jira.IssueDTO;
|
||||
|
||||
/**
|
||||
|
|
@ -48,8 +50,10 @@ public interface IJiraOrderElementSynchronizer {
|
|||
* https://jira.atlassian.com/browse/JRA-29409
|
||||
*
|
||||
* @return A list of labels
|
||||
* @throws ConnectorException
|
||||
* if connector not found
|
||||
*/
|
||||
List<String> getAllJiraLabels();
|
||||
List<String> getAllJiraLabels() throws ConnectorException;
|
||||
|
||||
/**
|
||||
* Get all jira issues based on the specified <code>label</code> parameter
|
||||
|
|
@ -59,8 +63,10 @@ public interface IJiraOrderElementSynchronizer {
|
|||
* search criteria for jira issues
|
||||
*
|
||||
* @return list of jira issues
|
||||
* @throws ConnectorException
|
||||
* if connector not found or contains invalid connection values
|
||||
*/
|
||||
List<IssueDTO> getJiraIssues(String label);
|
||||
List<IssueDTO> getJiraIssues(String label) throws ConnectorException;
|
||||
|
||||
/**
|
||||
* Synchronizes the list of {@link OrderElement}s,
|
||||
|
|
@ -82,9 +88,42 @@ public interface IJiraOrderElementSynchronizer {
|
|||
*/
|
||||
void syncOrderElementsWithJiraIssues(List<IssueDTO> issues, Order order);
|
||||
|
||||
/**
|
||||
* Saves synchronization info
|
||||
*
|
||||
* @param key
|
||||
* the key(label)
|
||||
* @param order
|
||||
* an order which already synchronized
|
||||
*/
|
||||
void saveSyncInfo(String key, Order order);
|
||||
|
||||
/**
|
||||
* Gets the most recent synchronized info
|
||||
*
|
||||
* @param order
|
||||
* the order
|
||||
* @return recent synchronized time sheet info
|
||||
*/
|
||||
OrderSyncInfo getOrderLastSyncInfo(Order order);
|
||||
|
||||
/**
|
||||
* returns synchronization info, success or fail info
|
||||
*/
|
||||
JiraSyncInfo getJiraSyncInfo();
|
||||
SynchronizationInfo getSynchronizationInfo();
|
||||
|
||||
/**
|
||||
* Synchronize order elements with JIRA issues if they already synchronized
|
||||
* using
|
||||
* {@link IJiraOrderElementSynchronizer#syncOrderElementsWithJiraIssues(List, Order)
|
||||
*
|
||||
* It gets then an already synchronized orders from the
|
||||
* {@link OrderSyncInfo} and re-synchronize them
|
||||
*
|
||||
* @return a list of {@link SynchronizationInfo}
|
||||
*
|
||||
* @throws ConnectorException
|
||||
* if connector not found or contains invalid connection values
|
||||
*/
|
||||
List<SynchronizationInfo> syncOrderElementsWithJiraIssues() throws ConnectorException;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.libreplan.importers;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.workreports.entities.WorkReportType;
|
||||
import org.libreplan.importers.jira.IssueDTO;
|
||||
|
|
@ -42,7 +43,6 @@ public interface IJiraTimesheetSynchronizer {
|
|||
/**
|
||||
* Synchronize jira timesheet with the specified jira <code>issues</code> .
|
||||
*
|
||||
*
|
||||
* Loop through all jira <code>issues</code> and check if timesheet is
|
||||
* already exist for the specified issue item. If it is, update the
|
||||
* timesheet with that issue item. If not create new one
|
||||
|
|
@ -51,12 +51,14 @@ public interface IJiraTimesheetSynchronizer {
|
|||
* the jira issues
|
||||
* @param order
|
||||
* an existing order
|
||||
* @throws ConnectorException
|
||||
* if not valid connector or connector contains invalid values
|
||||
*/
|
||||
void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order);
|
||||
void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order) throws ConnectorException;
|
||||
|
||||
/**
|
||||
* returns synchronization info, success or fail info
|
||||
*/
|
||||
JiraSyncInfo getJiraSyncInfo();
|
||||
SynchronizationInfo getSynchronizationInfo();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.scheduling.quartz.CronTriggerBean;
|
||||
import org.springframework.scheduling.quartz.JobDetailBean;
|
||||
|
||||
/**
|
||||
* A manager(client) that dynamically creates jobs and cron-triggers using
|
||||
* spring quartz library.
|
||||
*
|
||||
* The start and destroy of the scheduler itself is managed by the Spring
|
||||
* framework. The scheduler starts automatically when the application starts and
|
||||
* destroyed when the application stops.
|
||||
*
|
||||
* This manager (un)schedules the jobs based on the configuration
|
||||
* {@link JobSchedulerConfiguration} entity once the scheduler starts.
|
||||
*
|
||||
* <ul>
|
||||
* <li>Schedule job:create job {@link JobDetailBean} and cron-trigger
|
||||
* {@link CronTriggerBean}, associated the trigger with the job and add it to
|
||||
* the scheduler.
|
||||
* <li>
|
||||
* <li>Delete job: search the job in the scheduler and if found
|
||||
* unschedule(delete) the job</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface ISchedulerManager {
|
||||
|
||||
/**
|
||||
* Reads the jobs to be scheduled from the {@link JobSchedulerConfiguration}
|
||||
* and schedules the jobs based on the cron expression defined for each job
|
||||
* in the {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
void scheduleJobs();
|
||||
|
||||
/**
|
||||
* Reads the jobs to be scheduled from the specified
|
||||
* <code>{@link JobSchedulerConfiguration}</code> and (un)schedule it
|
||||
* accordingly
|
||||
*
|
||||
* In the specified <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>{@link JobSchedulerConfiguration#getConnectorName()}</code>
|
||||
* check if job has a connector and the connector is activated</li>
|
||||
* <li><code>{@link JobSchedulerConfiguration#isSchedule()}</code> if true
|
||||
* the job would be scheduled, if not job deleted</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration for job to be (un)scheduled
|
||||
* @throws SchedulerException
|
||||
* if unable to (un)schedule
|
||||
*/
|
||||
void scheduleOrUnscheduleJob(JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* Deletes the job from the scheduler for the specified job by
|
||||
* <code>{@link JobSchedulerConfiguration}</code>, if the job is already in
|
||||
* the scheduler
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration for job to be deleted
|
||||
* @throws SchedulerException
|
||||
* if unable to delete
|
||||
*/
|
||||
void deleteJob(JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException;
|
||||
|
||||
/**
|
||||
* gets the next fire time for the specified job from
|
||||
* {@link JobSchedulerConfiguration} if job is already scheduled. This is
|
||||
* only neede for UI
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration to check for next fire time
|
||||
* @return next fire time or empty string
|
||||
*/
|
||||
String getNextFireTime(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.calendars.daos.ICalendarExceptionTypeDAO;
|
||||
import org.libreplan.business.calendars.entities.CalendarException;
|
||||
import org.libreplan.business.calendars.entities.CalendarExceptionType;
|
||||
import org.libreplan.business.calendars.entities.Capacity;
|
||||
import org.libreplan.business.calendars.entities.PredefinedCalendarExceptionTypes;
|
||||
import org.libreplan.business.calendars.entities.ResourceCalendar;
|
||||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.IOnTransaction;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.resources.daos.IWorkerDAO;
|
||||
import org.libreplan.business.resources.entities.Worker;
|
||||
import org.libreplan.business.workingday.EffortDuration;
|
||||
import org.libreplan.importers.RosterException.RosterExceptionItem;
|
||||
import org.libreplan.importers.tim.DataDTO;
|
||||
import org.libreplan.importers.tim.DepartmentDTO;
|
||||
import org.libreplan.importers.tim.FilterDTO;
|
||||
import org.libreplan.importers.tim.PeriodDTO;
|
||||
import org.libreplan.importers.tim.PersonDTO;
|
||||
import org.libreplan.importers.tim.RosterCategoryDTO;
|
||||
import org.libreplan.importers.tim.RosterDTO;
|
||||
import org.libreplan.importers.tim.RosterRequestDTO;
|
||||
import org.libreplan.importers.tim.RosterResponseDTO;
|
||||
import org.libreplan.web.calendars.IBaseCalendarModel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Implementation of import roosters from tim
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class ImportRosterFromTim implements IImportRosterFromTim {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(ImportRosterFromTim.class);
|
||||
|
||||
@Autowired
|
||||
private IWorkerDAO workerDAO;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Autowired
|
||||
private IAdHocTransactionService adHocTransactionService;
|
||||
|
||||
@Autowired
|
||||
private ICalendarExceptionTypeDAO calendarExceptionTypeDAO;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("subclass")
|
||||
private IBaseCalendarModel baseCalendarModel;
|
||||
|
||||
private SynchronizationInfo synchronizationInfo;
|
||||
|
||||
/**
|
||||
* Search criteria for roster exception days in RESPONSE message
|
||||
* {@link RosterDTO}
|
||||
*/
|
||||
private static final String ABSENT = "Afwezig";
|
||||
|
||||
/**
|
||||
* The word "Vakantie"(holiday) in RESPONSE message that would be translated
|
||||
* to {@link PredefinedCalendarExceptionTypes#RESOURCE_HOLIDAY }
|
||||
*/
|
||||
private static final String HOLIDAY = "Vakantie";
|
||||
|
||||
/**
|
||||
* The word "Feestdag"(bank holiday) in RESPONSE message that would be
|
||||
* translated to {@link PredefinedCalendarExceptionTypes#BANK_HOLIDAY}
|
||||
*/
|
||||
private static final String BANK_HOLIDAY = "Feestdag";
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<SynchronizationInfo> importRosters() throws ConnectorException {
|
||||
Connector connector = connectorDAO
|
||||
.findUniqueByName(PredefinedConnectors.TIM.getName());
|
||||
if (connector == null) {
|
||||
throw new ConnectorException(_("Tim connector not found"));
|
||||
}
|
||||
|
||||
if (!connector.areConnectionValuesValid()) {
|
||||
throw new ConnectorException(
|
||||
_("Connection values of Tim connector are invalid"));
|
||||
}
|
||||
|
||||
Map<String, String> properties = connector.getPropertiesAsMap();
|
||||
String url = properties.get(PredefinedConnectorProperties.SERVER_URL);
|
||||
|
||||
String userName = properties
|
||||
.get(PredefinedConnectorProperties.USERNAME);
|
||||
|
||||
String password = properties
|
||||
.get(PredefinedConnectorProperties.PASSWORD);
|
||||
|
||||
int nrDaysRosterFromTim = Integer.parseInt(properties
|
||||
.get(PredefinedConnectorProperties.TIM_NR_DAYS_ROSTER));
|
||||
|
||||
int productivityFactor = Integer.parseInt(properties
|
||||
.get(PredefinedConnectorProperties.TIM_PRODUCTIVITY_FACTOR));
|
||||
|
||||
|
||||
String departmentIds = properties
|
||||
.get(PredefinedConnectorProperties.TIM_DEPARTAMENTS_IMPORT_ROSTER);
|
||||
|
||||
if (StringUtils.isBlank(departmentIds)) {
|
||||
LOG.warn("No departments configured");
|
||||
throw new ConnectorException(_("No departments configured"));
|
||||
}
|
||||
|
||||
String[] departmentIdsArray = StringUtils.stripAll(StringUtils.split(
|
||||
departmentIds, ","));
|
||||
|
||||
List<SynchronizationInfo> syncInfos = new ArrayList<SynchronizationInfo>();
|
||||
|
||||
for (String department : departmentIdsArray) {
|
||||
LOG.info("Department: " + department);
|
||||
|
||||
synchronizationInfo = new SynchronizationInfo(_(
|
||||
"Import roster for department {0}", department));
|
||||
|
||||
RosterRequestDTO rosterRequestDTO = createRosterRequest(department,
|
||||
nrDaysRosterFromTim);
|
||||
RosterResponseDTO rosterResponseDTO = TimSoapClient
|
||||
.sendRequestReceiveResponse(url, userName, password,
|
||||
rosterRequestDTO, RosterResponseDTO.class);
|
||||
|
||||
if (rosterResponseDTO != null) {
|
||||
updateWorkersCalendarException(rosterResponseDTO,
|
||||
productivityFactor);
|
||||
if (!synchronizationInfo.isSuccessful()) {
|
||||
syncInfos.add(synchronizationInfo);
|
||||
}
|
||||
} else {
|
||||
LOG.error("No valid response for department " + department);
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"No valid response for department \"{0}\"",
|
||||
department));
|
||||
syncInfos.add(synchronizationInfo);
|
||||
}
|
||||
}
|
||||
return syncInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* updates workers Exception calendar
|
||||
*
|
||||
* @param rosterResponse
|
||||
* the response from Tim SOAP server
|
||||
*/
|
||||
private void updateWorkersCalendarException(
|
||||
final RosterResponseDTO rosterResponse, final int productivityFactor) {
|
||||
adHocTransactionService
|
||||
.runOnAnotherTransaction(new IOnTransaction<Void>() {
|
||||
|
||||
@Override
|
||||
public Void execute() {
|
||||
List<RosterException> rosterExceptions = getRosterExceptions(
|
||||
rosterResponse, productivityFactor);
|
||||
if (!rosterExceptions.isEmpty()) {
|
||||
updateCalendarException(rosterExceptions);
|
||||
} else {
|
||||
LOG.info("No roster-exceptions found in the response");
|
||||
synchronizationInfo
|
||||
.addFailedReason(_("No roster-exceptions found in the response"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through <code>rosterResponseDTO</code> and creates
|
||||
* {@link RosterException}s and link them to the <code>worker</code>
|
||||
*
|
||||
* @param rosterResponseDTO
|
||||
* the response
|
||||
* @return a list of RosterExceptions
|
||||
*/
|
||||
private List<RosterException> getRosterExceptions(
|
||||
RosterResponseDTO rosterResponseDTO, int productivityFactor) {
|
||||
Map<String, List<RosterDTO>> map = getRosterExceptionPerWorker(rosterResponseDTO);
|
||||
|
||||
List<RosterException> rosterExceptions = new ArrayList<RosterException>();
|
||||
|
||||
for (Map.Entry<String, List<RosterDTO>> entry : map.entrySet()) {
|
||||
Worker worker = null;
|
||||
String workerCode = entry.getKey();
|
||||
try {
|
||||
worker = workerDAO.findUniqueByNif(workerCode);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
LOG.warn("Worker '" + workerCode + "' not found");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"Worker \"{0}\" not found",
|
||||
workerCode));
|
||||
}
|
||||
if (worker != null) {
|
||||
List<RosterDTO> list = entry.getValue();
|
||||
Collections.sort(list, new Comparator<RosterDTO>() {
|
||||
@Override
|
||||
public int compare(RosterDTO o1, RosterDTO o2) {
|
||||
return o1.getDate().compareTo(o2.getDate());
|
||||
}
|
||||
});
|
||||
RosterException re = new RosterException(worker,
|
||||
productivityFactor);
|
||||
re.addRosterExceptions(list);
|
||||
rosterExceptions.add(re);
|
||||
}
|
||||
}
|
||||
return rosterExceptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the roster on exceptions(absence) and creates a map with
|
||||
* <code>personsNetwork-name</name> as key
|
||||
* and list of <code>roster-exception</code> as value
|
||||
*
|
||||
* @param rosterResponseDTO
|
||||
* the response
|
||||
* @return person-roster exception map
|
||||
*/
|
||||
private Map<String, List<RosterDTO>> getRosterExceptionPerWorker(
|
||||
RosterResponseDTO rosterResponseDTO) {
|
||||
Map<String, List<RosterDTO>> rosterMap = new HashMap<String, List<RosterDTO>>();
|
||||
List<RosterDTO> rosterDTOs = rosterResponseDTO.getRosters();
|
||||
for (RosterDTO rosterDTO : rosterDTOs) {
|
||||
if (rosterDTO.getPrecence().equals(ABSENT)) {
|
||||
String personsNetWorkName = rosterDTO.getPersons().get(0)
|
||||
.getNetworkName();
|
||||
if (!rosterMap.containsKey(personsNetWorkName)) {
|
||||
rosterMap.put(personsNetWorkName,
|
||||
new ArrayList<RosterDTO>());
|
||||
}
|
||||
rosterMap.get(personsNetWorkName).add(rosterDTO);
|
||||
}
|
||||
}
|
||||
return rosterMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the workers calendar exception
|
||||
*
|
||||
* @param rosterExceptions
|
||||
* list of roster exceptions
|
||||
*/
|
||||
private void updateCalendarException(List<RosterException> rosterExceptions) {
|
||||
for (RosterException rosterException : rosterExceptions) {
|
||||
List<RosterExceptionItem> items = rosterException
|
||||
.getRosterExceptionItems();
|
||||
for (RosterExceptionItem item : items) {
|
||||
updateCalendarExceptionPerWorker(rosterException.getWorker(),
|
||||
item.getDate(), item.getExceptionType(),
|
||||
item.getEffortDuration());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* updates the calendar exception of the specified
|
||||
* <code>{@link Worker}</code> for the specified <code>date</code>
|
||||
*
|
||||
* @param worker
|
||||
* the worker
|
||||
* @param date
|
||||
* the date of the exception
|
||||
* @param exceptionName
|
||||
* the exception name
|
||||
* @param effortDuration
|
||||
* the exceptions effortDurtaion
|
||||
*/
|
||||
private void updateCalendarExceptionPerWorker(Worker worker,
|
||||
LocalDate date, String exceptionName, EffortDuration effortDuration) {
|
||||
CalendarExceptionType calendarExceptionType = getCalendarExceptionType(exceptionName);
|
||||
if (calendarExceptionType == null) {
|
||||
return;
|
||||
}
|
||||
ResourceCalendar resourceCalendar = (ResourceCalendar) worker
|
||||
.getCalendarOrDefault();
|
||||
CalendarException calendarExceptionDay = resourceCalendar
|
||||
.getExceptionDay(date);
|
||||
Capacity capacity = Capacity.create(effortDuration);
|
||||
if (calendarExceptionDay != null) {
|
||||
resourceCalendar.removeExceptionDay(calendarExceptionDay.getDate());
|
||||
}
|
||||
baseCalendarModel.initEdit(resourceCalendar);
|
||||
baseCalendarModel.updateException(calendarExceptionType, date, date,
|
||||
capacity);
|
||||
baseCalendarModel.confirmSave();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and returns the calendarExcptionType based on the specified
|
||||
* <code>name</code>
|
||||
*
|
||||
* If the specified parameter <code>name</code> contains the word
|
||||
* {@link ImportRosterFromTim#HOLIDAY}, the
|
||||
* <code>calendarExceptionType</code> assumed to be the
|
||||
* {@link PredefinedCalendarExceptionTypes#RESOURCE_HOLIDAY}, otherwise it
|
||||
* searches in {@link CalendarExceptionType} for unique
|
||||
* <code>calendarExceptionType</code>
|
||||
*
|
||||
* @param name
|
||||
* the exception calendar name
|
||||
*/
|
||||
private CalendarExceptionType getCalendarExceptionType(String name) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
LOG.error("Exception name should not be empty");
|
||||
synchronizationInfo
|
||||
.addFailedReason(_("Exception name should not be empty"));
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
String nameToSearch = name;
|
||||
if (nameToSearch.contains(HOLIDAY)) {
|
||||
nameToSearch = PredefinedCalendarExceptionTypes.RESOURCE_HOLIDAY
|
||||
.toString();
|
||||
} else if (nameToSearch.equals(BANK_HOLIDAY)) {
|
||||
nameToSearch = PredefinedCalendarExceptionTypes.BANK_HOLIDAY
|
||||
.toString();
|
||||
}
|
||||
return calendarExceptionTypeDAO.findUniqueByName(nameToSearch);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
LOG.error("Calendar exceptionType not found", e);
|
||||
synchronizationInfo
|
||||
.addFailedReason(_("Calendar exception day not found"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* creates and returns {@link RosterRequestDTO}
|
||||
*
|
||||
* @param nrDaysRosterFromTim
|
||||
* nr of days required to set the end date
|
||||
*/
|
||||
private RosterRequestDTO createRosterRequest(String department,
|
||||
int nrDaysRosterFromTim) {
|
||||
RosterDTO rosterDTO = createRoster(nrDaysRosterFromTim);
|
||||
|
||||
PeriodDTO periodeDTO = new PeriodDTO();
|
||||
periodeDTO.setStart(new org.joda.time.DateTime());
|
||||
periodeDTO.setEnd(new org.joda.time.DateTime()
|
||||
.plusDays(nrDaysRosterFromTim));
|
||||
List<PeriodDTO> periodDTOs = new ArrayList<PeriodDTO>();
|
||||
periodDTOs.add(periodeDTO);
|
||||
|
||||
DepartmentDTO departmentDTO = new DepartmentDTO();
|
||||
departmentDTO.setRef(department);
|
||||
|
||||
FilterDTO filterDTO = new FilterDTO();
|
||||
filterDTO.setPeriods(periodDTOs);
|
||||
filterDTO.setDepartment(departmentDTO);
|
||||
|
||||
rosterDTO.setFilter(filterDTO);
|
||||
|
||||
rosterDTO.setPersons(createEmptyPerson());
|
||||
|
||||
rosterDTO.setRosterCategories(createEmptyRosterCategory());
|
||||
|
||||
rosterDTO.setDepartment(departmentDTO);
|
||||
|
||||
rosterDTO.setPrecence(new String());
|
||||
rosterDTO.setPeriods(periodDTOs);
|
||||
|
||||
RosterRequestDTO exportRosterRequestDTO = new RosterRequestDTO();
|
||||
DataDTO<RosterDTO> dataDTO = new DataDTO<RosterDTO>();
|
||||
dataDTO.setData(rosterDTO);
|
||||
|
||||
exportRosterRequestDTO.setData(dataDTO);
|
||||
return exportRosterRequestDTO;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* creates and returns list of {@link PersonDTO} with empty
|
||||
* {@link PersonDTO}
|
||||
*
|
||||
* This is an indication to Tim server that it should include this Person
|
||||
* information in the RESPONSE message
|
||||
*/
|
||||
private List<PersonDTO> createEmptyPerson() {
|
||||
List<PersonDTO> personDTOs = new ArrayList<PersonDTO>();
|
||||
personDTOs.add(new PersonDTO());
|
||||
return personDTOs;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates and returns list of {@link RosterCategoryDTO} with empty
|
||||
* {@link RosterCategoryDTO}
|
||||
*
|
||||
* This is an indication to Tim server that it should include this
|
||||
* RosterCategory information in the RESPONSE message
|
||||
*/
|
||||
private List<RosterCategoryDTO> createEmptyRosterCategory() {
|
||||
List<RosterCategoryDTO> rosterCategorieDTOs = new ArrayList<RosterCategoryDTO>();
|
||||
RosterCategoryDTO rosterCategoryDTO = new RosterCategoryDTO();
|
||||
rosterCategoryDTO.setName(new String());
|
||||
rosterCategorieDTOs.add(rosterCategoryDTO);
|
||||
return rosterCategorieDTOs;
|
||||
}
|
||||
|
||||
/**
|
||||
* creates and returns {@link RosterDTO}
|
||||
*/
|
||||
private RosterDTO createRoster(int nrDaysRosterFromTim) {
|
||||
RosterDTO rosterDTO = new RosterDTO();
|
||||
rosterDTO.setStartDate(new LocalDate());
|
||||
rosterDTO.setEndDate(new LocalDate().plusDays(nrDaysRosterFromTim));
|
||||
rosterDTO.setResourcePlanning(false);
|
||||
rosterDTO.setDayPlanning(false);
|
||||
rosterDTO.setCalendar(false);
|
||||
rosterDTO.setNonPlaned(true);
|
||||
rosterDTO.setFullDay(false);
|
||||
rosterDTO.setConcept(false);
|
||||
return rosterDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SynchronizationInfo getSynchronizationInfo() {
|
||||
return synchronizationInfo;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* A job that import rosters from Tim SOAP server
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class ImportRosterFromTimJob extends QuartzJobBean {
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(ImportRosterFromTimJob.class);
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext context)
|
||||
throws JobExecutionException {
|
||||
ApplicationContext applicationContext = (ApplicationContext) context
|
||||
.getJobDetail().getJobDataMap().get("applicationContext");
|
||||
|
||||
IImportRosterFromTim importRosterFromTim = (IImportRosterFromTim) applicationContext
|
||||
.getBean("importRosterFromTim");
|
||||
|
||||
try {
|
||||
List<SynchronizationInfo> syncInfos = importRosterFromTim
|
||||
.importRosters();
|
||||
|
||||
LOG.info("Import scuccessful: "
|
||||
+ (syncInfos == null || syncInfos.isEmpty()));
|
||||
|
||||
} catch (ConnectorException e) {
|
||||
LOG.error("Import roster from Tim failed", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.net.MalformedURLException;
|
||||
|
|
@ -28,8 +30,11 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes;
|
||||
import org.libreplan.business.advance.entities.AdvanceMeasurement;
|
||||
|
|
@ -37,18 +42,26 @@ import org.libreplan.business.advance.entities.AdvanceType;
|
|||
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
|
||||
import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOrderElementException;
|
||||
import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalAdvanceException;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.entities.JiraConfiguration;
|
||||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.IOnTransaction;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
|
||||
import org.libreplan.business.orders.entities.HoursGroup;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.orders.entities.OrderLine;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.libreplan.business.workingday.EffortDuration;
|
||||
import org.libreplan.importers.jira.IssueDTO;
|
||||
import org.libreplan.importers.jira.StatusDTO;
|
||||
import org.libreplan.importers.jira.TimeTrackingDTO;
|
||||
import org.libreplan.importers.jira.WorkLogDTO;
|
||||
import org.libreplan.importers.jira.WorkLogItemDTO;
|
||||
import org.libreplan.web.orders.IOrderModel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
|
@ -64,17 +77,36 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchronizer {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(JiraOrderElementSynchronizer.class);
|
||||
|
||||
private SynchronizationInfo synchronizationInfo;
|
||||
|
||||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
private JiraSyncInfo jiraSyncInfo;
|
||||
@Autowired
|
||||
private IOrderSyncInfoDAO orderSyncInfoDAO;
|
||||
|
||||
@Autowired
|
||||
private IAdHocTransactionService adHocTransactionService;
|
||||
|
||||
@Autowired
|
||||
private IOrderModel orderModel;
|
||||
|
||||
@Autowired
|
||||
private IJiraTimesheetSynchronizer jiraTimesheetSynchronizer;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<String> getAllJiraLabels() {
|
||||
String jiraLabels = configurationDAO.getConfiguration()
|
||||
.getJiraConfiguration().getJiraLabels();
|
||||
public List<String> getAllJiraLabels() throws ConnectorException {
|
||||
Connector connector = getJiraConnector();
|
||||
if (connector == null) {
|
||||
throw new ConnectorException(_("JIRA connector not found"));
|
||||
}
|
||||
|
||||
String jiraLabels = connector.getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.JIRA_LABELS);
|
||||
|
||||
String labels;
|
||||
try {
|
||||
|
|
@ -88,13 +120,39 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
|
|||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<IssueDTO> getJiraIssues(String label) {
|
||||
JiraConfiguration jiraConfiguration = configurationDAO
|
||||
.getConfiguration().getJiraConfiguration();
|
||||
public List<IssueDTO> getJiraIssues(String label) throws ConnectorException {
|
||||
|
||||
String url = jiraConfiguration.getJiraUrl();
|
||||
String username = jiraConfiguration.getJiraUserId();
|
||||
String password = jiraConfiguration.getJiraPassword();
|
||||
Connector connector = getJiraConnector();
|
||||
if (connector == null) {
|
||||
throw new ConnectorException(_("JIRA connector not found"));
|
||||
}
|
||||
|
||||
if (!connector.areConnectionValuesValid()) {
|
||||
throw new ConnectorException(
|
||||
_("Connection values of JIRA connector are invalid"));
|
||||
}
|
||||
|
||||
return getJiraIssues(label, connector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all jira issues for the specified <code>label</code>
|
||||
*
|
||||
* @param label
|
||||
* the search criteria
|
||||
* @param connector
|
||||
* where to read the configuration parameters
|
||||
* @return a list of {@link IssueDTO}
|
||||
*/
|
||||
private List<IssueDTO> getJiraIssues(String label, Connector connector) {
|
||||
Map<String, String> properties = connector.getPropertiesAsMap();
|
||||
String url = properties.get(PredefinedConnectorProperties.SERVER_URL);
|
||||
|
||||
String username = properties
|
||||
.get(PredefinedConnectorProperties.USERNAME);
|
||||
|
||||
String password = properties
|
||||
.get(PredefinedConnectorProperties.PASSWORD);
|
||||
|
||||
String path = JiraRESTClient.PATH_SEARCH;
|
||||
String query = "labels=" + label;
|
||||
|
|
@ -109,17 +167,20 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
|
|||
@Transactional(readOnly = true)
|
||||
public void syncOrderElementsWithJiraIssues(List<IssueDTO> issues, Order order) {
|
||||
|
||||
jiraSyncInfo = new JiraSyncInfo();
|
||||
synchronizationInfo = new SynchronizationInfo(_(
|
||||
"Synchronization order {0}", order.getName()));
|
||||
|
||||
for (IssueDTO issue : issues) {
|
||||
String code = JiraConfiguration.CODE_PREFIX + order.getCode() + "-"
|
||||
String code = PredefinedConnectorProperties.JIRA_CODE_PREFIX
|
||||
+ order.getCode() + "-"
|
||||
+ issue.getKey();
|
||||
String name = issue.getFields().getSummary();
|
||||
|
||||
OrderLine orderLine = syncOrderLine(order, code, name);
|
||||
if (orderLine == null) {
|
||||
jiraSyncInfo.addSyncFailedReason("Order-element for '"
|
||||
+ issue.getKey() + "' issue not found");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"Order-element for \"{0}\" issue not found",
|
||||
issue.getKey()));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -129,8 +190,9 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
|
|||
.getTimetracking(), loggedHours);
|
||||
|
||||
if (estimatedHours.isZero()) {
|
||||
jiraSyncInfo.addSyncFailedReason("Estimated time for '"
|
||||
+ issue.getKey() + "' issue is 0");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"Estimated time for \"{0}\" issue is 0",
|
||||
issue.getKey()));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -217,15 +279,16 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
|
|||
WorkLogDTO workLog = issue.getFields().getWorklog();
|
||||
|
||||
if (workLog == null) {
|
||||
jiraSyncInfo.addSyncFailedReason("No worklogs found for '"
|
||||
+ issue.getKey() + "' issue");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"No worklogs found for \"{0}\" issue", issue.getKey()));
|
||||
return;
|
||||
}
|
||||
|
||||
List<WorkLogItemDTO> workLogItems = workLog.getWorklogs();
|
||||
if (workLogItems.isEmpty()) {
|
||||
jiraSyncInfo.addSyncFailedReason("No worklog items found for '"
|
||||
+ issue.getKey() + "' issue");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"No worklog items found for \"{0}\" issue",
|
||||
issue.getKey()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -334,9 +397,10 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
|
|||
} catch (DuplicateAdvanceAssignmentForOrderElementException e) {
|
||||
// This could happen if a parent or child of the current
|
||||
// OrderElement has an advance of type PERCENTAGE
|
||||
jiraSyncInfo
|
||||
.addSyncFailedReason("Duplicate value AdvanceAssignment for order element of '"
|
||||
+ orderElement.getCode() + "'");
|
||||
synchronizationInfo
|
||||
.addFailedReason(_(
|
||||
"Duplicate value AdvanceAssignment for order element of \"{0}\"",
|
||||
orderElement.getCode()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -393,8 +457,109 @@ public class JiraOrderElementSynchronizer implements IJiraOrderElementSynchroniz
|
|||
}
|
||||
|
||||
@Override
|
||||
public JiraSyncInfo getJiraSyncInfo() {
|
||||
return jiraSyncInfo;
|
||||
public SynchronizationInfo getSynchronizationInfo() {
|
||||
return synchronizationInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns JIRA connector
|
||||
*/
|
||||
private Connector getJiraConnector() {
|
||||
return connectorDAO.findUniqueByName(PredefinedConnectors.JIRA
|
||||
.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveSyncInfo(final String key, final Order order) {
|
||||
adHocTransactionService
|
||||
.runOnAnotherTransaction(new IOnTransaction<Void>() {
|
||||
@Override
|
||||
public Void execute() {
|
||||
OrderSyncInfo orderSyncInfo = orderSyncInfoDAO
|
||||
.findByKeyOrderAndConnectorName(key, order,
|
||||
PredefinedConnectors.JIRA.getName());
|
||||
if (orderSyncInfo == null) {
|
||||
orderSyncInfo = OrderSyncInfo.create(key, order,
|
||||
PredefinedConnectors.JIRA.getName());
|
||||
}
|
||||
orderSyncInfo.setLastSyncDate(new Date());
|
||||
orderSyncInfoDAO.save(orderSyncInfo);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public OrderSyncInfo getOrderLastSyncInfo(Order order) {
|
||||
return orderSyncInfoDAO.findLastSynchronizedInfoByOrderAndConnectorName(
|
||||
order, PredefinedConnectors.JIRA.getName());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public List<SynchronizationInfo> syncOrderElementsWithJiraIssues() throws ConnectorException {
|
||||
Connector connector = getJiraConnector();
|
||||
if (connector == null) {
|
||||
throw new ConnectorException(_("JIRA connector not found"));
|
||||
}
|
||||
if (!connector.areConnectionValuesValid()) {
|
||||
throw new ConnectorException(
|
||||
_("Connection values of JIRA connector are invalid"));
|
||||
}
|
||||
|
||||
List<OrderSyncInfo> orderSyncInfos = orderSyncInfoDAO
|
||||
.findByConnectorName(PredefinedConnectors.JIRA.getName());
|
||||
|
||||
synchronizationInfo = new SynchronizationInfo(_("Synchronization"));
|
||||
|
||||
List<SynchronizationInfo> syncInfos = new ArrayList<SynchronizationInfo>();
|
||||
|
||||
if (orderSyncInfos == null || orderSyncInfos.isEmpty()) {
|
||||
LOG.warn("No items found in 'OrderSyncInfo' to synchronize with JIRA issues");
|
||||
synchronizationInfo
|
||||
.addFailedReason(_("No items found in 'OrderSyncInfo' to synchronize with JIRA issues"));
|
||||
syncInfos.add(synchronizationInfo);
|
||||
return syncInfos;
|
||||
}
|
||||
|
||||
for (OrderSyncInfo orderSyncInfo : orderSyncInfos) {
|
||||
Order order = orderSyncInfo.getOrder();
|
||||
LOG.info("Synchronizing '" + order.getName() + "'");
|
||||
synchronizationInfo = new SynchronizationInfo(_(
|
||||
"Synchronization order {0}", order.getName()));
|
||||
|
||||
List<IssueDTO> issueDTOs = getJiraIssues(orderSyncInfo.getKey(),
|
||||
connector);
|
||||
if (issueDTOs == null || issueDTOs.isEmpty()) {
|
||||
LOG.warn("No JIRA issues found for '" + orderSyncInfo.getKey()
|
||||
+ "'");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"No JIRA issues found for key {0}",
|
||||
orderSyncInfo.getKey()));
|
||||
syncInfos.add(synchronizationInfo);
|
||||
continue;
|
||||
}
|
||||
|
||||
orderModel.initEdit(order, null);
|
||||
syncOrderElementsWithJiraIssues(issueDTOs, order);
|
||||
if (!synchronizationInfo.isSuccessful()) {
|
||||
syncInfos.add(synchronizationInfo);
|
||||
continue;
|
||||
}
|
||||
orderModel.save(false);
|
||||
|
||||
saveSyncInfo(orderSyncInfo.getKey(), order);
|
||||
|
||||
jiraTimesheetSynchronizer.syncJiraTimesheetWithJiraIssues(
|
||||
issueDTOs, order);
|
||||
if (!synchronizationInfo.isSuccessful()) {
|
||||
syncInfos.add(synchronizationInfo);
|
||||
}
|
||||
}
|
||||
return syncInfos;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
|
||||
/**
|
||||
* A job that synchronizes order elements and time sheets with JIRA issues
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JiraOrderElementSynchronizerJob extends QuartzJobBean {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(JiraOrderElementSynchronizerJob.class);
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext context)
|
||||
throws JobExecutionException {
|
||||
ApplicationContext applicationContext = (ApplicationContext) context
|
||||
.getJobDetail().getJobDataMap().get("applicationContext");
|
||||
|
||||
IJiraOrderElementSynchronizer jiraOrderElementSynchronizer = (IJiraOrderElementSynchronizer) applicationContext
|
||||
.getBean("jiraOrderElementSynchronizer");
|
||||
|
||||
try {
|
||||
List<SynchronizationInfo> syncInfos = jiraOrderElementSynchronizer
|
||||
.syncOrderElementsWithJiraIssues();
|
||||
|
||||
LOG.info("Synchronization scuccessful: "
|
||||
+ (syncInfos == null || syncInfos.isEmpty()));
|
||||
|
||||
} catch (ConnectorException e) {
|
||||
LOG.error("Synchronize order elements failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,24 +19,31 @@
|
|||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.NonUniqueResultException;
|
||||
import org.libreplan.business.common.IAdHocTransactionService;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.entities.JiraConfiguration;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO;
|
||||
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
|
||||
import org.libreplan.business.orders.daos.IOrderSyncInfoDAO;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.libreplan.business.resources.daos.IWorkerDAO;
|
||||
import org.libreplan.business.resources.entities.Resource;
|
||||
import org.libreplan.business.resources.entities.Worker;
|
||||
import org.libreplan.business.workingday.EffortDuration;
|
||||
import org.libreplan.business.workreports.daos.IWorkReportDAO;
|
||||
import org.libreplan.business.workreports.daos.IWorkReportLineDAO;
|
||||
import org.libreplan.business.workreports.daos.IWorkReportTypeDAO;
|
||||
import org.libreplan.business.workreports.entities.PredefinedWorkReportTypes;
|
||||
import org.libreplan.business.workreports.entities.WorkReport;
|
||||
|
|
@ -63,7 +70,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
|
||||
|
||||
private JiraSyncInfo jiraSyncInfo;
|
||||
private SynchronizationInfo synchronizationInfo;
|
||||
|
||||
private List<Worker> workers;
|
||||
|
||||
|
|
@ -80,9 +87,6 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
|
|||
@Autowired
|
||||
private IWorkReportDAO workReportDAO;
|
||||
|
||||
@Autowired
|
||||
private IWorkReportLineDAO workReportLineDAO;
|
||||
|
||||
@Autowired
|
||||
private IWorkReportModel workReportModel;
|
||||
|
||||
|
|
@ -90,50 +94,69 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
|
|||
private ITypeOfWorkHoursDAO typeOfWorkHoursDAO;
|
||||
|
||||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Autowired
|
||||
private IOrderSyncInfoDAO orderSyncInfoDAO;
|
||||
|
||||
@Autowired
|
||||
private IAdHocTransactionService adHocTransactionService;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order) {
|
||||
jiraSyncInfo = new JiraSyncInfo();
|
||||
public void syncJiraTimesheetWithJiraIssues(List<IssueDTO> issues, Order order) throws ConnectorException {
|
||||
synchronizationInfo = new SynchronizationInfo(_("Synchronization"));
|
||||
|
||||
workReportType = getJiraTimesheetsWorkReportType();
|
||||
typeOfWorkHours = getTypeOfWorkHours();
|
||||
|
||||
workers = getWorkers();
|
||||
if (workers == null && workers.isEmpty()) {
|
||||
jiraSyncInfo.addSyncFailedReason("No workers found");
|
||||
synchronizationInfo.addFailedReason(_("No workers found"));
|
||||
return;
|
||||
}
|
||||
|
||||
String code = order.getCode() + "-" + order.getImportedLabel();
|
||||
OrderSyncInfo orderSyncInfo = orderSyncInfoDAO
|
||||
.findLastSynchronizedInfoByOrderAndConnectorName(order,
|
||||
PredefinedConnectors.JIRA.getName());
|
||||
if (orderSyncInfo == null) {
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"Order \"{0}\" not found. Order probalbly not synchronized",
|
||||
order.getName()));
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isBlank(orderSyncInfo.getKey())) {
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"Key for Order \"{0}\" is empty",
|
||||
order.getName()));
|
||||
return;
|
||||
}
|
||||
|
||||
String code = order.getCode() + "-" + orderSyncInfo.getKey();
|
||||
|
||||
WorkReport workReport = updateOrCreateWorkReport(code);
|
||||
|
||||
for (IssueDTO issue : issues) {
|
||||
WorkLogDTO worklog = issue.getFields().getWorklog();
|
||||
if (worklog == null) {
|
||||
jiraSyncInfo.addSyncFailedReason("No worklogs found for '"
|
||||
+ issue.getKey() + "'");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"No worklogs found for \"{0}\" key", issue.getKey()));
|
||||
} else {
|
||||
List<WorkLogItemDTO> workLogItems = worklog.getWorklogs();
|
||||
if (workLogItems == null || workLogItems.isEmpty()) {
|
||||
jiraSyncInfo
|
||||
.addSyncFailedReason("No worklog items found for '"
|
||||
+ issue.getKey() + "' issue");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"No worklog items found for \"{0}\" issue",
|
||||
issue.getKey()));
|
||||
} else {
|
||||
|
||||
String codeOrderElement = JiraConfiguration.CODE_PREFIX
|
||||
String codeOrderElement = PredefinedConnectorProperties.JIRA_CODE_PREFIX
|
||||
+ order.getCode() + "-" + issue.getKey();
|
||||
|
||||
OrderElement orderElement = order.getOrderElement(codeOrderElement);
|
||||
|
||||
if (orderElement == null) {
|
||||
jiraSyncInfo.addSyncFailedReason("Order element("
|
||||
+ code + ") not found");
|
||||
synchronizationInfo.addFailedReason(_(
|
||||
"Order element \"{0}\" not found", code));
|
||||
} else {
|
||||
updateOrCreateWorkReportLineAndAddToWorkReport(workReport, orderElement,
|
||||
workLogItems);
|
||||
|
|
@ -291,10 +314,31 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
|
|||
* Returns {@link TypeOfWorkHours} configured for JIRA connector
|
||||
*
|
||||
* @return TypeOfWorkHours for JIRA connector
|
||||
* @throws ConnectorException
|
||||
*/
|
||||
private TypeOfWorkHours getTypeOfWorkHours() {
|
||||
return configurationDAO.getConfiguration().getJiraConfiguration()
|
||||
.getJiraConnectorTypeOfWorkHours();
|
||||
private TypeOfWorkHours getTypeOfWorkHours() throws ConnectorException {
|
||||
Connector connector = connectorDAO
|
||||
.findUniqueByName(PredefinedConnectors.JIRA.getName());
|
||||
if (connector == null) {
|
||||
throw new ConnectorException(_("JIRA connector not found"));
|
||||
}
|
||||
|
||||
TypeOfWorkHours typeOfWorkHours;
|
||||
String name = connector.getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.JIRA_HOURS_TYPE);
|
||||
|
||||
if (StringUtils.isBlank(name)) {
|
||||
throw new ConnectorException(
|
||||
_("Hours type should not be empty to synchronine timesheets"));
|
||||
}
|
||||
|
||||
try {
|
||||
typeOfWorkHours = typeOfWorkHoursDAO.findUniqueByName(name);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return typeOfWorkHours;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -336,13 +380,13 @@ public class JiraTimesheetSynchronizer implements IJiraTimesheetSynchronizer {
|
|||
return worker;
|
||||
}
|
||||
}
|
||||
jiraSyncInfo.addSyncFailedReason("Worker('" + nif + "') not found");
|
||||
synchronizationInfo.addFailedReason(_("Worker \"{0}\" not found", nif));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public JiraSyncInfo getJiraSyncInfo() {
|
||||
return jiraSyncInfo;
|
||||
public SynchronizationInfo getSynchronizationInfo() {
|
||||
return synchronizationInfo;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.resources.entities.Worker;
|
||||
import org.libreplan.business.workingday.EffortDuration;
|
||||
import org.libreplan.business.workingday.IntraDayDate.PartialDay;
|
||||
import org.libreplan.importers.tim.RosterDTO;
|
||||
|
||||
/**
|
||||
* Class to convert the Roster response DTO to the <code>RosterException<code>
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class RosterException {
|
||||
private Worker worker;
|
||||
private int productivityFactor;
|
||||
|
||||
List<RosterExceptionItem> rosterExceptionItems = new ArrayList<RosterExceptionItem>();
|
||||
|
||||
public RosterException(Worker worker, int productivityFactor) {
|
||||
this.worker = worker;
|
||||
this.productivityFactor = productivityFactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the rosters and add the exceptions to
|
||||
* <code>rosterExceptionItems</code>
|
||||
*
|
||||
* @param rosterDTOs
|
||||
* list of rosterDTO
|
||||
*/
|
||||
public void addRosterExceptions(List<RosterDTO> rosterDTOs) {
|
||||
Map<LocalDate, List<RosterDTO>> mapDateRosterDTO = new TreeMap<LocalDate, List<RosterDTO>>();
|
||||
|
||||
for (RosterDTO rosterDTO : rosterDTOs) {
|
||||
if (!mapDateRosterDTO.containsKey(rosterDTO.getDate())) {
|
||||
mapDateRosterDTO.put(rosterDTO.getDate(), new ArrayList<RosterDTO>());
|
||||
}
|
||||
mapDateRosterDTO.get(rosterDTO.getDate()).add(rosterDTO);
|
||||
|
||||
}
|
||||
|
||||
for (Map.Entry<LocalDate, List<RosterDTO>> entry : mapDateRosterDTO
|
||||
.entrySet()) {
|
||||
RosterExceptionItem item = new RosterExceptionItem(entry.getKey());
|
||||
updateExceptionTypeAndEffort(item, entry.getValue());
|
||||
rosterExceptionItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the <code>exceptionType</code> and <code>effortDuration</code>
|
||||
*
|
||||
* In Tim you can divide your exception day in different
|
||||
* <code>exceptionType</code>, for example on Monday:
|
||||
* <ul>
|
||||
* <li>4 hours RESOURCE_HOLIDAY</li>
|
||||
* <li>2 hours STRIKE</li>
|
||||
* <li>2 hours BANK_HOLIDAY</li>
|
||||
* </ul>
|
||||
*
|
||||
* But Libreplan allows only one <code>exceptionType</code> per day.
|
||||
*
|
||||
* In order to store different <code>exceptionTypes</code> per day as one
|
||||
* <code>exceptionType</code>, this method gets the
|
||||
* <code>exceptionType</code> from the <code>rosterDTO</code> with the
|
||||
* highest duration, in this example RESOURCE_HOLIDAY as a valid exception
|
||||
* type, but the total duration is the sum of all these exception types
|
||||
*
|
||||
* Again in Tim this total duration means that the worker is on holiday for
|
||||
* that total duration, but Libreplan does the opposite. In Libreplan, the
|
||||
* total duration in this case means that the worker is not on holiday. If
|
||||
* he is then the total duration should be Zero. And this method does this
|
||||
* translation
|
||||
*
|
||||
* @param rosterExceptionItem
|
||||
* the rosterException item
|
||||
* @param rosterDTOs
|
||||
* list of rosterDTO
|
||||
*/
|
||||
private void updateExceptionTypeAndEffort(
|
||||
RosterExceptionItem rosterExceptionItem, List<RosterDTO> rosterDTOs) {
|
||||
EffortDuration max = EffortDuration.zero();
|
||||
EffortDuration sum = EffortDuration.zero();
|
||||
String rosterCatName = rosterDTOs.get(0).getRosterCategories().get(0)
|
||||
.getName();
|
||||
for (RosterDTO rosterDTO : rosterDTOs) {
|
||||
EffortDuration duration = EffortDuration
|
||||
.parseFromFormattedString(rosterDTO.getDuration());
|
||||
if (duration.compareTo(max) > 0) {
|
||||
rosterCatName = rosterDTO.getRosterCategories().get(0)
|
||||
.getName();
|
||||
}
|
||||
max = EffortDuration.max(max, duration);
|
||||
sum = EffortDuration.sum(sum, duration);
|
||||
|
||||
}
|
||||
EffortDuration exceptionTime = EffortDuration.zero();
|
||||
|
||||
EffortDuration workableTime = worker.getCalendar().getCapacityOn(
|
||||
PartialDay.wholeDay(rosterExceptionItem.getDate()));
|
||||
|
||||
// Convert the total duration from Tim to the productivity time as is
|
||||
// configured in resource calendar
|
||||
EffortDuration productivityTime = sum.multiplyBy(productivityFactor)
|
||||
.divideBy(100);
|
||||
|
||||
// Calculate the exception time
|
||||
if (workableTime.compareTo(productivityTime) >= 0) {
|
||||
exceptionTime = workableTime.minus(productivityTime);
|
||||
}
|
||||
|
||||
rosterExceptionItem.setExceptionType(rosterCatName);
|
||||
rosterExceptionItem.setEffortDuration(exceptionTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns {@link Worker}
|
||||
*/
|
||||
public Worker getWorker() {
|
||||
return worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns list of {@link RosterExceptionItem}
|
||||
*/
|
||||
public List<RosterExceptionItem> getRosterExceptionItems() {
|
||||
return rosterExceptionItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* class representing RosterExceptionItem
|
||||
*/
|
||||
public class RosterExceptionItem {
|
||||
private LocalDate date;
|
||||
private String exceptionType;
|
||||
private EffortDuration effortDuration;
|
||||
|
||||
public RosterExceptionItem(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public String getExceptionType() {
|
||||
return exceptionType;
|
||||
}
|
||||
|
||||
public void setExceptionType(String exceptionType) {
|
||||
this.exceptionType = exceptionType;
|
||||
}
|
||||
|
||||
public EffortDuration getEffortDuration() {
|
||||
return effortDuration;
|
||||
}
|
||||
|
||||
public void setEffortDuration(EffortDuration effortDuration) {
|
||||
this.effortDuration = effortDuration;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
|
||||
/**
|
||||
* Holds information about the scheduler, The information comes partly form
|
||||
* {@link JobSchedulerConfiguration} and partly form {@link SchedulerManager}
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class SchedulerInfo {
|
||||
|
||||
private JobSchedulerConfiguration jobSchedulerConfiguration;
|
||||
private String nextFireTime;
|
||||
|
||||
public SchedulerInfo() {
|
||||
|
||||
}
|
||||
|
||||
public SchedulerInfo(JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
this.jobSchedulerConfiguration = jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
public String getNextFireTime() {
|
||||
return nextFireTime;
|
||||
}
|
||||
|
||||
public void setNextFireTime(String nextFireTime) {
|
||||
this.nextFireTime = nextFireTime;
|
||||
}
|
||||
|
||||
public JobSchedulerConfiguration getJobSchedulerConfiguration() {
|
||||
return jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
public void setJobSchedulerConfiguration(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
this.jobSchedulerConfiguration = jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.JobClassNameEnum;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.quartz.CronExpression;
|
||||
import org.quartz.CronTrigger;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.scheduling.quartz.CronTriggerBean;
|
||||
import org.springframework.scheduling.quartz.JobDetailBean;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Implementation of scheduler manager
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class SchedulerManager implements ISchedulerManager {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(SchedulerManager.class);
|
||||
|
||||
@Autowired
|
||||
private Scheduler scheduler;
|
||||
|
||||
@Autowired
|
||||
private IJobSchedulerConfigurationDAO jobSchedulerConfigurationDAO;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
|
||||
/**
|
||||
* suffix for trigger -group and -name
|
||||
*/
|
||||
private static final String TRIGGER_SUFFIX = "-TRIGGER";
|
||||
|
||||
public Scheduler getScheduler() {
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
public void setScheduler(Scheduler scheduler) {
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scheduleJobs() {
|
||||
List<JobSchedulerConfiguration> jobSchedulerConfigurations = jobSchedulerConfigurationDAO
|
||||
.getAll();
|
||||
for (JobSchedulerConfiguration conf : jobSchedulerConfigurations) {
|
||||
try {
|
||||
scheduleOrUnscheduleJob(conf);
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("Unable to schedule", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public void scheduleOrUnscheduleJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException {
|
||||
|
||||
if (hasConnector(jobSchedulerConfiguration.getConnectorName())) {
|
||||
if (isConnectorActivated(jobSchedulerConfiguration
|
||||
.getConnectorName())) {
|
||||
if (jobSchedulerConfiguration.isSchedule()) {
|
||||
scheduleNewJob(jobSchedulerConfiguration);
|
||||
return;
|
||||
}
|
||||
}
|
||||
deleteJob(jobSchedulerConfiguration);
|
||||
return;
|
||||
}
|
||||
if (!jobSchedulerConfiguration.isSchedule()) {
|
||||
deleteJob(jobSchedulerConfiguration);
|
||||
return;
|
||||
}
|
||||
scheduleNewJob(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if {@link JobSchedulerConfiguration} has a connector
|
||||
*
|
||||
* @param connectorName
|
||||
* the connector to check for
|
||||
* @return true if connector is not null or empty
|
||||
*/
|
||||
private boolean hasConnector(String connectorName) {
|
||||
return !StringUtils.isBlank(connectorName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the specified <code>{@link Connector}</code> is activated
|
||||
*
|
||||
* @param connectorName
|
||||
* the connector to check for activated
|
||||
* @return true if activated
|
||||
*/
|
||||
private boolean isConnectorActivated(String connectorName) {
|
||||
Connector connector = connectorDAO.findUniqueByName(connectorName);
|
||||
if (connector == null) {
|
||||
return false;
|
||||
}
|
||||
return connector.isActivated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteJob(JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException {
|
||||
String triggerName = jobSchedulerConfiguration.getJobName()
|
||||
+ TRIGGER_SUFFIX;
|
||||
String triggerGroup = jobSchedulerConfiguration.getJobGroup()
|
||||
+ TRIGGER_SUFFIX;
|
||||
|
||||
CronTriggerBean trigger = getTriggerBean(triggerName, triggerGroup);
|
||||
if (trigger == null) {
|
||||
LOG.warn("Trigger not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJobCurrentlyExecuting(triggerName, triggerGroup)) {
|
||||
LOG.warn("Job is currently executing...");
|
||||
return;
|
||||
}
|
||||
|
||||
// deleteJob doesn't work using unscheduleJob
|
||||
this.scheduler.unscheduleJob(trigger.getName(), trigger.getGroup());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if job is currently running for the specified
|
||||
* <code>triggerName</code> and <code>triggerGroup</code>
|
||||
*
|
||||
* @param triggerName
|
||||
* the triggerName
|
||||
* @param triggerGroup
|
||||
* the triggerGroup
|
||||
* @return true if job is currently running, otherwise false
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private boolean isJobCurrentlyExecuting(String triggerName,
|
||||
String triggerGroup) {
|
||||
try {
|
||||
List<JobExecutionContext> currentExecutingJobs = this.scheduler
|
||||
.getCurrentlyExecutingJobs();
|
||||
for (JobExecutionContext jobExecutionContext : currentExecutingJobs) {
|
||||
String name = jobExecutionContext.getTrigger().getName();
|
||||
String group = jobExecutionContext.getTrigger().getGroup();
|
||||
if (triggerName.equals(name) && triggerGroup.equals(group)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("Unable to get currently executing jobs", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link CronTriggerBean} and {@link JobDetailBean} based on the
|
||||
* specified <code>{@link JobSchedulerConfiguration}</code>. First delete
|
||||
* job if exist and then schedule it
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* where to reade jobs to be scheduled
|
||||
* @throws SchedulerException
|
||||
* if unable to delete and/or schedule job
|
||||
*/
|
||||
private void scheduleNewJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) throws SchedulerException {
|
||||
CronTriggerBean cronTriggerBean = createCronTriggerBean(jobSchedulerConfiguration);
|
||||
if (cronTriggerBean == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
JobDetailBean jobDetailBean = createJobDetailBean(jobSchedulerConfiguration);
|
||||
if (jobDetailBean == null) {
|
||||
return;
|
||||
}
|
||||
deleteJob(jobSchedulerConfiguration);
|
||||
this.scheduler.scheduleJob(jobDetailBean, cronTriggerBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link CronTriggerBean} from the specified
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration to create <code>CronTriggerBean</>
|
||||
* @return the created <code>CronTriggerBean</code> or null if unable to
|
||||
* create it
|
||||
*/
|
||||
private CronTriggerBean createCronTriggerBean(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
CronTriggerBean cronTriggerBean = new CronTriggerBean();
|
||||
cronTriggerBean.setName(jobSchedulerConfiguration.getJobName() + TRIGGER_SUFFIX);
|
||||
cronTriggerBean.setGroup(jobSchedulerConfiguration.getJobGroup()
|
||||
+ TRIGGER_SUFFIX);
|
||||
|
||||
try {
|
||||
cronTriggerBean.setCronExpression(new CronExpression(
|
||||
jobSchedulerConfiguration.getCronExpression()));
|
||||
cronTriggerBean.setJobName(jobSchedulerConfiguration.getJobName());
|
||||
cronTriggerBean
|
||||
.setJobGroup(jobSchedulerConfiguration.getJobGroup());
|
||||
return cronTriggerBean;
|
||||
} catch (ParseException e) {
|
||||
LOG.error("Unable to parse cron expression", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates {@link JobDetailBean} from the specified
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration to create <code>JobDetailBean</>
|
||||
* @return the created <code>JobDetailBean</code> or null if unable to it
|
||||
*/
|
||||
private JobDetailBean createJobDetailBean(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
JobDetailBean jobDetailBean = new JobDetailBean();
|
||||
|
||||
Class<?> jobClass = getJobClass(jobSchedulerConfiguration
|
||||
.getJobClassName());
|
||||
if (jobClass == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
jobDetailBean.setName(jobSchedulerConfiguration.getJobName());
|
||||
jobDetailBean.setGroup(jobSchedulerConfiguration.getJobGroup());
|
||||
jobDetailBean.setJobClass(jobClass);
|
||||
|
||||
Map<String, Object> jobDataAsMap = new HashMap<String, Object>();
|
||||
jobDataAsMap.put("applicationContext", applicationContext);
|
||||
jobDetailBean.setJobDataAsMap(jobDataAsMap);
|
||||
return jobDetailBean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* returns jobClass based on <code>jobClassName</code> parameter
|
||||
*
|
||||
* @param jobClassName
|
||||
* job className
|
||||
*/
|
||||
private Class<?> getJobClass(JobClassNameEnum jobClassName) {
|
||||
try {
|
||||
return Class.forName(jobClassName.getPackageName() + "."
|
||||
+ jobClassName.getName());
|
||||
} catch (ClassNotFoundException e) {
|
||||
LOG.error("Unable to get class object '" + jobClassName + "'", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNextFireTime(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
try {
|
||||
CronTrigger trigger = (CronTrigger) this.scheduler.getTrigger(
|
||||
jobSchedulerConfiguration.getJobName() + TRIGGER_SUFFIX,
|
||||
jobSchedulerConfiguration.getJobGroup()
|
||||
+ TRIGGER_SUFFIX);
|
||||
if (trigger != null) {
|
||||
return trigger.getNextFireTime().toString();
|
||||
}
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("unable to get the trigger", e);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the {@link CronTriggerBean} for the specified
|
||||
* <code>triggerName</code> and <code>tirggerGroup</code>
|
||||
*
|
||||
* @param triggerName
|
||||
* the trigger name
|
||||
* @param triggerGroup
|
||||
* the trigger group
|
||||
* @return CronTriggerBean if found, otherwise null
|
||||
*/
|
||||
private CronTriggerBean getTriggerBean(String triggerName,
|
||||
String triggerGroup) {
|
||||
try {
|
||||
return (CronTriggerBean) this.scheduler.getTrigger(triggerName,
|
||||
triggerGroup);
|
||||
} catch (SchedulerException e) {
|
||||
LOG.error("Unable to get job trigger", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,38 +24,57 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Keeps track the synchronization info.
|
||||
* Keeps track the success/failure of synchronization process
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JiraSyncInfo {
|
||||
|
||||
private List<String> syncFailedReasons = new ArrayList<String>();
|
||||
public class SynchronizationInfo {
|
||||
|
||||
/**
|
||||
* Add the specified <code>reason</code> to syncFailedReasons list
|
||||
*
|
||||
* @param reason
|
||||
* reason why synchronizition failed
|
||||
* The action, a unique key for example synchronization, import or export
|
||||
* etc action
|
||||
*/
|
||||
public void addSyncFailedReason(String reason) {
|
||||
syncFailedReasons.add(reason);
|
||||
private String action;
|
||||
|
||||
/**
|
||||
* Holds failed reasons
|
||||
*/
|
||||
private List<String> failedReasons = new ArrayList<String>();
|
||||
|
||||
public SynchronizationInfo(String action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is synchronization successful
|
||||
*
|
||||
* @return
|
||||
* Returns the action
|
||||
*/
|
||||
public boolean isSyncSuccessful() {
|
||||
return syncFailedReasons.isEmpty();
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified <code>reason</code> to <code>failedReasons<code> list
|
||||
*
|
||||
* @param reason
|
||||
* reason why synchronization is failed
|
||||
*/
|
||||
public void addFailedReason(String reason) {
|
||||
failedReasons.add(reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is synchronization succeeded
|
||||
*
|
||||
* @return true if <code>failedReasons</code> is empty
|
||||
*/
|
||||
public boolean isSuccessful() {
|
||||
return failedReasons.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns reasons why synchronization is failed
|
||||
*/
|
||||
public List<String> getSyncFailedReasons() {
|
||||
return Collections.unmodifiableList(syncFailedReasons);
|
||||
public List<String> getFailedReasons() {
|
||||
return Collections.unmodifiableList(failedReasons);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.soap.MessageFactory;
|
||||
import javax.xml.soap.Node;
|
||||
import javax.xml.soap.SOAPBody;
|
||||
import javax.xml.soap.SOAPConnection;
|
||||
import javax.xml.soap.SOAPConnectionFactory;
|
||||
import javax.xml.soap.SOAPEnvelope;
|
||||
import javax.xml.soap.SOAPException;
|
||||
import javax.xml.soap.SOAPMessage;
|
||||
import javax.xml.soap.SOAPPart;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.cxf.common.util.Base64Utility;
|
||||
import org.libreplan.importers.tim.RosterResponseDTO;
|
||||
|
||||
/**
|
||||
* Client to interact with Tim SOAP server.
|
||||
*
|
||||
* This client creates SOAP message, makes connection to the SOAP server and
|
||||
* sends the request. It is also the task of this client to convert the
|
||||
* response(xml document) to java objects
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class TimSoapClient {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(TimSoapClient.class);
|
||||
|
||||
/**
|
||||
* Creates request message to be send to the SOAP server
|
||||
*
|
||||
* @param clazz
|
||||
* object to be marshaled
|
||||
* @param userName
|
||||
* the user name
|
||||
* @param password
|
||||
* the password
|
||||
* @return the created soap message
|
||||
* @throws SOAPException
|
||||
* if unable to create message or envelope
|
||||
* @throws JAXBException
|
||||
* if unable to marshal the clazz
|
||||
*/
|
||||
private static <T> SOAPMessage createRequest(T clazz, String userName,
|
||||
String password) throws SOAPException, JAXBException {
|
||||
|
||||
SOAPMessage message = createMessage();
|
||||
|
||||
addAuthorization(message, userName, password);
|
||||
|
||||
SOAPEnvelope soapEnvelope = createEnvelope(message.getSOAPPart());
|
||||
|
||||
SOAPBody soapBody = soapEnvelope.getBody();
|
||||
marshal(clazz, soapBody);
|
||||
|
||||
message.saveChanges();
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates SOAP message to be send to the SOAP server
|
||||
*
|
||||
* @return the created SOAP message
|
||||
* @throws SOAPException
|
||||
* if unable to create soap message
|
||||
*/
|
||||
private static SOAPMessage createMessage() throws SOAPException {
|
||||
MessageFactory messageFactory = MessageFactory.newInstance();
|
||||
SOAPMessage message = messageFactory.createMessage();
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds authorization to the specified parameter <code>message</code>
|
||||
*
|
||||
* @param message
|
||||
* the message
|
||||
* @param username
|
||||
* the user name
|
||||
* @param password
|
||||
* the password
|
||||
*/
|
||||
private static void addAuthorization(SOAPMessage message, String username,
|
||||
String password) {
|
||||
String encodeUserInfo = username + ":" + password;
|
||||
encodeUserInfo = Base64Utility.encode(encodeUserInfo.getBytes());
|
||||
message.getMimeHeaders().setHeader("Authorization",
|
||||
"Basic " + encodeUserInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates SOAP envelope and adds namespace declaration and sets encoding
|
||||
* style
|
||||
*
|
||||
* @param soapPart
|
||||
* the message part
|
||||
* @return the SOAP envelope
|
||||
* @throws SOAPException
|
||||
*/
|
||||
private static SOAPEnvelope createEnvelope(SOAPPart soapPart)
|
||||
throws SOAPException {
|
||||
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
|
||||
addNamespaceDeclaration(soapEnvelope);
|
||||
setEncodingStyle(soapEnvelope);
|
||||
return soapEnvelope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds namespace declaration to the specified parameter
|
||||
* <code>soapEnvelop</code>
|
||||
*
|
||||
* @param soapEnvelope
|
||||
* the SOAP envelope
|
||||
* @throws SOAPException
|
||||
*/
|
||||
private static void addNamespaceDeclaration(SOAPEnvelope soapEnvelope)
|
||||
throws SOAPException {
|
||||
soapEnvelope.addNamespaceDeclaration("xsd",
|
||||
"http://www.w3.org/2001/XMLSchema");
|
||||
soapEnvelope.addNamespaceDeclaration("xsi",
|
||||
"http://www.w3.org/2001/XMLSchema-instance");
|
||||
soapEnvelope.addNamespaceDeclaration("enc",
|
||||
"http://schemas.xmlsoap.org/soap/encoding/");
|
||||
soapEnvelope.addNamespaceDeclaration("env",
|
||||
"http://schemas.xmlsoap.org/soap/envelop/");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the encoding style to the specified parameter
|
||||
* <code>soapEnvelop</code>
|
||||
*
|
||||
* @param soapEnvelope
|
||||
* the SOAP envelope
|
||||
* @throws SOAPException
|
||||
*/
|
||||
private static void setEncodingStyle(SOAPEnvelope soapEnvelope)
|
||||
throws SOAPException {
|
||||
soapEnvelope
|
||||
.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshals the specified parameter <code>clazz</code> to the specified
|
||||
* <code>soapBody</code>
|
||||
*
|
||||
* @param clazz
|
||||
* the object to be marshaled
|
||||
* @param soapBody
|
||||
* the SOAP body, result of marshal
|
||||
* @throws JAXBException
|
||||
* if marshaling failed
|
||||
*/
|
||||
private static <T> void marshal(T clazz, SOAPBody soapBody)
|
||||
throws JAXBException {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(clazz.getClass());
|
||||
Marshaller marshaller = jaxbContext.createMarshaller();
|
||||
marshaller.marshal(clazz, soapBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshals the specified paramter <code>soapBody</code> to the specified
|
||||
* <code>clazz</code>
|
||||
*
|
||||
* @param clazz
|
||||
* object to hold unmarashal result
|
||||
* @param soapBody
|
||||
* the soap body to be unmarshalled
|
||||
* @return the unmarashalled object
|
||||
* @throws JAXBException
|
||||
* if unmarshal failed
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T unmarshal(Class<T> clazz, SOAPBody soapBody)
|
||||
throws JAXBException {
|
||||
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
|
||||
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
Node bindElement = (Node) soapBody.getFirstChild();
|
||||
while (bindElement.getNodeType() != Node.ELEMENT_NODE) {
|
||||
bindElement = (Node) bindElement.getNextSibling();
|
||||
}
|
||||
return unmarshaller.unmarshal(bindElement, clazz).getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the SOAP message request to the SOAP server
|
||||
*
|
||||
* @param url
|
||||
* the endpoint of the web service
|
||||
* @param message
|
||||
* the SOAP message to be send
|
||||
* @return the response, SOAP message
|
||||
* @throws SOAPException
|
||||
* if unable to send request
|
||||
*/
|
||||
private static SOAPMessage sendRequest(String url, SOAPMessage message)
|
||||
throws SOAPException {
|
||||
SOAPConnection connection = null;
|
||||
SOAPMessage response = null;
|
||||
try {
|
||||
connection = createConnection();
|
||||
response = connection.call(message, url);
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
closeConnection(connection);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SOAP connection to the SOAP server
|
||||
*
|
||||
* @return the SOAPconnection object
|
||||
* @throws SOAPException
|
||||
* if unable to create connection
|
||||
*/
|
||||
private static SOAPConnection createConnection() throws SOAPException {
|
||||
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory
|
||||
.newInstance();
|
||||
SOAPConnection connection = soapConnectionFactory.createConnection();
|
||||
return connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the SOAP connection
|
||||
*
|
||||
* @param connection
|
||||
* the SOAP connection
|
||||
* @throws SOAPException
|
||||
* if unable to close connection
|
||||
*/
|
||||
private static void closeConnection(SOAPConnection connection)
|
||||
throws SOAPException {
|
||||
connection.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends soap request to the SOAP server. Receives and unmarshals the
|
||||
* response
|
||||
*
|
||||
* @param url
|
||||
* the SOAP server url(endpoint)
|
||||
* @param userName
|
||||
* the user
|
||||
* @param password
|
||||
* the password
|
||||
* @param request
|
||||
* the request object
|
||||
* @param response
|
||||
* the response class
|
||||
* @return the expected object or null
|
||||
*/
|
||||
public static <T, U> T sendRequestReceiveResponse(String url,
|
||||
String userName, String password, U request, Class<T> response) {
|
||||
try {
|
||||
SOAPMessage requestMsg = createRequest(request, userName, password);
|
||||
SOAPMessage responseMsg = sendRequest(url, requestMsg);
|
||||
return unmarshal(response, responseMsg.getSOAPBody());
|
||||
} catch (SOAPException soapExp) {
|
||||
LOG.error("SOAPException: ", soapExp);
|
||||
} catch (JAXBException jaxbExp) {
|
||||
LOG.error("JAXBException: ", jaxbExp);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks authorization for the specified <code>username</code> and
|
||||
* <code>password</code>
|
||||
*
|
||||
* @param url
|
||||
* webservices url
|
||||
* @param username
|
||||
* the user
|
||||
* @param password
|
||||
* the password
|
||||
* @return true if user is authorized otherwise false
|
||||
*/
|
||||
public static boolean checkAuthorization(String url, String username,
|
||||
String password) {
|
||||
try {
|
||||
SOAPMessage message = createMessage();
|
||||
addAuthorization(message, username, password);
|
||||
sendRequest(url, message);
|
||||
return true;
|
||||
} catch (SOAPException e) {
|
||||
LOG.error("SOAP Exception: ", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* simulates roster response, to be used for example by unit test
|
||||
*
|
||||
* unmarshals the roster xml from the specified <code>file</code> and
|
||||
* returns {@link RosterResponseDTO}
|
||||
*
|
||||
* @param file
|
||||
* file with xml contents
|
||||
* @return exportRosterDTO if unmarshal succeeded otherwise null
|
||||
*/
|
||||
public static RosterResponseDTO unmarshalRosterFromFile(File file) {
|
||||
try {
|
||||
JAXBContext jaxbContext = JAXBContext
|
||||
.newInstance(RosterResponseDTO.class);
|
||||
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
RosterResponseDTO exportResponseDTO = (RosterResponseDTO) unmarshaller
|
||||
.unmarshal(file);
|
||||
return exportResponseDTO;
|
||||
} catch (JAXBException e) {
|
||||
LOG.error("Error processing response: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAnyElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector Data
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement
|
||||
@XmlSeeAlso({ RosterDTO.class })
|
||||
public class DataDTO<T> {
|
||||
|
||||
@XmlAnyElement
|
||||
private T data;
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector Department
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "Afdeling")
|
||||
public class DepartmentDTO {
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement
|
||||
private String ref;
|
||||
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public void setRef(String ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlValue;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector Duration
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement
|
||||
public class DurationDTO {
|
||||
|
||||
@XmlAttribute(name = "options", required = true)
|
||||
private String options;
|
||||
|
||||
|
||||
@XmlValue
|
||||
@XmlJavaTypeAdapter(TimDoubleAdapter.class)
|
||||
private Double duration;
|
||||
|
||||
public String getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(String options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public Double getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(Double duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector filter
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement
|
||||
public class FilterDTO {
|
||||
|
||||
@XmlElement(name = "persoon")
|
||||
private PersonDTO person;
|
||||
|
||||
@XmlElement(name = "periode")
|
||||
private List<PeriodDTO> periods;
|
||||
|
||||
@XmlElement(name = "Afdeling")
|
||||
private DepartmentDTO department;
|
||||
|
||||
@XmlElement(name = "roostercategorie")
|
||||
private RosterCategoryDTO rosterCategory;
|
||||
|
||||
public PersonDTO getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(PersonDTO person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
public List<PeriodDTO> getPeriods() {
|
||||
return periods;
|
||||
}
|
||||
|
||||
public void setPeriods(List<PeriodDTO> periods) {
|
||||
this.periods = periods;
|
||||
}
|
||||
|
||||
public DepartmentDTO getDepartment() {
|
||||
return department;
|
||||
}
|
||||
|
||||
public void setDepartment(DepartmentDTO department) {
|
||||
this.department = department;
|
||||
}
|
||||
|
||||
public RosterCategoryDTO getRosterCategory() {
|
||||
return rosterCategory;
|
||||
}
|
||||
|
||||
public void setRosterCategory(RosterCategoryDTO rosterCategory) {
|
||||
this.rosterCategory = rosterCategory;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector Period
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement
|
||||
public class PeriodDTO {
|
||||
|
||||
@XmlElement(name = "startdate", required = true, nillable = true)
|
||||
private DateTime start;
|
||||
|
||||
@XmlElement(name = "enddate", required = true, nillable = true)
|
||||
private DateTime end;
|
||||
|
||||
public DateTime getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(DateTime start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public DateTime getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(DateTime end) {
|
||||
this.end = end;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector Person
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "Persoon")
|
||||
@XmlType(propOrder = { "networkName", "name", "emailAddress" })
|
||||
public class PersonDTO {
|
||||
|
||||
@XmlAttribute(name = "options")
|
||||
private String options;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "naam", nillable = true)
|
||||
private String name;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "emaladres", nillable = true)
|
||||
private String emailAddress;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "netwerknaam", nillable = true)
|
||||
private String networkName;
|
||||
|
||||
public String getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(String options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getEmailAddress() {
|
||||
return emailAddress;
|
||||
}
|
||||
|
||||
public void setEmailAddress(String emailAddress) {
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
public String getNetworkName() {
|
||||
return networkName;
|
||||
}
|
||||
|
||||
public void setNetworkName(String networkName) {
|
||||
this.networkName = networkName;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector Product
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement
|
||||
public class ProductDTO {
|
||||
|
||||
@XmlAttribute(required = true)
|
||||
private String options;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement
|
||||
private String code;
|
||||
|
||||
private String name;
|
||||
|
||||
public String getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(String options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlValue;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector RegistrationDate
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "datum")
|
||||
public class RegistrationDateDTO {
|
||||
|
||||
@XmlAttribute(name = "options", required = true)
|
||||
private String options;
|
||||
|
||||
@XmlValue
|
||||
private LocalDate date;
|
||||
|
||||
public String getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
public void setOptions(String options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector RosterCategory
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "roostercategorie")
|
||||
@XmlType(propOrder = { "name", "presence", "status" })
|
||||
public class RosterCategoryDTO {
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "naam", required = true, nillable = true)
|
||||
private String name;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "aanwezigheid", required = true, nillable = true)
|
||||
private String presence;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(required = true, nillable = true)
|
||||
private String status;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPresence() {
|
||||
return presence;
|
||||
}
|
||||
|
||||
public void setPresence(String presence) {
|
||||
this.presence = presence;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.LocalTime;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector Roster
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "bezettingblok")
|
||||
public class RosterDTO {
|
||||
|
||||
@XmlAttribute(name = "startdate", required = true)
|
||||
private LocalDate startDate;
|
||||
|
||||
@XmlAttribute(name = "enddate", required = true)
|
||||
private LocalDate endDate;
|
||||
|
||||
@XmlAttribute(name = "resource_planning")
|
||||
private Boolean resourcePlanning;
|
||||
|
||||
@XmlAttribute(name = "day_planning")
|
||||
private Boolean dayPlanning;
|
||||
|
||||
@XmlAttribute
|
||||
private Boolean calendar;
|
||||
|
||||
@XmlAttribute(name = "non_planned")
|
||||
private Boolean nonPlaned;
|
||||
|
||||
@XmlAttribute(name = "full_day")
|
||||
private Boolean fullDay;
|
||||
|
||||
@XmlAttribute
|
||||
private Boolean concept;
|
||||
|
||||
@XmlElement
|
||||
private FilterDTO filter;
|
||||
|
||||
@XmlElement(name = "Persoon")
|
||||
private List<PersonDTO> persons;
|
||||
|
||||
@XmlElement(name = "Roostercategorie")
|
||||
private List<RosterCategoryDTO> rosterCategories;
|
||||
|
||||
@XmlElement(name = "Afdeling")
|
||||
private DepartmentDTO department;
|
||||
|
||||
@XmlElement(name = "Datum", required = true, nillable = true)
|
||||
private LocalDate date;
|
||||
|
||||
@XmlElement(name = "Tijd", required = true, nillable = true)
|
||||
private LocalTime time;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "duur", required = true, nillable = true)
|
||||
private String duration;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "aanwezigheid")
|
||||
private String precence;
|
||||
|
||||
@XmlElement(name = "periode")
|
||||
private List<PeriodDTO> periods;
|
||||
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@XmlElement(name = "status")
|
||||
private String status;
|
||||
|
||||
public LocalDate getStartDate() {
|
||||
return startDate;
|
||||
}
|
||||
|
||||
public void setStartDate(LocalDate startDate) {
|
||||
this.startDate = startDate;
|
||||
}
|
||||
|
||||
public LocalDate getEndDate() {
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public void setEndDate(LocalDate endDate) {
|
||||
this.endDate = endDate;
|
||||
}
|
||||
|
||||
public Boolean getResourcePlanning() {
|
||||
return resourcePlanning;
|
||||
}
|
||||
|
||||
public void setResourcePlanning(Boolean resourcePlanning) {
|
||||
this.resourcePlanning = resourcePlanning;
|
||||
}
|
||||
|
||||
public Boolean getDayPlanning() {
|
||||
return dayPlanning;
|
||||
}
|
||||
|
||||
public void setDayPlanning(Boolean dayPlanning) {
|
||||
this.dayPlanning = dayPlanning;
|
||||
}
|
||||
|
||||
public Boolean getCalendar() {
|
||||
return calendar;
|
||||
}
|
||||
|
||||
public void setCalendar(Boolean calendar) {
|
||||
this.calendar = calendar;
|
||||
}
|
||||
|
||||
public Boolean getNonPlaned() {
|
||||
return nonPlaned;
|
||||
}
|
||||
|
||||
public void setNonPlaned(Boolean nonPlaned) {
|
||||
this.nonPlaned = nonPlaned;
|
||||
}
|
||||
|
||||
public Boolean getFullDay() {
|
||||
return fullDay;
|
||||
}
|
||||
|
||||
public void setFullDay(Boolean fullDay) {
|
||||
this.fullDay = fullDay;
|
||||
}
|
||||
|
||||
public Boolean getConcept() {
|
||||
return concept;
|
||||
}
|
||||
|
||||
public void setConcept(Boolean concept) {
|
||||
this.concept = concept;
|
||||
}
|
||||
|
||||
public FilterDTO getFilter() {
|
||||
return filter;
|
||||
}
|
||||
|
||||
public void setFilter(FilterDTO filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public List<PersonDTO> getPersons() {
|
||||
return persons;
|
||||
}
|
||||
|
||||
public void setPersons(List<PersonDTO> persons) {
|
||||
this.persons = persons;
|
||||
}
|
||||
|
||||
public List<RosterCategoryDTO> getRosterCategories() {
|
||||
return rosterCategories;
|
||||
}
|
||||
|
||||
public void setRosterCategories(List<RosterCategoryDTO> rosterCategories) {
|
||||
this.rosterCategories = rosterCategories;
|
||||
}
|
||||
|
||||
public DepartmentDTO getDepartment() {
|
||||
return department;
|
||||
}
|
||||
|
||||
public void setDepartment(DepartmentDTO department) {
|
||||
this.department = department;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public LocalTime getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTime(LocalTime time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public String getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(String duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public String getPrecence() {
|
||||
return precence;
|
||||
}
|
||||
|
||||
public void setPrecence(String precence) {
|
||||
this.precence = precence;
|
||||
}
|
||||
|
||||
public List<PeriodDTO> getPeriods() {
|
||||
return periods;
|
||||
}
|
||||
|
||||
public void setPeriods(List<PeriodDTO> periods) {
|
||||
this.periods = periods;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector RosterRequest
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "export", namespace = "impexp.timn.aenova.nl")
|
||||
public class RosterRequestDTO {
|
||||
|
||||
@XmlElement
|
||||
private DataDTO<RosterDTO> data;
|
||||
|
||||
public DataDTO<RosterDTO> getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(DataDTO<RosterDTO> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector RosterResponse
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "exportResponse", namespace = "impexp.timn.aenova.nl")
|
||||
public class RosterResponseDTO {
|
||||
|
||||
@XmlElementWrapper(name = "return")
|
||||
@XmlElement(name = "bezettingblok")
|
||||
private List<RosterDTO> rosters;
|
||||
|
||||
public List<RosterDTO> getRosters() {
|
||||
return rosters;
|
||||
}
|
||||
|
||||
public void setRosters(List<RosterDTO> rosters) {
|
||||
this.rosters = rosters;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Adapter responsible for converting from <code>DateTime</code> to
|
||||
* string(tim-string-datetime) and vice versa
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class TimDateTimeAdapter extends XmlAdapter<String, DateTime> {
|
||||
|
||||
@Override
|
||||
public String marshal(DateTime dateTime) throws Exception {
|
||||
return dateTime.toString("dd-MM-yyyy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateTime unmarshal(String dateTimeStr) throws Exception {
|
||||
DateTimeFormatter fmt = DateTimeFormat
|
||||
.forPattern("dd-MM-yyyy HH:mm:ss.SSS");
|
||||
return fmt.parseDateTime(dateTimeStr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
/**
|
||||
* Adapter responsible for converting from <code>Double</code> to
|
||||
* string(tim-string-double) and vice versa
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class TimDoubleAdapter extends XmlAdapter<String, Double> {
|
||||
|
||||
@Override
|
||||
public String marshal(Double value) throws Exception {
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
return String.format(Locale.GERMAN, "%1$,.2f", value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double unmarshal(String value) throws Exception {
|
||||
return DatatypeConverter.parseDouble(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Adapter responsible for converting from <code>LocalDate</code> to
|
||||
* string(tim-string-date) and vice versa
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class TimLocalDateAdapter extends XmlAdapter<String, LocalDate> {
|
||||
|
||||
@Override
|
||||
public String marshal(LocalDate localDate) throws Exception {
|
||||
return localDate.toString("dd-MM-yyyy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalDate unmarshal(String dateStr) throws Exception {
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern("dd-MM-yyyy");
|
||||
return fmt.parseDateTime(dateStr).toLocalDate();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
/**
|
||||
* Class containing all constants for Tim-options.
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public final class TimOptions {
|
||||
|
||||
private TimOptions() {
|
||||
|
||||
}
|
||||
|
||||
public static final String UPDATE_OR_INSERT = "@";
|
||||
public static final String UPDATE = "%";
|
||||
public static final String AUTO_INSERT = "!";
|
||||
public static final String QUOTED = "''";
|
||||
public static final String DECIMAL = "#";
|
||||
public static final String SUM_DOUBLE = "+";
|
||||
public static final String SUM_LONG = "&";
|
||||
public static final String PARENT = "^";
|
||||
public static final String ANY_PARENT = "~";
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.joda.time.LocalTime;
|
||||
|
||||
/**
|
||||
* Adapter responsible for converting from <code>LocalTime</code> to
|
||||
* string(tim-string-time) and vice versa
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class TimTimeAdapter extends XmlAdapter<String, LocalTime> {
|
||||
|
||||
@Override
|
||||
public String marshal(LocalTime localTime) throws Exception {
|
||||
return localTime.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocalTime unmarshal(String localTimeStr) throws Exception {
|
||||
return new LocalTime(localTimeStr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector TimeRegistration
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "tijdregistratie")
|
||||
public class TimeRegistrationDTO {
|
||||
|
||||
@XmlElement(name = "persoon")
|
||||
private PersonDTO person;
|
||||
|
||||
private ProductDTO product;
|
||||
|
||||
@XmlElement(name = "datum")
|
||||
private RegistrationDateDTO registrationDate;
|
||||
|
||||
@XmlElement(name = "duur")
|
||||
private DurationDTO duration;
|
||||
|
||||
public PersonDTO getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(PersonDTO person) {
|
||||
this.person = person;
|
||||
}
|
||||
|
||||
public ProductDTO getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
public void setProduct(ProductDTO product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
public RegistrationDateDTO getRegistrationDate() {
|
||||
return registrationDate;
|
||||
}
|
||||
|
||||
public void setRegistrationDate(RegistrationDateDTO registrationDate) {
|
||||
this.registrationDate = registrationDate;
|
||||
}
|
||||
|
||||
public DurationDTO getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public void setDuration(DurationDTO duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector TimeRegistrationRequest
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "import", namespace = "impexp.timn.aenova.nl")
|
||||
public class TimeRegistrationRequestDTO {
|
||||
|
||||
@XmlElementWrapper(name = "data")
|
||||
@XmlElement(name = "tijdregistratie")
|
||||
private List<TimeRegistrationDTO> timeRegistrations;
|
||||
|
||||
public List<TimeRegistrationDTO> getTimeRegistrations() {
|
||||
return timeRegistrations;
|
||||
}
|
||||
|
||||
public void setTimeRegistrations(List<TimeRegistrationDTO> timeRegistrations) {
|
||||
this.timeRegistrations = timeRegistrations;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* DTO representing a tim-connector TimeRegistrationResponse
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlRootElement(name = "importResponse", namespace = "impexp.timn.aenova.nl")
|
||||
public class TimeRegistrationResponseDTO {
|
||||
|
||||
@XmlElementWrapper(name = "return")
|
||||
@XmlElement(name = "ref")
|
||||
private List<Integer> ref;
|
||||
|
||||
public List<Integer> getRefs() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
public void setRefs(List<Integer> ref) {
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An xmlAdapaters that will be applied within this package
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters({
|
||||
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type = DateTime.class, value = org.libreplan.importers.tim.TimDateTimeAdapter.class),
|
||||
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type = LocalDate.class, value = org.libreplan.importers.tim.TimLocalDateAdapter.class),
|
||||
@javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type = Date.class, value = org.libreplan.importers.tim.TimTimeAdapter.class) })
|
||||
package org.libreplan.importers.tim;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
|
|
@ -30,6 +30,7 @@ import java.util.Comparator;
|
|||
import java.util.ConcurrentModificationException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
|
@ -42,16 +43,20 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.apache.cxf.jaxrs.client.WebClient;
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.entities.Configuration;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorProperty;
|
||||
import org.libreplan.business.common.entities.EntityNameEnum;
|
||||
import org.libreplan.business.common.entities.EntitySequence;
|
||||
import org.libreplan.business.common.entities.JiraConfiguration;
|
||||
import org.libreplan.business.common.entities.LDAPConfiguration;
|
||||
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.common.entities.ProgressType;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
|
||||
import org.libreplan.business.users.entities.UserRole;
|
||||
import org.libreplan.importers.JiraRESTClient;
|
||||
import org.libreplan.importers.TimSoapClient;
|
||||
import org.libreplan.web.common.components.bandboxsearch.BandboxSearch;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
|
|
@ -83,6 +88,7 @@ import org.zkoss.zul.Rows;
|
|||
import org.zkoss.zul.SimpleListModel;
|
||||
import org.zkoss.zul.Textbox;
|
||||
import org.zkoss.zul.api.Window;
|
||||
import org.zkoss.zul.impl.InputElement;
|
||||
|
||||
/**
|
||||
* Controller for {@link Configuration} entity.
|
||||
|
|
@ -125,6 +131,12 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
|
||||
private Radiogroup strategy;
|
||||
|
||||
private Combobox connectorCombo;
|
||||
|
||||
private Grid connectorPropertriesGrid;
|
||||
|
||||
private Connector selectedConnector;
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
|
|
@ -215,8 +227,16 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
configurationModel.confirm();
|
||||
configurationModel.init();
|
||||
messages.showMessage(Level.INFO, _("Changes saved"));
|
||||
if (getSelectedConnector() != null
|
||||
&& !configurationModel
|
||||
.scheduleOrUnscheduleJobs(getSelectedConnector())) {
|
||||
messages.showMessage(
|
||||
Level.ERROR,
|
||||
_("Scheduling or unscheduling of jobs for this connector is not completed"));
|
||||
}
|
||||
reloadWindow();
|
||||
reloadEntitySequences();
|
||||
reloadConnectors();
|
||||
} catch (ValidationException e) {
|
||||
messages.showInvalidValues(e);
|
||||
} catch (ConcurrentModificationException e) {
|
||||
|
|
@ -224,6 +244,7 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
configurationModel.init();
|
||||
reloadWindow();
|
||||
reloadEntitySequences();
|
||||
reloadConnectors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -233,6 +254,7 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
messages.showMessage(Level.INFO, _("Changes have been canceled"));
|
||||
reloadWindow();
|
||||
reloadEntitySequences();
|
||||
reloadConnectors();
|
||||
}
|
||||
|
||||
public void testLDAPConnection() {
|
||||
|
|
@ -267,22 +289,71 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
/**
|
||||
* tests jira connection
|
||||
* Tests connection
|
||||
*/
|
||||
public void testJiraConnection() {
|
||||
public void testConnection() {
|
||||
if (selectedConnector == null) {
|
||||
messages.showMessage(Level.ERROR,
|
||||
_("Please select a connector to test it"));
|
||||
return;
|
||||
}
|
||||
|
||||
JiraConfiguration jiraConfiguration = configurationModel
|
||||
.getJiraConfiguration();
|
||||
Map<String, String> properties = selectedConnector.getPropertiesAsMap();
|
||||
String url = properties.get(PredefinedConnectorProperties.SERVER_URL);
|
||||
String username = properties
|
||||
.get(PredefinedConnectorProperties.USERNAME);
|
||||
String password = properties
|
||||
.get(PredefinedConnectorProperties.PASSWORD);
|
||||
|
||||
if (selectedConnector.getName().equals(
|
||||
PredefinedConnectors.TIM.getName())) {
|
||||
testTimConnection(url, username, password);
|
||||
} else if (selectedConnector.getName().equals(
|
||||
PredefinedConnectors.JIRA.getName())) {
|
||||
testJiraConnection(url, username, password);
|
||||
} else {
|
||||
throw new RuntimeException("Unknown connector");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test tim connection
|
||||
*
|
||||
* @param url
|
||||
* the url of the server
|
||||
* @param username
|
||||
* the username
|
||||
* @param password
|
||||
* the password
|
||||
*/
|
||||
private void testTimConnection(String url, String username, String password) {
|
||||
if (TimSoapClient.checkAuthorization(url, username, password)) {
|
||||
messages.showMessage(Level.INFO, _("Tim connection was successful"));
|
||||
} else {
|
||||
messages.showMessage(Level.ERROR, _("Cannot connet to Tim server"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JIRA connection
|
||||
*
|
||||
* @param url
|
||||
* the url
|
||||
* @param username
|
||||
* the username
|
||||
* @param password
|
||||
* the password
|
||||
*/
|
||||
private void testJiraConnection(String url, String username, String password) {
|
||||
|
||||
try {
|
||||
|
||||
WebClient client = WebClient.create(jiraConfiguration.getJiraUrl());
|
||||
WebClient client = WebClient.create(url);
|
||||
client.path(JiraRESTClient.PATH_AUTH_SESSION).accept(
|
||||
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML);
|
||||
|
||||
org.libreplan.ws.common.impl.Util.addAuthorizationHeader(client,
|
||||
jiraConfiguration.getJiraUserId(),
|
||||
jiraConfiguration.getJiraPassword());
|
||||
username, password);
|
||||
|
||||
Response response = client.get();
|
||||
|
||||
|
|
@ -290,17 +361,16 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
messages.showMessage(Level.INFO,
|
||||
_("JIRA connection was successful"));
|
||||
} else {
|
||||
LOG.info("Status code: " + response.getStatus());
|
||||
LOG.error("Status code: " + response.getStatus());
|
||||
messages.showMessage(Level.ERROR,
|
||||
_("Cannot connect to JIRA server"));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOG.info(e);
|
||||
LOG.error(e);
|
||||
messages.showMessage(Level.ERROR,
|
||||
_("Cannot connect to JIRA server"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean checkValidEntitySequenceRows() {
|
||||
|
|
@ -346,6 +416,14 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
entitySequencesGrid.invalidate();
|
||||
}
|
||||
|
||||
private void reloadConnectors() {
|
||||
selectedConnector = configurationModel
|
||||
.getConnectorByName(selectedConnector != null ? selectedConnector
|
||||
.getName() : null);
|
||||
Util.reloadBindings(connectorCombo);
|
||||
Util.reloadBindings(connectorPropertriesGrid);
|
||||
}
|
||||
|
||||
public String getCompanyCode() {
|
||||
return configurationModel.getCompanyCode();
|
||||
}
|
||||
|
|
@ -818,14 +896,6 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
configurationModel.setLdapConfiguration(ldapConfiguration);
|
||||
}
|
||||
|
||||
public JiraConfiguration getJiraConfiguration() {
|
||||
return configurationModel.getJiraConfiguration();
|
||||
}
|
||||
|
||||
public void setJiraConfiguration(JiraConfiguration jiraConfiguration) {
|
||||
configurationModel.setJiraConfiguration(jiraConfiguration);
|
||||
}
|
||||
|
||||
public RowRenderer getAllUserRolesRenderer() {
|
||||
return new RowRenderer() {
|
||||
@Override
|
||||
|
|
@ -976,12 +1046,105 @@ public class ConfigurationController extends GenericForwardComposer {
|
|||
configurationModel.setSecondsPlanningWarning(secondsPlanningWarning);
|
||||
}
|
||||
|
||||
public TypeOfWorkHours getJiraConnectorTypeOfWorkHours() {
|
||||
return configurationModel.getJiraConnectorTypeOfWorkHours();
|
||||
public List<Connector> getConnectors() {
|
||||
return configurationModel.getConnectors();
|
||||
}
|
||||
|
||||
public void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
|
||||
configurationModel.setJiraConnectorTypeOfWorkHours(typeOfWorkHours);
|
||||
public Connector getSelectedConnector() {
|
||||
return selectedConnector;
|
||||
}
|
||||
|
||||
public void setSelectedConnector(Connector connector) {
|
||||
selectedConnector = connector;
|
||||
Util.reloadBindings(connectorPropertriesGrid);
|
||||
}
|
||||
|
||||
public List<ConnectorProperty> getConnectorPropertries() {
|
||||
if (selectedConnector == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return selectedConnector.getProperties();
|
||||
}
|
||||
|
||||
public RowRenderer getConnectorPropertriesRenderer() {
|
||||
return new RowRenderer() {
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
ConnectorProperty property = (ConnectorProperty) data;
|
||||
row.setValue(property);
|
||||
|
||||
Util.appendLabel(row, _(property.getKey()));
|
||||
appendValueTextbox(row, property);
|
||||
}
|
||||
|
||||
private void appendValueTextbox(Row row,
|
||||
final ConnectorProperty property) {
|
||||
final Textbox textbox = new Textbox();
|
||||
textbox.setWidth("400px");
|
||||
textbox.setConstraint(checkPropertyValue(property));
|
||||
|
||||
Util.bind(textbox, new Util.Getter<String>() {
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
return property.getValue();
|
||||
}
|
||||
}, new Util.Setter<String>() {
|
||||
|
||||
@Override
|
||||
public void set(String value) {
|
||||
property.setValue(value);
|
||||
}
|
||||
});
|
||||
if (property.getKey().equals(
|
||||
PredefinedConnectorProperties.PASSWORD)) {
|
||||
textbox.setType("password");
|
||||
}
|
||||
|
||||
row.appendChild(textbox);
|
||||
}
|
||||
|
||||
public Constraint checkPropertyValue(
|
||||
final ConnectorProperty property) {
|
||||
final String key = property.getKey();
|
||||
return new Constraint() {
|
||||
@Override
|
||||
public void validate(Component comp, Object value) {
|
||||
if (key.equals(PredefinedConnectorProperties.ACTIVATED)) {
|
||||
if (!((String) value).equalsIgnoreCase("Y")
|
||||
&& !((String) value).equalsIgnoreCase("N")) {
|
||||
throw new WrongValueException(comp, _(
|
||||
"Only {0} allowed", "Y/N"));
|
||||
}
|
||||
} else if (key
|
||||
.equals(PredefinedConnectorProperties.SERVER_URL)
|
||||
|| key.equals(PredefinedConnectorProperties.USERNAME)
|
||||
|| key.equals(PredefinedConnectorProperties.PASSWORD)
|
||||
|| key.equals(PredefinedConnectorProperties.JIRA_HOURS_TYPE)) {
|
||||
((InputElement) comp).setConstraint("no empty:"
|
||||
+ _("cannot be empty"));
|
||||
} else if (key
|
||||
.equals(PredefinedConnectorProperties.TIM_NR_DAYS_TIMESHEET)
|
||||
|| key.equals(PredefinedConnectorProperties.TIM_NR_DAYS_ROSTER)) {
|
||||
if (!isNumeric((String) value)) {
|
||||
throw new WrongValueException(comp,
|
||||
_("Only digits allowed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isNumeric(String input) {
|
||||
try {
|
||||
Integer.parseInt(input);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import static org.libreplan.web.I18nHelper._;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Currency;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
|
@ -38,11 +39,12 @@ import org.apache.commons.lang.StringUtils;
|
|||
import org.libreplan.business.calendars.daos.IBaseCalendarDAO;
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.daos.IEntitySequenceDAO;
|
||||
import org.libreplan.business.common.entities.Configuration;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.EntityNameEnum;
|
||||
import org.libreplan.business.common.entities.EntitySequence;
|
||||
import org.libreplan.business.common.entities.JiraConfiguration;
|
||||
import org.libreplan.business.common.entities.LDAPConfiguration;
|
||||
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
|
||||
import org.libreplan.business.common.entities.ProgressType;
|
||||
|
|
@ -76,6 +78,8 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
|
||||
private static Map<String, String> currencies = getAllCurrencies();
|
||||
|
||||
private List<Connector> connectors;
|
||||
|
||||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
|
||||
|
|
@ -88,6 +92,12 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
@Autowired
|
||||
private IWorkReportDAO workReportDAO;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Autowired
|
||||
private IJobSchedulerModel jobSchedulerModel;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<BaseCalendar> getCalendars() {
|
||||
|
|
@ -107,6 +117,8 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
public void init() {
|
||||
this.configuration = getCurrentConfiguration();
|
||||
initEntitySequences();
|
||||
initLdapConfiguration();
|
||||
initConnectorConfiguration();
|
||||
}
|
||||
|
||||
private void initEntitySequences() {
|
||||
|
|
@ -120,6 +132,23 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
}
|
||||
}
|
||||
|
||||
private void initLdapConfiguration() {
|
||||
if (null == configuration.getLdapConfiguration()) {
|
||||
configuration.setLdapConfiguration(LDAPConfiguration.create());
|
||||
}
|
||||
}
|
||||
|
||||
private void initConnectorConfiguration() {
|
||||
connectors = connectorDAO.getAll();
|
||||
forceLoadConnectors();
|
||||
}
|
||||
|
||||
private void forceLoadConnectors() {
|
||||
for (Connector connector : connectors) {
|
||||
connector.getProperties().size();
|
||||
}
|
||||
}
|
||||
|
||||
private Configuration getCurrentConfiguration() {
|
||||
Configuration configuration = configurationDAO.getConfiguration();
|
||||
if (configuration == null) {
|
||||
|
|
@ -132,8 +161,6 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
private void forceLoad(Configuration configuration) {
|
||||
forceLoad(configuration.getDefaultCalendar());
|
||||
forceLoad(configuration.getPersonalTimesheetsTypeOfWorkHours());
|
||||
forceLoad(configuration.getJiraConfiguration()
|
||||
.getJiraConnectorTypeOfWorkHours());
|
||||
}
|
||||
|
||||
private void forceLoad(BaseCalendar calendar) {
|
||||
|
|
@ -160,6 +187,7 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
public void confirm() {
|
||||
checkEntitySequences();
|
||||
configurationDAO.save(configuration);
|
||||
saveConnectors();
|
||||
try {
|
||||
storeAndRemoveEntitySequences();
|
||||
} catch (IllegalStateException e) {
|
||||
|
|
@ -663,36 +691,34 @@ public class ConfigurationModel implements IConfigurationModel {
|
|||
configuration.setSecondsPlanningWarning(secondsPlanningWarning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJiraConfiguration(JiraConfiguration jiraConfiguration) {
|
||||
configuration.setJiraConfiguration(jiraConfiguration);
|
||||
private void saveConnectors() {
|
||||
for (Connector connector : connectors) {
|
||||
connectorDAO.save(connector);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JiraConfiguration getJiraConfiguration() {
|
||||
return configuration.getJiraConfiguration();
|
||||
public List<Connector> getConnectors() {
|
||||
return Collections.unmodifiableList(connectors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeOfWorkHours getJiraConnectorTypeOfWorkHours() {
|
||||
JiraConfiguration jiraConfiguration = configuration
|
||||
.getJiraConfiguration();
|
||||
if (jiraConfiguration != null) {
|
||||
return jiraConfiguration.getJiraConnectorTypeOfWorkHours();
|
||||
public Connector getConnectorByName(String name) {
|
||||
if (name == null || connectors == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Connector connector : connectors) {
|
||||
if (connector.getName().equals(name)) {
|
||||
return connector;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours) {
|
||||
if (configuration != null) {
|
||||
JiraConfiguration jiraConfiguration = configuration
|
||||
.getJiraConfiguration();
|
||||
if (jiraConfiguration != null) {
|
||||
jiraConfiguration
|
||||
.setJiraConnectorTypeOfWorkHours(typeOfWorkHours);
|
||||
}
|
||||
}
|
||||
public boolean scheduleOrUnscheduleJobs(Connector connector) {
|
||||
return jobSchedulerModel.scheduleOrUnscheduleJobs(connector);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -414,6 +414,13 @@ public class CustomMenuController extends Div implements IMenuItemsRegister {
|
|||
"/profiles/profiles.zul",
|
||||
"13-usuarios.html#administraci-n-de-perfiles"));
|
||||
}
|
||||
if (SecurityUtils
|
||||
.isSuperuserOrUserInRoles(UserRole.ROLE_JOB_SCHEDULING)) {
|
||||
configurationItems.add(subItem(_("Job Scheduling"),
|
||||
"/common/job_scheduling.zul",
|
||||
"16-ldap-authentication.html"));
|
||||
}
|
||||
|
||||
if (!configurationItems.isEmpty()) {
|
||||
topItem(_("Configuration"), "/common/configuration.zul", "",
|
||||
configurationItems);
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.EntityNameEnum;
|
||||
import org.libreplan.business.common.entities.EntitySequence;
|
||||
import org.libreplan.business.common.entities.JiraConfiguration;
|
||||
import org.libreplan.business.common.entities.LDAPConfiguration;
|
||||
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
|
||||
import org.libreplan.business.common.entities.ProgressType;
|
||||
|
|
@ -186,12 +186,10 @@ public interface IConfigurationModel {
|
|||
void setSecondsPlanningWarning(
|
||||
Integer planningWarningExitWithoutSavingSeconds);
|
||||
|
||||
void setJiraConfiguration(JiraConfiguration jiraConfiguration);
|
||||
List<Connector> getConnectors();
|
||||
|
||||
JiraConfiguration getJiraConfiguration();
|
||||
Connector getConnectorByName(String name);
|
||||
|
||||
TypeOfWorkHours getJiraConnectorTypeOfWorkHours();
|
||||
|
||||
void setJiraConnectorTypeOfWorkHours(TypeOfWorkHours typeOfWorkHours);
|
||||
boolean scheduleOrUnscheduleJobs(Connector connector);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.importers.SynchronizationInfo;
|
||||
|
||||
/**
|
||||
* Contract for {@link JobSchedulerModel}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public interface IJobSchedulerModel {
|
||||
|
||||
/**
|
||||
* returns all job scheduler configurations
|
||||
*
|
||||
* @return list of <code>JobSchedulerConfiguration</code>
|
||||
*/
|
||||
List<JobSchedulerConfiguration> getJobSchedulerConfigurations();
|
||||
|
||||
/**
|
||||
* returns next fire time for the specified job from
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the job scheduler configuration
|
||||
*/
|
||||
String getNextFireTime(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
/**
|
||||
* Do manual action(replacement of scheduling)
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the job configuration
|
||||
* @throws ConnectorException
|
||||
* if connector is not valid
|
||||
*/
|
||||
void doManual(JobSchedulerConfiguration jobSchedulerConfiguration)
|
||||
throws ConnectorException;
|
||||
|
||||
/**
|
||||
* Returns synchronization infos. Failures or successes info
|
||||
*/
|
||||
List<SynchronizationInfo> getSynchronizationInfos();
|
||||
|
||||
/**
|
||||
* Prepares for create a new {@link JobSchedulerConfiguration}.
|
||||
*/
|
||||
void initCreate();
|
||||
|
||||
/**
|
||||
* Prepares for edit {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* object to be edited
|
||||
*/
|
||||
void initEdit(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
/**
|
||||
* Gets the current {@link JobSchedulerConfiguration}.
|
||||
*
|
||||
* @return A {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
JobSchedulerConfiguration getJobSchedulerConfiguration();
|
||||
|
||||
/**
|
||||
* Saves the current {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @throws ValidationException
|
||||
* if validation fails
|
||||
*/
|
||||
void confirmSave() throws ValidationException;
|
||||
|
||||
/**
|
||||
* Cancels the current {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Removes the current {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* object to be removed
|
||||
*/
|
||||
void remove(JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
/**
|
||||
* returns list of connectors
|
||||
*/
|
||||
List<Connector> getConnectors();
|
||||
|
||||
/**
|
||||
* Schedule or unschedule jobs for the specified <code>connector</code>
|
||||
*
|
||||
* schedule all jobs of the specified <code>connector</code>'s property
|
||||
* {@link PredefinedConnectorProperties#ACTIVATED} is 'Y', otherwise
|
||||
* unschedule the jobs
|
||||
*
|
||||
* @param connector
|
||||
* where to check if property is changed
|
||||
* @return true if (un)scheduling is successful, false otherwise
|
||||
*/
|
||||
boolean scheduleOrUnscheduleJobs(Connector connector);
|
||||
|
||||
/**
|
||||
* schedule or unschedule job for the specified job in
|
||||
* <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @return true if scheduling is succeeded, false otherwise
|
||||
*/
|
||||
boolean scheduleOrUnscheduleJob();
|
||||
|
||||
/**
|
||||
* Delete job specified in <code>{@link JobSchedulerConfiguration}</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* configuration for the job to be deleted
|
||||
* @return true if job is successfully deleted from the scheduler, false
|
||||
* otherwise
|
||||
*/
|
||||
boolean deleteScheduledJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.common;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.JobClassNameEnum;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.importers.SynchronizationInfo;
|
||||
import org.quartz.CronExpression;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.SuspendNotAllowedException;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Groupbox;
|
||||
import org.zkoss.zul.Hbox;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Listbox;
|
||||
import org.zkoss.zul.Popup;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
import org.zkoss.zul.api.Caption;
|
||||
import org.zkoss.zul.api.Textbox;
|
||||
import org.zkoss.zul.api.Window;
|
||||
|
||||
/**
|
||||
* Controller for job scheduler manager
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JobSchedulerController extends
|
||||
BaseCRUDController<JobSchedulerConfiguration> {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(JobSchedulerController.class);
|
||||
|
||||
private Grid listJobSchedulings;
|
||||
private Grid cronExpressionGrid;
|
||||
|
||||
private Popup cronExpressionInputPopup;
|
||||
|
||||
private Label jobGroup;
|
||||
private Label jobName;
|
||||
|
||||
private Textbox cronExpressionTextBox;
|
||||
private Textbox cronExpressionSeconds;
|
||||
private Textbox cronExpressionMinutes;
|
||||
private Textbox cronExpressionHours;
|
||||
private Textbox cronExpressionDayOfMonth;
|
||||
private Textbox cronExpressionMonth;
|
||||
private Textbox cronExpressionDayOfWeek;
|
||||
private Textbox cronExpressionYear;
|
||||
|
||||
private IJobSchedulerModel jobSchedulerModel;
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
listJobSchedulings = (Grid) listWindow
|
||||
.getFellowIfAny("listJobSchedulings");
|
||||
listJobSchedulings.getModel();
|
||||
initCronExpressionPopup();
|
||||
}
|
||||
|
||||
/**
|
||||
* initializes cron expressions for popup
|
||||
*/
|
||||
private void initCronExpressionPopup() {
|
||||
cronExpressionTextBox = (Textbox) editWindow
|
||||
.getFellow("cronExpressionTextBox");
|
||||
|
||||
cronExpressionInputPopup = (Popup) editWindow
|
||||
.getFellow("cronExpressionInputPopup");
|
||||
|
||||
jobGroup = (Label) cronExpressionInputPopup.getFellow("jobGroup");
|
||||
jobName = (Label) cronExpressionInputPopup.getFellow("jobName");
|
||||
|
||||
cronExpressionGrid = (Grid) cronExpressionInputPopup
|
||||
.getFellow("cronExpressionGrid");
|
||||
|
||||
cronExpressionSeconds = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionSeconds");
|
||||
cronExpressionMinutes = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionMinutes");
|
||||
cronExpressionHours = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionHours");
|
||||
cronExpressionDayOfMonth = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionDayOfMonth");
|
||||
cronExpressionMonth = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionMonth");
|
||||
cronExpressionDayOfWeek = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionDayOfWeek");
|
||||
cronExpressionYear = (Textbox) cronExpressionGrid
|
||||
.getFellow("cronExpressionYear");
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a list of {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
public List<JobSchedulerConfiguration> getJobSchedulerConfigurations() {
|
||||
return jobSchedulerModel.getJobSchedulerConfigurations();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns {@link JobSchedulerConfiguration}
|
||||
*/
|
||||
public JobSchedulerConfiguration getJobSchedulerConfiguration() {
|
||||
return jobSchedulerModel.getJobSchedulerConfiguration();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns all predefined jobs
|
||||
*/
|
||||
public JobClassNameEnum[] getJobNames() {
|
||||
return JobClassNameEnum.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* return list of connectorNames
|
||||
*/
|
||||
public List<String> getConnectorNames() {
|
||||
List<Connector> connectors = jobSchedulerModel.getConnectors();
|
||||
List<String> connectorNames = new ArrayList<String>();
|
||||
for (Connector connector : connectors) {
|
||||
connectorNames.add(connector.getName());
|
||||
}
|
||||
return connectorNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* renders job scheduling and returns {@link RowRenderer}
|
||||
*/
|
||||
public RowRenderer getJobSchedulingRenderer() {
|
||||
return new RowRenderer() {
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
final JobSchedulerConfiguration jobSchedulerConfiguration = (JobSchedulerConfiguration) data;
|
||||
row.setValue(data);
|
||||
|
||||
Util.appendLabel(row, jobSchedulerConfiguration.getJobGroup());
|
||||
Util.appendLabel(row, jobSchedulerConfiguration.getJobName());
|
||||
Util.appendLabel(row,
|
||||
jobSchedulerConfiguration.getCronExpression());
|
||||
Util.appendLabel(row,
|
||||
getNextFireTime(jobSchedulerConfiguration));
|
||||
Hbox hbox = new Hbox();
|
||||
hbox.appendChild(createManualButton(new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) throws Exception {
|
||||
try {
|
||||
jobSchedulerModel.doManual(jobSchedulerConfiguration);
|
||||
showSynchronizationInfo();
|
||||
} catch (ConnectorException e) {
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
}));
|
||||
hbox.appendChild(Util.createEditButton(new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
goToEditForm(jobSchedulerConfiguration);
|
||||
}
|
||||
}));
|
||||
hbox.appendChild(Util.createRemoveButton(new EventListener() {
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
confirmDelete(jobSchedulerConfiguration);
|
||||
}
|
||||
}));
|
||||
row.appendChild(hbox);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public RowRenderer getSynchronizationInfoRenderer() {
|
||||
return new RowRenderer() {
|
||||
|
||||
@Override
|
||||
public void render(Row row, Object data) {
|
||||
final SynchronizationInfo synchronizationInfo = (SynchronizationInfo) data;
|
||||
row.setValue(data);
|
||||
|
||||
Groupbox groupbox = new Groupbox();
|
||||
groupbox.setClosable(true);
|
||||
Caption caption = new org.zkoss.zul.Caption();
|
||||
caption.setLabel(synchronizationInfo.getAction());
|
||||
groupbox.appendChild(caption);
|
||||
row.appendChild(groupbox);
|
||||
|
||||
if (synchronizationInfo.isSuccessful()) {
|
||||
groupbox.appendChild(new Label(_("Completed")));
|
||||
} else {
|
||||
|
||||
Listbox listbox = new Listbox();
|
||||
|
||||
listbox.setModel(new SimpleListModel(synchronizationInfo
|
||||
.getFailedReasons()));
|
||||
groupbox.appendChild(listbox);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public List<SynchronizationInfo> getSynchronizationInfos() {
|
||||
return jobSchedulerModel.getSynchronizationInfos();
|
||||
}
|
||||
|
||||
|
||||
private void showSynchronizationInfo() {
|
||||
Map<String, Object> args = new HashMap<String, Object>();
|
||||
|
||||
Window win = (Window) Executions.createComponents(
|
||||
"/orders/_synchronizationInfo.zul", null, args);
|
||||
|
||||
Window syncInfoWin = (Window) win.getFellowIfAny("syncInfoWin");
|
||||
|
||||
Grid syncInfoGrid = (Grid) syncInfoWin.getFellowIfAny("syncInfoGrid");
|
||||
|
||||
syncInfoGrid.setModel(new SimpleListModel(getSynchronizationInfos()));
|
||||
|
||||
syncInfoGrid.setRowRenderer(getSynchronizationInfoRenderer());
|
||||
|
||||
try {
|
||||
win.doModal();
|
||||
} catch (SuspendNotAllowedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the next fire time for the specified job in
|
||||
* {@link JobSchedulerConfiguration}
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* the job scheduler configuration
|
||||
*/
|
||||
private String getNextFireTime(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
return jobSchedulerModel.getNextFireTime(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* creates and returns a button
|
||||
*
|
||||
* @param eventListener
|
||||
* Event listener for this button
|
||||
*/
|
||||
private static Button createManualButton(EventListener eventListener) {
|
||||
Button button = new Button(_("Manual"));
|
||||
button.setTooltiptext(_("Manual"));
|
||||
button.addEventListener(Events.ON_CLICK, eventListener);
|
||||
return button;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the <code>cronExpressionInputPopup</code>
|
||||
*/
|
||||
public void openPopup() {
|
||||
setupCronExpressionPopup(getJobSchedulerConfiguration());
|
||||
cronExpressionInputPopup.open(cronExpressionTextBox, "after_start");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cronExpression values for <code>cronExpressionInputPopup</code>
|
||||
*
|
||||
* @param jobSchedulerConfiguration
|
||||
* where to read the values
|
||||
*/
|
||||
private void setupCronExpressionPopup(
|
||||
final JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
if (jobSchedulerConfiguration != null) {
|
||||
jobGroup.setValue(jobSchedulerConfiguration.getJobGroup());
|
||||
jobName.setValue(jobSchedulerConfiguration.getJobName());
|
||||
|
||||
String cronExpression = jobSchedulerConfiguration
|
||||
.getCronExpression();
|
||||
if (cronExpression == null || cronExpression.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String[] cronExpressionArray = StringUtils.split(cronExpression);
|
||||
|
||||
cronExpressionSeconds.setValue(cronExpressionArray[0]);
|
||||
cronExpressionMinutes.setValue(cronExpressionArray[1]);
|
||||
cronExpressionHours.setValue(cronExpressionArray[2]);
|
||||
cronExpressionDayOfMonth.setValue(cronExpressionArray[3]);
|
||||
cronExpressionMonth.setValue(cronExpressionArray[4]);
|
||||
cronExpressionDayOfWeek.setValue(cronExpressionArray[5]);
|
||||
|
||||
if (cronExpressionArray.length == 7) {
|
||||
cronExpressionYear.setValue(cronExpressionArray[6]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets the <code>cronExpressionTextBox</code> value from the
|
||||
* <code>cronExpressionInputPopup</code>
|
||||
*/
|
||||
public void updateCronExpression() {
|
||||
String cronExpression = getCronExpressionString();
|
||||
try {
|
||||
// Check cron expression format
|
||||
new CronExpression(cronExpression);
|
||||
} catch (ParseException e) {
|
||||
LOG.info("Unable to parse cron expression", e);
|
||||
throw new WrongValueException(cronExpressionInputPopup,
|
||||
_("Unable to parse cron expression") + ":\n"
|
||||
+ e.getMessage());
|
||||
}
|
||||
cronExpressionTextBox.setValue(cronExpression);
|
||||
cronExpressionInputPopup.close();
|
||||
Util.saveBindings(cronExpressionTextBox);
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenating the cronExpression values
|
||||
*
|
||||
* @return cronExpression string
|
||||
*/
|
||||
private String getCronExpressionString() {
|
||||
String cronExpression = "";
|
||||
cronExpression += StringUtils.trimToEmpty(cronExpressionSeconds.getValue()) + " ";
|
||||
cronExpression += StringUtils.trimToEmpty(cronExpressionMinutes.getValue()) + " ";
|
||||
cronExpression += StringUtils.trimToEmpty(cronExpressionHours.getValue()) + " ";
|
||||
cronExpression += StringUtils.trimToEmpty(cronExpressionDayOfMonth.getValue()) + " ";
|
||||
cronExpression += StringUtils.trimToEmpty(cronExpressionMonth.getValue()) + " ";
|
||||
cronExpression += StringUtils.trimToEmpty(cronExpressionDayOfWeek.getValue());
|
||||
|
||||
String year = StringUtils.trimToEmpty(cronExpressionYear.getValue());
|
||||
if (!year.isEmpty()) {
|
||||
cronExpression += " " + year;
|
||||
}
|
||||
|
||||
return cronExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* closes the popup
|
||||
*/
|
||||
public void cancelPopup() {
|
||||
cronExpressionInputPopup.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getEntityType() {
|
||||
return _("Job scheduling");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPluralEntityType() {
|
||||
return _("Job scheduling");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initCreate() {
|
||||
jobSchedulerModel.initCreate();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initEdit(JobSchedulerConfiguration entity) {
|
||||
jobSchedulerModel.initEdit(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void save() throws ValidationException {
|
||||
jobSchedulerModel.confirmSave();
|
||||
if (jobSchedulerModel.scheduleOrUnscheduleJob()) {
|
||||
messagesForUser.showMessage(Level.INFO,
|
||||
_("Job is scheduled/unscheduled"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancel() {
|
||||
jobSchedulerModel.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobSchedulerConfiguration getEntityBeingEdited() {
|
||||
return jobSchedulerModel.getJobSchedulerConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void delete(JobSchedulerConfiguration entity)
|
||||
throws InstanceNotFoundException {
|
||||
jobSchedulerModel.remove(entity);
|
||||
if (jobSchedulerModel.deleteScheduledJob(entity)) {
|
||||
messagesForUser.showMessage(Level.INFO,
|
||||
_("Job is deleted from scheduler"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 Igalia, S.L.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.common;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.daos.IJobSchedulerConfigurationDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.JobClassNameEnum;
|
||||
import org.libreplan.business.common.entities.JobSchedulerConfiguration;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.common.exceptions.ValidationException;
|
||||
import org.libreplan.importers.IExportTimesheetsToTim;
|
||||
import org.libreplan.importers.IImportRosterFromTim;
|
||||
import org.libreplan.importers.IJiraOrderElementSynchronizer;
|
||||
import org.libreplan.importers.ISchedulerManager;
|
||||
import org.libreplan.importers.SynchronizationInfo;
|
||||
import org.libreplan.web.common.concurrentdetection.OnConcurrentModification;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Model for UI operations related to {@link JobSchedulerConfiguration}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
@OnConcurrentModification(goToPage = "/common/job_scheduling.zul")
|
||||
public class JobSchedulerModel implements IJobSchedulerModel {
|
||||
|
||||
private JobSchedulerConfiguration jobSchedulerConfiguration;
|
||||
|
||||
@Autowired
|
||||
private ISchedulerManager schedulerManager;
|
||||
|
||||
@Autowired
|
||||
private IJobSchedulerConfigurationDAO jobSchedulerConfigurationDAO;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Autowired
|
||||
private IImportRosterFromTim importRosterFromTim;
|
||||
|
||||
@Autowired
|
||||
private IExportTimesheetsToTim exportTimesheetsToTim;
|
||||
|
||||
@Autowired
|
||||
private IJiraOrderElementSynchronizer jiraOrderElementSynchronizer;
|
||||
|
||||
private List<SynchronizationInfo> synchronizationInfos;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<JobSchedulerConfiguration> getJobSchedulerConfigurations() {
|
||||
return jobSchedulerConfigurationDAO.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNextFireTime(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
return schedulerManager.getNextFireTime(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doManual(JobSchedulerConfiguration jobSchedulerConfiguration)
|
||||
throws ConnectorException {
|
||||
String name = jobSchedulerConfiguration.getJobClassName().getName();
|
||||
if (name.equals(JobClassNameEnum.IMPORT_ROSTER_FROM_TIM_JOB.getName())) {
|
||||
synchronizationInfos = importRosterFromTim.importRosters();
|
||||
return;
|
||||
}
|
||||
if (name.equals(JobClassNameEnum.EXPORT_TIMESHEET_TO_TIM_JOB.getName())) {
|
||||
synchronizationInfos = exportTimesheetsToTim.exportTimesheets();
|
||||
return;
|
||||
}
|
||||
if (name.equals(JobClassNameEnum.SYNC_ORDERELEMENTS_WITH_JIRA_ISSUES_JOB
|
||||
.getName())) {
|
||||
synchronizationInfos = jiraOrderElementSynchronizer
|
||||
.syncOrderElementsWithJiraIssues();
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("Unknown action");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SynchronizationInfo> getSynchronizationInfos() {
|
||||
return synchronizationInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initCreate() {
|
||||
this.jobSchedulerConfiguration = JobSchedulerConfiguration.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initEdit(JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
this.jobSchedulerConfiguration = jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobSchedulerConfiguration getJobSchedulerConfiguration() {
|
||||
return this.jobSchedulerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void confirmSave() throws ValidationException {
|
||||
jobSchedulerConfigurationDAO.save(jobSchedulerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
jobSchedulerConfiguration = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void remove(JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
try {
|
||||
jobSchedulerConfigurationDAO.remove(jobSchedulerConfiguration
|
||||
.getId());
|
||||
} catch (InstanceNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<Connector> getConnectors() {
|
||||
return connectorDAO.getAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scheduleOrUnscheduleJobs(Connector connector) {
|
||||
List<JobSchedulerConfiguration> jobSchedulerConfigurations = jobSchedulerConfigurationDAO
|
||||
.findByConnectorName(connector.getName());
|
||||
|
||||
for (JobSchedulerConfiguration jobSchedulerConfiguration : jobSchedulerConfigurations) {
|
||||
try {
|
||||
schedulerManager.scheduleOrUnscheduleJob(jobSchedulerConfiguration);
|
||||
} catch (SchedulerException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean scheduleOrUnscheduleJob() {
|
||||
try {
|
||||
schedulerManager.scheduleOrUnscheduleJob(jobSchedulerConfiguration);
|
||||
} catch (SchedulerException e) {
|
||||
throw new RuntimeException("Failed to schedule job", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteScheduledJob(
|
||||
JobSchedulerConfiguration jobSchedulerConfiguration) {
|
||||
try {
|
||||
schedulerManager.deleteJob(jobSchedulerConfiguration);
|
||||
} catch (SchedulerException e) {
|
||||
throw new RuntimeException("Failed to delete job", e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import java.io.IOException;
|
|||
import java.io.InputStreamReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -161,10 +162,10 @@ public class DashboardController extends GenericForwardComposer {
|
|||
|
||||
if ((lblAbsolute != null) && (absoluteMargin != null)) {
|
||||
lblAbsolute
|
||||
.setValue(String
|
||||
.format(_("There is a margin of %d days with the project global deadline (%.2f %%)."),
|
||||
absoluteMargin + 0,
|
||||
relativeMargin.doubleValue() * 100));
|
||||
.setValue(_(
|
||||
"There is a margin of {0} days with the project global deadline ({1}%).",
|
||||
absoluteMargin, (new DecimalFormat("#.##"))
|
||||
.format(relativeMargin.doubleValue() * 100)));
|
||||
} else {
|
||||
lblAbsolute.setValue(_("No project deadline defined"));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ public class ManualAllocationController extends GenericForwardComposer {
|
|||
public String getCurrentQueue() {
|
||||
if (getBeingEditedElement() == null
|
||||
|| getBeingEditedElement().getLimitingResourceQueue() == null) {
|
||||
return _("Unnasigned");
|
||||
return _("Unassigned");
|
||||
}
|
||||
return getBeingEditedElement().getLimitingResourceQueue().getResource()
|
||||
.getName();
|
||||
|
|
@ -582,7 +582,7 @@ public class ManualAllocationController extends GenericForwardComposer {
|
|||
public String getCurrentStart() {
|
||||
if (getBeingEditedElement() == null
|
||||
|| getBeingEditedElement().getStartDate() == null) {
|
||||
return _("Unnasigned");
|
||||
return _("Unassigned");
|
||||
}
|
||||
return getBeingEditedElement().getStartDate().toString();
|
||||
}
|
||||
|
|
@ -590,7 +590,7 @@ public class ManualAllocationController extends GenericForwardComposer {
|
|||
public String getCurrentEnd() {
|
||||
if (getBeingEditedElement() == null
|
||||
|| getBeingEditedElement().getEndDate() == null) {
|
||||
return _("Unnasigned");
|
||||
return _("Unassigned");
|
||||
}
|
||||
return getBeingEditedElement().getEndDate().toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,4 @@ public interface IOrderModel extends IIntegrationEntityModel {
|
|||
|
||||
User getUser();
|
||||
|
||||
boolean isJiraActivated();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.orders;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.libreplan.importers.IJiraOrderElementSynchronizer;
|
||||
import org.libreplan.importers.IJiraTimesheetSynchronizer;
|
||||
import org.libreplan.importers.SynchronizationInfo;
|
||||
import org.libreplan.importers.jira.IssueDTO;
|
||||
import org.libreplan.web.common.IMessagesForUser;
|
||||
import org.libreplan.web.common.Level;
|
||||
import org.libreplan.web.common.MessagesForUser;
|
||||
import org.libreplan.web.common.Util;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.SuspendNotAllowedException;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Combobox;
|
||||
import org.zkoss.zul.ListModel;
|
||||
import org.zkoss.zul.Popup;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
import org.zkoss.zul.Tab;
|
||||
import org.zkoss.zul.Textbox;
|
||||
import org.zkoss.zul.api.Groupbox;
|
||||
import org.zkoss.zul.api.Window;
|
||||
|
||||
/**
|
||||
* Controller for JIRA synchronization
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class JiraSynchronizationController extends GenericForwardComposer {
|
||||
|
||||
private static final org.apache.commons.logging.Log LOG = LogFactory
|
||||
.getLog(JiraSynchronizationController.class);
|
||||
|
||||
private OrderCRUDController orderController;
|
||||
|
||||
private Window editWindow;
|
||||
|
||||
private Groupbox jiraGroupBox;
|
||||
|
||||
private Popup jirasyncPopup;
|
||||
|
||||
private Button startJiraSyncButton, cancelJiraSyncButton,
|
||||
syncWithJiraButton;
|
||||
|
||||
private Textbox txtImportedLabel, txtLastSyncDate;
|
||||
|
||||
private Combobox comboJiraLabel;
|
||||
|
||||
private IMessagesForUser messagesForUser;
|
||||
|
||||
private Component messagesContainer;
|
||||
|
||||
@Autowired
|
||||
private IJiraOrderElementSynchronizer jiraOrderElementSynchronizer;
|
||||
|
||||
@Autowired
|
||||
private IJiraTimesheetSynchronizer jiraTimesheetSynchronizer;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
comp.setVariable("jiraSynchroniaztionController", this, true);
|
||||
loadComponentsEditWindow();
|
||||
showOrHideJiraEditWindow();
|
||||
updateOrderLastSyncInfoScreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current {@link Order}
|
||||
*/
|
||||
private Order getOrder() {
|
||||
return orderController.getOrder();
|
||||
}
|
||||
|
||||
private void loadComponentsEditWindow() {
|
||||
txtLastSyncDate = (Textbox) editWindow
|
||||
.getFellowIfAny("txtLastSyncDate");
|
||||
txtImportedLabel = (Textbox) editWindow
|
||||
.getFellowIfAny("txtImportedLabel");
|
||||
jiraGroupBox = (Groupbox) editWindow.getFellowIfAny("jiraGroupBox");
|
||||
syncWithJiraButton = (Button) editWindow
|
||||
.getFellow("syncWithJiraButton");
|
||||
messagesForUser = new MessagesForUser(messagesContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide <code>JiraEditWindow</code> based on JIRA
|
||||
* {@link Connector#isActivated()}
|
||||
*/
|
||||
private void showOrHideJiraEditWindow() {
|
||||
jiraGroupBox.setVisible(isJiraActivated());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UI text last synchronized date and the text imported label
|
||||
*/
|
||||
private void updateOrderLastSyncInfoScreen() {
|
||||
OrderSyncInfo orderSyncInfo = jiraOrderElementSynchronizer
|
||||
.getOrderLastSyncInfo(getOrder());
|
||||
|
||||
if (orderSyncInfo != null) {
|
||||
txtLastSyncDate.setValue(Util.formatDateTime(orderSyncInfo
|
||||
.getLastSyncDate()));
|
||||
txtImportedLabel.setValue(orderSyncInfo.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if jira is Activated. Used to show/hide Jira edit window
|
||||
*/
|
||||
public boolean isJiraActivated() {
|
||||
Connector connector = connectorDAO
|
||||
.findUniqueByName(PredefinedConnectors.JIRA.getName());
|
||||
if (connector == null) {
|
||||
return false;
|
||||
}
|
||||
return connector.isActivated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize with Jira
|
||||
*/
|
||||
public void syncWithJira() {
|
||||
try {
|
||||
List<String> items = jiraOrderElementSynchronizer
|
||||
.getAllJiraLabels();
|
||||
|
||||
if (!(txtImportedLabel.getText()).isEmpty()) {
|
||||
startSyncWithJira(txtImportedLabel.getText());
|
||||
return;
|
||||
}
|
||||
|
||||
setupJiraSyncPopup(editWindow, new SimpleListModelExt(items));
|
||||
|
||||
jirasyncPopup.open(syncWithJiraButton, "before_start");
|
||||
|
||||
} catch (ConnectorException e) {
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("Failed: {0}", e.getMessage()));
|
||||
} catch (WebApplicationException e) {
|
||||
LOG.info(e);
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("Cannot connect to JIRA server"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start synchronize with jira for the specified <code>label</code>
|
||||
*
|
||||
* @param label
|
||||
* the jira label
|
||||
*/
|
||||
public void startSyncWithJira(String label) {
|
||||
try {
|
||||
Order order = getOrder();
|
||||
|
||||
List<IssueDTO> issues = jiraOrderElementSynchronizer
|
||||
.getJiraIssues(label);
|
||||
|
||||
if (issues == null || issues.isEmpty()) {
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("No JIRA issues to import"));
|
||||
return;
|
||||
}
|
||||
|
||||
order.setCodeAutogenerated(false);
|
||||
|
||||
jiraOrderElementSynchronizer.syncOrderElementsWithJiraIssues(
|
||||
issues, order);
|
||||
|
||||
orderController.saveAndContinue(false);
|
||||
|
||||
jiraOrderElementSynchronizer.saveSyncInfo(label, order);
|
||||
|
||||
updateOrderLastSyncInfoScreen();
|
||||
|
||||
if (jirasyncPopup != null) {
|
||||
jirasyncPopup.close();
|
||||
}
|
||||
|
||||
jiraTimesheetSynchronizer.syncJiraTimesheetWithJiraIssues(issues,
|
||||
order);
|
||||
|
||||
showSyncInfo();
|
||||
|
||||
// Reload order info in all tabs
|
||||
Tab previousTab = orderController.getCurrentTab();
|
||||
orderController.initEdit(order);
|
||||
orderController.selectTab(previousTab.getId());
|
||||
} catch (ConnectorException e) {
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("Failed: {0}", e.getMessage()));
|
||||
} catch (WebApplicationException e) {
|
||||
LOG.info(e);
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("Cannot connect to JIRA server"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the success or failure info of synchronization
|
||||
*/
|
||||
private void showSyncInfo() {
|
||||
Map<String, Object> args = new HashMap<String, Object>();
|
||||
|
||||
SynchronizationInfo syncOrderElementInfo = jiraOrderElementSynchronizer
|
||||
.getSynchronizationInfo();
|
||||
|
||||
boolean succeeded = isSyncSucceeded(syncOrderElementInfo);
|
||||
|
||||
args.put("syncOrderElementSuccess", succeeded);
|
||||
if (syncOrderElementInfo != null) {
|
||||
args.put("syncOrderElementFailedReasons", new SimpleListModel(
|
||||
syncOrderElementInfo.getFailedReasons()));
|
||||
}
|
||||
|
||||
SynchronizationInfo jiraSyncInfoTimesheet = jiraTimesheetSynchronizer
|
||||
.getSynchronizationInfo();
|
||||
|
||||
succeeded = isSyncSucceeded(jiraSyncInfoTimesheet);
|
||||
|
||||
args.put("syncTimesheetSuccess", succeeded);
|
||||
if (jiraSyncInfoTimesheet != null) {
|
||||
args.put("syncTimesheetFailedReasons", new SimpleListModel(
|
||||
jiraSyncInfoTimesheet.getFailedReasons()));
|
||||
}
|
||||
|
||||
Window jiraSyncInfoWindow = (Window) Executions.createComponents(
|
||||
"/orders/_jiraSyncInfo.zul", null, args);
|
||||
|
||||
try {
|
||||
jiraSyncInfoWindow.doModal();
|
||||
} catch (SuspendNotAllowedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSyncSucceeded(SynchronizationInfo syncInfo) {
|
||||
if (syncInfo == null) {
|
||||
return false;
|
||||
}
|
||||
return syncInfo.isSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups the pop-up components
|
||||
*
|
||||
* @param comp
|
||||
* the compenent(editWidnow)
|
||||
* @param model
|
||||
* labels list model to render the combobox
|
||||
* <code>comboJiraLabel</code>
|
||||
*/
|
||||
private void setupJiraSyncPopup(Component comp, ListModel model) {
|
||||
|
||||
startJiraSyncButton = (Button) comp.getFellow("startJiraSyncButton");
|
||||
startJiraSyncButton.setLabel(_("Start sync"));
|
||||
|
||||
startJiraSyncButton.addEventListener(Events.ON_CLICK,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
startSyncWithJira(comboJiraLabel.getValue());
|
||||
}
|
||||
});
|
||||
cancelJiraSyncButton = (Button) comp.getFellow("cancelJiraSyncButton");
|
||||
cancelJiraSyncButton.setLabel(_("Cancel"));
|
||||
cancelJiraSyncButton.addEventListener(Events.ON_CLICK,
|
||||
new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
jirasyncPopup.close();
|
||||
}
|
||||
});
|
||||
comboJiraLabel = (Combobox) comp.getFellowIfAny("comboJiraLabel");
|
||||
comboJiraLabel.setModel(model);
|
||||
|
||||
jirasyncPopup = (Popup) comp.getFellow("jirasyncPopup");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This class provides case insensitive search for the {@link Combobox}.
|
||||
*/
|
||||
private class SimpleListModelExt extends SimpleListModel {
|
||||
|
||||
public SimpleListModelExt(List data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
public ListModel getSubModel(Object value, int nRows) {
|
||||
final String idx = value == null ? "" : objectToString(value);
|
||||
if (nRows < 0) {
|
||||
nRows = 10;
|
||||
}
|
||||
final LinkedList data = new LinkedList();
|
||||
for (int i = 0; i < getSize(); i++) {
|
||||
if (idx.equals("")
|
||||
|| entryMatchesText(getElementAt(i).toString(), idx)) {
|
||||
data.add(getElementAt(i));
|
||||
if (--nRows <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new SimpleListModelExt(data);
|
||||
}
|
||||
|
||||
public boolean entryMatchesText(String entry, String text) {
|
||||
return entry.toLowerCase().contains(text.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,20 +29,17 @@ import java.util.ConcurrentModificationException;
|
|||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.ws.rs.WebApplicationException;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.calendars.entities.BaseCalendar;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.externalcompanies.entities.DeadlineCommunication;
|
||||
import org.libreplan.business.externalcompanies.entities.DeliverDateComparator;
|
||||
|
|
@ -58,10 +55,6 @@ import org.libreplan.business.resources.entities.Criterion;
|
|||
import org.libreplan.business.templates.entities.OrderTemplate;
|
||||
import org.libreplan.business.users.entities.User;
|
||||
import org.libreplan.business.users.entities.UserRole;
|
||||
import org.libreplan.importers.IJiraOrderElementSynchronizer;
|
||||
import org.libreplan.importers.IJiraTimesheetSynchronizer;
|
||||
import org.libreplan.importers.JiraSyncInfo;
|
||||
import org.libreplan.importers.jira.IssueDTO;
|
||||
import org.libreplan.web.common.ConfirmCloseUtil;
|
||||
import org.libreplan.web.common.FilterUtils;
|
||||
import org.libreplan.web.common.IMessagesForUser;
|
||||
|
|
@ -92,7 +85,6 @@ import org.zkoss.ganttz.util.LongOperationFeedback;
|
|||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.Desktop;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.SuspendNotAllowedException;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
|
|
@ -110,9 +102,7 @@ import org.zkoss.zul.Datebox;
|
|||
import org.zkoss.zul.Grid;
|
||||
import org.zkoss.zul.Hbox;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.ListModel;
|
||||
import org.zkoss.zul.Messagebox;
|
||||
import org.zkoss.zul.Popup;
|
||||
import org.zkoss.zul.Row;
|
||||
import org.zkoss.zul.RowRenderer;
|
||||
import org.zkoss.zul.Rows;
|
||||
|
|
@ -202,6 +192,10 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
|
||||
private ProjectDetailsController projectDetailsController;
|
||||
|
||||
private JiraSynchronizationController jiraSynchronizationController;
|
||||
|
||||
private TimSynchronizationController timSynchronizationController;
|
||||
|
||||
@Autowired
|
||||
private IOrderDAO orderDAO;
|
||||
|
||||
|
|
@ -209,16 +203,6 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
|
||||
private EndDatesRenderer endDatesRenderer = new EndDatesRenderer();
|
||||
|
||||
@Autowired
|
||||
private IJiraOrderElementSynchronizer jiraOrderElementSynchronizer;
|
||||
|
||||
@Autowired
|
||||
private IJiraTimesheetSynchronizer jiraTimesheetSynchronizer;
|
||||
|
||||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
|
|
@ -821,7 +805,7 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
saveAndContinue(true);
|
||||
}
|
||||
|
||||
private void saveAndContinue(boolean showSaveMessage) {
|
||||
protected void saveAndContinue(boolean showSaveMessage) {
|
||||
|
||||
Order order = orderModel.getOrder();
|
||||
final boolean isNewObject = order.isNewObject();
|
||||
|
|
@ -930,11 +914,11 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
}
|
||||
}
|
||||
|
||||
private Tab getCurrentTab() {
|
||||
protected Tab getCurrentTab() {
|
||||
return selectedTab;
|
||||
}
|
||||
|
||||
private void selectTab(String str) {
|
||||
protected void selectTab(String str) {
|
||||
Tab tab = (Tab) editWindow.getFellowIfAny(str);
|
||||
if (tab != null) {
|
||||
tab.setSelected(true);
|
||||
|
|
@ -1082,6 +1066,12 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
}
|
||||
|
||||
public void initEdit(Order order) {
|
||||
checkUserCanRead(order);
|
||||
orderModel.initEdit(order, getDesktop());
|
||||
prepareEditWindow(_("Edit project"));
|
||||
}
|
||||
|
||||
public void checkUserCanRead(Order order) {
|
||||
if (!orderModel.userCanRead(order, SecurityUtils.getSessionUserLoginName())) {
|
||||
try {
|
||||
Messagebox.show(_("Sorry, you do not have permissions to access this project"),
|
||||
|
|
@ -1090,9 +1080,6 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
orderModel.initEdit(order, getDesktop());
|
||||
prepareEditWindow(_("Edit project"));
|
||||
}
|
||||
|
||||
public IOrderModel getOrderModel() {
|
||||
|
|
@ -1169,6 +1156,8 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
initializeCustomerComponent();
|
||||
reloadOrderDetailsTab();
|
||||
orderDatesHandler.chooseCurrentSchedulingMode();
|
||||
setupJiraSynchronizationController();
|
||||
setupTimSynchronizationController();
|
||||
}
|
||||
|
||||
public void reloadOrderDetailsTab() {
|
||||
|
|
@ -1876,167 +1865,32 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
loadLabels();
|
||||
}
|
||||
|
||||
private Popup jirasyncPopup;
|
||||
private Button startJiraSyncButton, cancelJiraSyncButton, syncWithJiraButton;
|
||||
private Combobox comboJiraLabel;
|
||||
|
||||
public boolean isJiraDeactivated() {
|
||||
return !configurationDAO.getConfigurationWithReadOnlyTransaction()
|
||||
.getJiraConfiguration().isJiraActivated();
|
||||
}
|
||||
|
||||
public void syncWithJira() {
|
||||
try {
|
||||
List<String> items = jiraOrderElementSynchronizer.getAllJiraLabels();
|
||||
|
||||
Textbox txtImportedLabel = (Textbox) editWindow
|
||||
.getFellowIfAny("txtImportedLabel");
|
||||
|
||||
if (!(txtImportedLabel.getText()).isEmpty()) {
|
||||
startSyncWithJira(txtImportedLabel.getText());
|
||||
return;
|
||||
}
|
||||
|
||||
setupJiraSyncPopup(editWindow, new SimpleListModelExt(items));
|
||||
|
||||
syncWithJiraButton = (Button) getCurrentTab().getFellow(
|
||||
"syncWithJiraButton");
|
||||
|
||||
jirasyncPopup.open(syncWithJiraButton, "before_start");
|
||||
|
||||
} catch (WebApplicationException e) {
|
||||
LOG.info(e);
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("Cannot connect to JIRA server"));
|
||||
/**
|
||||
* Setup the connector, JiraSynchronization controller
|
||||
*/
|
||||
public void setupJiraSynchronizationController() {
|
||||
if (jiraSynchronizationController == null) {
|
||||
jiraSynchronizationController = new JiraSynchronizationController();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void startSyncWithJira(String label) {
|
||||
try {
|
||||
Order order = getOrder();
|
||||
|
||||
List<IssueDTO> issues = jiraOrderElementSynchronizer
|
||||
.getJiraIssues(label);
|
||||
|
||||
order.setCodeAutogenerated(false);
|
||||
order.setImportedLabel(label);
|
||||
|
||||
jiraOrderElementSynchronizer.syncOrderElementsWithJiraIssues(
|
||||
issues, order);
|
||||
|
||||
saveAndContinue(false);
|
||||
if (jirasyncPopup != null) {
|
||||
jirasyncPopup.close();
|
||||
}
|
||||
|
||||
jiraTimesheetSynchronizer.syncJiraTimesheetWithJiraIssues(issues,
|
||||
order);
|
||||
|
||||
showSyncInfo();
|
||||
|
||||
// Reload order info in all tabs
|
||||
Tab previousTab = getCurrentTab();
|
||||
initEdit(order);
|
||||
selectTab(previousTab.getId());
|
||||
} catch (WebApplicationException e) {
|
||||
LOG.info(e);
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("Cannot connect to JIRA server"));
|
||||
}
|
||||
}
|
||||
|
||||
private void showSyncInfo() {
|
||||
Map<String, Object> args = new HashMap<String, Object>();
|
||||
|
||||
JiraSyncInfo jiraSyncInfoProgress = jiraOrderElementSynchronizer
|
||||
.getJiraSyncInfo();
|
||||
args.put("showSyncProgressSuccess",
|
||||
jiraSyncInfoProgress.isSyncSuccessful());
|
||||
args.put("jiraSyncProgressFailedReasons", new SimpleListModel(
|
||||
jiraSyncInfoProgress.getSyncFailedReasons()));
|
||||
|
||||
JiraSyncInfo jiraSyncInfoTimesheet = jiraTimesheetSynchronizer
|
||||
.getJiraSyncInfo();
|
||||
args.put("showSyncTimesheetSuccess",
|
||||
jiraSyncInfoTimesheet.isSyncSuccessful());
|
||||
args.put("jiraSyncTimesheetFailedReasons", new SimpleListModel(
|
||||
jiraSyncInfoTimesheet.getSyncFailedReasons()));
|
||||
|
||||
Window jiraSyncInfoWindow = (Window) Executions.createComponents(
|
||||
"/orders/_jiraSyncInfo.zul", null, args);
|
||||
|
||||
try {
|
||||
jiraSyncInfoWindow.doModal();
|
||||
} catch (SuspendNotAllowedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
jiraSynchronizationController.doAfterCompose(editWindow);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupJiraSyncPopup(Component comp, ListModel model) {
|
||||
|
||||
startJiraSyncButton = (Button) comp.getFellow("startJiraSyncButton");
|
||||
startJiraSyncButton.setLabel(_("Start sync"));
|
||||
|
||||
startJiraSyncButton.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
startSyncWithJira(comboJiraLabel.getValue());
|
||||
}
|
||||
});
|
||||
cancelJiraSyncButton = (Button) comp.getFellow("cancelJiraSyncButton");
|
||||
cancelJiraSyncButton.setLabel(_("Cancel"));
|
||||
cancelJiraSyncButton.addEventListener(Events.ON_CLICK, new EventListener() {
|
||||
|
||||
@Override
|
||||
public void onEvent(Event event) {
|
||||
jirasyncPopup.close();
|
||||
}
|
||||
});
|
||||
comboJiraLabel = (Combobox) comp.getFellowIfAny("comboJiraLabel");
|
||||
comboJiraLabel.setModel(model);
|
||||
|
||||
jirasyncPopup = (Popup) comp.getFellow("jirasyncPopup");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This class provides case insensitive search for the {@link Combobox}.
|
||||
* Setup the connector, TimSynchronization controller
|
||||
*/
|
||||
private class SimpleListModelExt extends SimpleListModel {
|
||||
|
||||
public SimpleListModelExt(List data) {
|
||||
super(data);
|
||||
public void setupTimSynchronizationController() {
|
||||
if (timSynchronizationController == null) {
|
||||
timSynchronizationController = new TimSynchronizationController();
|
||||
}
|
||||
|
||||
public ListModel getSubModel(Object value, int nRows) {
|
||||
final String idx = value == null ? "" : objectToString(value);
|
||||
if (nRows < 0) {
|
||||
nRows = 10;
|
||||
}
|
||||
final LinkedList data = new LinkedList();
|
||||
for (int i = 0; i < getSize(); i++) {
|
||||
if (idx.equals("")
|
||||
|| entryMatchesText(getElementAt(i).toString(), idx)) {
|
||||
data.add(getElementAt(i));
|
||||
if (--nRows <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new SimpleListModelExt(data);
|
||||
try {
|
||||
timSynchronizationController.doAfterCompose(editWindow);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
public boolean entryMatchesText(String entry, String text) {
|
||||
return entry.toLowerCase().contains(text.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isJiraActivated() {
|
||||
return orderModel.isJiraActivated();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,11 @@ import java.util.logging.Filter;
|
|||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.libreplan.business.common.daos.IConfigurationDAO;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.EntitySequence;
|
||||
import org.libreplan.business.common.entities.JiraConfiguration;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectorProperties;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.orders.entities.OrderLine;
|
||||
|
|
@ -126,7 +128,7 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
|
|||
private Popup filterOptionsPopup;
|
||||
|
||||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
public List<org.libreplan.business.labels.entities.Label> getLabels() {
|
||||
return orderModel.getLabels();
|
||||
|
|
@ -510,9 +512,17 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
|
|||
String code = orderElement.getCode();
|
||||
A hyperlink = new A(code);
|
||||
|
||||
String jiraUrl = configurationDAO.getConfigurationWithReadOnlyTransaction().getJiraConfiguration().getJiraUrl();
|
||||
Connector connector = connectorDAO
|
||||
.findUniqueByName(PredefinedConnectors.JIRA.getName());
|
||||
if (connector == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String codeWithoutPrefix = StringUtils.removeStart(code, JiraConfiguration.CODE_PREFIX);
|
||||
String jiraUrl = connector.getPropertiesAsMap().get(
|
||||
PredefinedConnectorProperties.SERVER_URL);
|
||||
|
||||
String codeWithoutPrefix = StringUtils.removeStart(code,
|
||||
PredefinedConnectorProperties.JIRA_CODE_PREFIX);
|
||||
codeWithoutPrefix = StringUtils.removeStart(codeWithoutPrefix,
|
||||
orderElement.getOrder().getCode()
|
||||
+ EntitySequence.CODE_SEPARATOR_CHILDREN);
|
||||
|
|
|
|||
|
|
@ -962,11 +962,4 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
|
|||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public boolean isJiraActivated() {
|
||||
return configurationDAO.getConfiguration().getJiraConfiguration()
|
||||
.isJiraActivated();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* This file is part of LibrePlan
|
||||
*
|
||||
* Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.libreplan.web.orders;
|
||||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.libreplan.business.common.daos.IConnectorDAO;
|
||||
import org.libreplan.business.common.entities.Connector;
|
||||
import org.libreplan.business.common.entities.ConnectorException;
|
||||
import org.libreplan.business.common.entities.PredefinedConnectors;
|
||||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderSyncInfo;
|
||||
import org.libreplan.importers.IExportTimesheetsToTim;
|
||||
import org.libreplan.importers.SynchronizationInfo;
|
||||
import org.libreplan.web.common.IMessagesForUser;
|
||||
import org.libreplan.web.common.Level;
|
||||
import org.libreplan.web.common.MessagesForUser;
|
||||
import org.libreplan.web.common.Util;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.zkoss.zk.ui.Component;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.SuspendNotAllowedException;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.SimpleListModel;
|
||||
import org.zkoss.zul.Textbox;
|
||||
import org.zkoss.zul.api.Groupbox;
|
||||
import org.zkoss.zul.api.Window;
|
||||
|
||||
/**
|
||||
* Controller for Tim synchronization
|
||||
*
|
||||
* @author Miciele Ghiorghis <m.ghiorghis@antoniusziekenhuis.nl>
|
||||
*/
|
||||
public class TimSynchronizationController extends GenericForwardComposer {
|
||||
|
||||
private static final org.apache.commons.logging.Log LOG = LogFactory
|
||||
.getLog(TimSynchronizationController.class);
|
||||
|
||||
private OrderCRUDController orderController;
|
||||
|
||||
private Window editWindow;
|
||||
|
||||
private Groupbox timGroupBox;
|
||||
|
||||
private Textbox txtProductCode;
|
||||
|
||||
private Label labelProductCode, labelLastSyncDate;
|
||||
|
||||
@Autowired
|
||||
private IExportTimesheetsToTim exportTimesheetsToTim;
|
||||
|
||||
@Autowired
|
||||
private IConnectorDAO connectorDAO;
|
||||
|
||||
private Component messagesContainer;
|
||||
|
||||
private IMessagesForUser messagesForUser;
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
comp.setVariable("timSynchronizationController", this, true);
|
||||
loadComponentsEditWindow(comp);
|
||||
showOrHideTimEditWindow();
|
||||
updateOrderLastSyncInfoScreen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current {@link Order}
|
||||
*/
|
||||
private Order getOrder() {
|
||||
return orderController.getOrder();
|
||||
}
|
||||
|
||||
private void loadComponentsEditWindow(Component comp) {
|
||||
txtProductCode = (Textbox) comp.getFellowIfAny("txtProductCode");
|
||||
labelLastSyncDate = (Label) comp
|
||||
.getFellowIfAny("labelLastSyncDate");
|
||||
labelProductCode = (Label) comp
|
||||
.getFellowIfAny("labelProductCode");
|
||||
timGroupBox = (Groupbox) comp.getFellowIfAny("timGroupBox");
|
||||
|
||||
messagesForUser = new MessagesForUser(messagesContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide <code>TimEditWindow</code> based on Tim
|
||||
* {@link Connector#isActivated()}
|
||||
*/
|
||||
private void showOrHideTimEditWindow() {
|
||||
timGroupBox.setVisible(isTimActivated());
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UI text last synchronized date and the text product code
|
||||
*/
|
||||
private void updateOrderLastSyncInfoScreen() {
|
||||
OrderSyncInfo orderSyncInfo = exportTimesheetsToTim
|
||||
.getOrderLastSyncInfo(getOrder());
|
||||
if (orderSyncInfo != null) {
|
||||
labelLastSyncDate.setValue(Util.formatDateTime(orderSyncInfo
|
||||
.getLastSyncDate()));
|
||||
labelProductCode.setValue("(" + orderSyncInfo.getKey() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Tim is Activated. Used to show/hide Tim edit window
|
||||
*/
|
||||
public boolean isTimActivated() {
|
||||
Connector connector = connectorDAO
|
||||
.findUniqueByName(PredefinedConnectors.TIM.getName());
|
||||
if (connector == null) {
|
||||
return false;
|
||||
}
|
||||
return connector.isActivated();
|
||||
}
|
||||
|
||||
public void startExportToTim() {
|
||||
txtProductCode.setConstraint("no empty:" + _("cannot be empty"));
|
||||
try {
|
||||
exportTimesheetsToTim.exportTimesheets(txtProductCode.getValue(),
|
||||
getOrder());
|
||||
|
||||
updateOrderLastSyncInfoScreen();
|
||||
|
||||
shwoImpExpInfo();
|
||||
|
||||
} catch (ConnectorException e) {
|
||||
messagesForUser.showMessage(Level.ERROR,
|
||||
_("Exporting timesheets to Tim failed. Check the Tim connector"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void shwoImpExpInfo() {
|
||||
Map<String, Object> args = new HashMap<String, Object>();
|
||||
|
||||
SynchronizationInfo synchronizationInfo = exportTimesheetsToTim.getSynchronizationInfo();
|
||||
args.put("action", synchronizationInfo.getAction());
|
||||
args.put("showSuccess", synchronizationInfo.isSuccessful());
|
||||
args.put("failedReasons",
|
||||
new SimpleListModel(synchronizationInfo.getFailedReasons()));
|
||||
|
||||
Window timImpExpInfoWindow = (Window) Executions.createComponents(
|
||||
"/orders/_timImpExpInfo.zul", null, args);
|
||||
|
||||
try {
|
||||
timImpExpInfoWindow.doModal();
|
||||
} catch (SuspendNotAllowedException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -273,6 +273,8 @@ public class PlanningTabCreator {
|
|||
breadcrumbs.appendChild(new Label(_("Project Scheduling")));
|
||||
if (mode.isOf(ModeType.ORDER)) {
|
||||
|
||||
orderPlanningController.getOrderCRUDController()
|
||||
.checkUserCanRead(order);
|
||||
Label nameLabel = new Label(order.getName());
|
||||
nameLabel.setTooltiptext(order.getName() + "."
|
||||
+ order.getDescription());
|
||||
|
|
|
|||
|
|
@ -5395,10 +5395,8 @@ msgid "Progress Evolution"
|
|||
msgstr "Evolución del progreso"
|
||||
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java:165
|
||||
msgid ""
|
||||
"There is a margin of %d days with the project global deadline (%.2f %%)."
|
||||
msgstr ""
|
||||
"Hay un margen de %d días con la fecha límite global del proyecto (%.2f %%)."
|
||||
msgid "There is a margin of {0} days with the project global deadline ({1}%)."
|
||||
msgstr "Hay un margen de {0} días con la fecha límite global del proyecto ({1}%)."
|
||||
|
||||
#: libreplan-webapp/src/main/webapp/planner/taskpanels/_tabPanelNonLimitingResourceAllocation.zul:91
|
||||
msgid "Original"
|
||||
|
|
|
|||
|
|
@ -5156,9 +5156,8 @@ msgid ""
|
|||
msgstr "Os valores de subcontratación son de só lectura porque foron notificados pola empresa subcontratista."
|
||||
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java:165
|
||||
msgid ""
|
||||
"There is a margin of %d days with the project global deadline (%.2f %%)."
|
||||
msgstr "Hai unha marxe de %d días coa data límite global do proxecto (%.2f %%)."
|
||||
msgid "There is a margin of {0} days with the project global deadline ({1}%)."
|
||||
msgstr "Hai unha marxe de {0} días coa data límite global do proxecto ({1}%)."
|
||||
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/EarnedValueChartFiller.java:250
|
||||
msgid "CV"
|
||||
|
|
|
|||
|
|
@ -5203,7 +5203,7 @@ msgstr ""
|
|||
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java:165
|
||||
msgid ""
|
||||
"There is a margin of %d days with the project global deadline (%.2f %%)."
|
||||
"There is a margin of {0} days with the project global deadline ({1}%)."
|
||||
msgstr ""
|
||||
|
||||
#: libreplan-webapp/src/main/webapp/planner/taskpanels/_tabPanelNonLimitingResourceAllocation.zul:91
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# LibrePlan - Webapp module.
|
||||
# LibrePlae - Webapp module.
|
||||
# Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
# Desenvolvemento Tecnolóxico de Galicia
|
||||
# Copyright (C) 2010-2012 Igalia, S.L.
|
||||
|
|
@ -72,7 +72,7 @@ msgid "Create Virtual Worker"
|
|||
msgstr "创建虚拟工作人员"
|
||||
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/workreports/WorkReportCRUDController.java:862
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/tree/TreeComponent.java:105
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/tree/TreeComponent.java:104
|
||||
#: libreplan-webapp/src/main/webapp/labels/_editLabelType.zul:81
|
||||
#: libreplan-webapp/src/main/webapp/labels/_listLabelTypes.zul:28
|
||||
#: libreplan-webapp/src/main/webapp/advance/_listAdvanceTypes.zul:30
|
||||
|
|
@ -5156,8 +5156,8 @@ msgstr "阅读不仅是因为他们的报告由分包商公司的分包商值。
|
|||
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardController.java:165
|
||||
msgid ""
|
||||
"There is a margin of %d days with the project global deadline (%.2f %%)."
|
||||
msgstr "总项目的截止日期(%.2f %%)前有%d天的余量。"
|
||||
"There is a margin of {0} days with the project global deadline ({1}%)."
|
||||
msgstr "总项目的截止日期({1}%)前有{0}天的余量。"
|
||||
|
||||
#: libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/EarnedValueChartFiller.java:250
|
||||
msgid "CV"
|
||||
|
|
|
|||
|
|
@ -49,6 +49,16 @@
|
|||
class="org.libreplan.web.scenarios.CurrentUserScenarioAwareManager"
|
||||
scope="singleton"/>
|
||||
|
||||
<!-- Scheduler -->
|
||||
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" />
|
||||
|
||||
<bean id="schedulerManager"
|
||||
class="org.libreplan.importers.SchedulerManager"
|
||||
scope="singleton"
|
||||
init-method="scheduleJobs">
|
||||
<property name="scheduler" ref="schedulerFactoryBean"/>
|
||||
</bean>
|
||||
|
||||
<context:component-scan base-package="org.libreplan"/>
|
||||
|
||||
<!-- CXF -->
|
||||
|
|
|
|||
167
libreplan-webapp/src/main/webapp/common/_editJobScheduling.zul
Normal file
167
libreplan-webapp/src/main/webapp/common/_editJobScheduling.zul
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
<!--
|
||||
This file is part of LibrePlan
|
||||
|
||||
Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<window id="${arg.id}">
|
||||
<caption id="caption" sclass="caption-title" />
|
||||
<grid id="jobSchedulerGrid" fixedLayout="true">
|
||||
<columns>
|
||||
<column width="200px" />
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="${i18n:_('Job group')}" />
|
||||
<textbox id="jobGroupTextBox" width="400px"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
value="@{controller.jobSchedulerConfiguration.jobGroup}"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Job name')}" />
|
||||
<textbox id="jobNameTextBox" width="400px"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
value="@{controller.jobSchedulerConfiguration.jobName}"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Cron expression')}" />
|
||||
<hbox>
|
||||
<textbox id="cronExpressionTextBox"
|
||||
value="@{controller.jobSchedulerConfiguration.cronExpression}"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
width="400px" disabled="true"/>
|
||||
<button sclass="icono" image="/common/img/ico_editar1.png"
|
||||
hoverImage="/common/img/ico_editar.png"
|
||||
tooltiptext="${i18n:_('Edit')}"
|
||||
onClick="controller.openPopup()"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Job class name')}" />
|
||||
<combobox id="jobCombo" autodrop="true" width="400px"
|
||||
constraint="no empty:${i18n:_('cannot be empty')}"
|
||||
model="@{controller.jobNames}"
|
||||
selectedItem="@{controller.jobSchedulerConfiguration.jobClassName}">
|
||||
<comboitem
|
||||
self="@{each=jobNames}"
|
||||
label="@{jobNames.name}"
|
||||
value="@{jobNames}" />
|
||||
</combobox>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Connector')}" />
|
||||
<combobox id="connectorCombo" autodrop="true" width="400px"
|
||||
model="@{controller.connectorNames}"
|
||||
selectedItem="@{controller.jobSchedulerConfiguration.connectorName}">
|
||||
<comboitem
|
||||
self="@{each=connectorNames}"
|
||||
label="@{connectorNames.name}"
|
||||
value="@{connectorNames}" />
|
||||
</combobox>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Schedule')}" />
|
||||
<checkbox checked="@{controller.jobSchedulerConfiguration.schedule}" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<!-- Control buttons -->
|
||||
<button onClick="controller.saveAndExit()"
|
||||
label="${i18n:_('Save')}"
|
||||
sclass="save-button global-action" />
|
||||
<button onClick="controller.saveAndContinue()"
|
||||
label="${i18n:_('Save and Continue')}"
|
||||
sclass="save-button global-action" />
|
||||
<button onClick="controller.cancelForm()"
|
||||
label="${i18n:_('Cancel')}"
|
||||
sclass="cancel-button global-action" />
|
||||
|
||||
<div>
|
||||
<groupbox closable="false" >
|
||||
<caption label="${i18n:_('Cron expression format')}" />
|
||||
<grid width="500px">
|
||||
<columns>
|
||||
<column label="${i18n:_('Field')}" width="150px"/>
|
||||
<column label="${i18n:_('Allowed values')}" />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="${i18n:_('Seconds')}"/>
|
||||
<label value="0-59"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Minutes')}"/>
|
||||
<label value="0-59"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Hours')}"/>
|
||||
<label value="0-23"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Day of month')}"/>
|
||||
<label value="1-31"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Month')}"/>
|
||||
<span>1-12 (<label value="${i18n:_('or names')}"/> [JAN-DEC])</span>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Day of week')}"/>
|
||||
<span>0-7 (<label value="${i18n:_('0 or 7 is Sunday, or use names')}"/> [SUN-SAT])</span>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Year (optional)')}"/>
|
||||
<label value="1970-2099"/>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<div>
|
||||
${i18n:_("For more details on cron expression click")}
|
||||
<a href="http://www.manpagez.com/man/5/crontab/">${i18n:_('here')}.</a>
|
||||
</div>
|
||||
</groupbox>
|
||||
</div>
|
||||
|
||||
<popup id="cronExpressionInputPopup" width="525px">
|
||||
<label id="jobGroup" value="@{jobSchedulerController.jobGroup}"/>
|
||||
<label id="jobName" value="@{jobSchedulerController.jobName}"/>
|
||||
<grid id="cronExpressionGrid">
|
||||
<columns>
|
||||
<column label="${i18n:_('Seconds')}"/>
|
||||
<column label="${i18n:_('Minutes')}" />
|
||||
<column label="${i18n:_('Hours')}"/>
|
||||
<column label="${i18n:_('Day of month')}"/>
|
||||
<column label="${i18n:_('Month')}"/>
|
||||
<column label="${i18n:_('Day of week')}"/>
|
||||
<column label="${i18n:_('Year')}"/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<textbox id="cronExpressionSeconds" width="60px" />
|
||||
<textbox id="cronExpressionMinutes" width="60px" />
|
||||
<textbox id="cronExpressionHours" width="60px" />
|
||||
<textbox id="cronExpressionDayOfMonth" width="60px" />
|
||||
<textbox id="cronExpressionMonth" width="60px" />
|
||||
<textbox id="cronExpressionDayOfWeek" width="60px" />
|
||||
<textbox id="cronExpressionYear" width="60px" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<button onClick="controller.updateCronExpression();" label="${i18n:_('OK')}" />
|
||||
<button onClick="controller.cancelPopup();" label="${i18n:_('Cancel')}" />
|
||||
</popup>
|
||||
</window>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<!--
|
||||
This file is part of LibrePlan
|
||||
|
||||
Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<window id="${arg.id}" title="${i18n:_('Job Scheduling List')}">
|
||||
|
||||
<grid id="listJobSchedulings"
|
||||
rowRenderer="@{controller.jobSchedulingRenderer}"
|
||||
model="@{controller.jobSchedulerConfigurations}"
|
||||
mold="paging" pageSize="10" fixedLayout="true">
|
||||
<columns>
|
||||
<column label="${i18n:_('Job group')}" />
|
||||
<column label="${i18n:_('Job name')}" />
|
||||
<column label="${i18n:_('Cron expression')}" />
|
||||
<column label="${i18n:_('Next fire time')}" />
|
||||
<column label="${i18n:_('Operations')}" />
|
||||
</columns>
|
||||
</grid>
|
||||
<button label="${i18n:_('Create')}" onClick="controller.goToCreateForm()"
|
||||
sclass="create-button-global-action"/>
|
||||
</window>
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
<tab label="${i18n:_('Main preferences')}" />
|
||||
<tab label="${i18n:_('Entity sequences')}" />
|
||||
<tab label="${i18n:_('LDAP configuration')}" />
|
||||
<tab label="${i18n:_('JIRA connector')}" />
|
||||
<tab label="${i18n:_('Connectors')}" />
|
||||
</tabs>
|
||||
<tabpanels>
|
||||
<tabpanel id="panelConfiguration">
|
||||
|
|
@ -414,47 +414,35 @@
|
|||
</vbox>
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
|
||||
<tabpanel id="panelJiraConfiguration">
|
||||
<grid>
|
||||
<columns>
|
||||
<column width="200px" />
|
||||
<column />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label value="${i18n:_('Activated')}" />
|
||||
<checkbox id="jiraActivated" checked="@{configurationController.jiraConfiguration.jiraActivated}" width="300px" />
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('JIRA URL')}" />
|
||||
<textbox id="jiraURL" value="@{configurationController.jiraConfiguration.jiraUrl}" width="300px"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('JIRA sync account')}" />
|
||||
<textbox id="jiraSyncAccount" value="@{configurationController.jiraConfiguration.jiraUserId}" width="300px"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('JIRA sync password')}" />
|
||||
<textbox id="jiraSyncPassword" value="@{configurationController.jiraConfiguration.jiraPassword}" type="password" width="300px"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('JIRA labels: comma-separated list of labels or URL')}" />
|
||||
<textbox id="jiraLabels" value="@{configurationController.jiraConfiguration.jiraLabels}" width="600px"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Hours type for JIRA connector')}" />
|
||||
<bandboxSearch
|
||||
finder="TypeOfWorkHoursBandboxFinder"
|
||||
selectedElement="@{configurationController.jiraConnectorTypeOfWorkHours, access='both'}" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<separator />
|
||||
<tabpanel id="panelConnectors">
|
||||
<groupbox style="margin-top: 5px" closable="false">
|
||||
<caption label="${i18n:_('Application properties')}" />
|
||||
<vbox>
|
||||
<hbox pack="center">
|
||||
<label value="${i18n:_('Select connector')}" />
|
||||
<combobox id="connectorCombo" autodrop="true"
|
||||
model="@{configurationController.connectors}"
|
||||
selectedItem="@{configurationController.selectedConnector}">
|
||||
<comboitem
|
||||
self="@{each=connectors}"
|
||||
label="@{connectors.name}"
|
||||
value="@{connectors}" />
|
||||
</combobox>
|
||||
</hbox>
|
||||
<separator />
|
||||
<grid id="connectorPropertriesGrid"
|
||||
model="@{configurationController.connectorPropertries}"
|
||||
rowRenderer="@{configurationController.connectorPropertriesRenderer}">
|
||||
<columns>
|
||||
<column label="${i18n:_('Name')}" width="200px"/>
|
||||
<column label="${i18n:_('Value')}" />
|
||||
</columns>
|
||||
</grid>
|
||||
</vbox>
|
||||
<separator />
|
||||
<button label="${i18n:_('Test connection')}"
|
||||
onClick="configurationController.testJiraConnection()" />
|
||||
<separator />
|
||||
|
||||
onClick="configurationController.testConnection()" />
|
||||
</groupbox>
|
||||
</tabpanel>
|
||||
</tabpanels>
|
||||
</tabbox>
|
||||
|
|
|
|||
38
libreplan-webapp/src/main/webapp/common/job_scheduling.zul
Normal file
38
libreplan-webapp/src/main/webapp/common/job_scheduling.zul
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<!--
|
||||
This file is part of LibrePlan
|
||||
|
||||
Copyright (C) 2013 St. Antoniusziekenhuis
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<?page id="jobSchedulingList" title="${i18n:_('LibrePlan: Job Scheduling')}" ?>
|
||||
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
|
||||
<?init class="org.zkoss.zk.ui.util.Composition" arg0="/common/layout/template.zul"?>
|
||||
|
||||
<?link rel="shortcut icon" href="/common/img/favicon.ico" type="image/x-icon"?>
|
||||
<?link rel="stylesheet" type="text/css" href="/common/css/libreplan.css"?>
|
||||
<?link rel="stylesheet" type="text/css" href="/common/css/libreplan_zk.css"?>
|
||||
|
||||
<?component name="list" inline="true" macroURI="_listJobScheduling.zul"?>
|
||||
<?component name="edit" inline="true" macroURI="_editJobScheduling.zul"?>
|
||||
|
||||
<zk>
|
||||
<window self="@{define(content)}"
|
||||
apply="org.libreplan.web.common.JobSchedulerController">
|
||||
<vbox id="messagesContainer" />
|
||||
<list id="listWindow" />
|
||||
<edit id="editWindow" />
|
||||
</window>
|
||||
</zk>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue