gt:         if (header != null) {
context: /*
   * Copyright (C) 2000 - 2021 Silverpeas
   *
   * 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.
   *
   * As a special exception to the terms and conditions of version 3.0 of
   * the GPL, you may redistribute this Program in connection with Free/Libre
   * Open Source Software ("FLOSS") applications as described in Silverpeas's
   * FLOSS exception.  You should have received a copy of the text describing
   * the FLOSS exception, and it is also available here:
   * "https://www.silverpeas.org/legal/floss_exception.html"
   *
   * 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.silverpeas.core.personalorganizer.service;
  
  import org.silverpeas.core.admin.component.ComponentInstanceDeletion;
  import org.silverpeas.core.annotation.Service;
  import org.silverpeas.core.index.indexing.model.FullIndexEntry;
  import org.silverpeas.core.index.indexing.model.IndexEngineProxy;
  import org.silverpeas.core.index.indexing.model.IndexEntryKey;
  import org.silverpeas.core.persistence.jdbc.DBUtil;
  import org.silverpeas.core.persistence.jdbc.sql.JdbcSqlQuery;
  import org.silverpeas.core.personalorganizer.model.Attendee;
  import org.silverpeas.core.personalorganizer.model.Category;
  import org.silverpeas.core.personalorganizer.model.HolidayDetail;
  import org.silverpeas.core.personalorganizer.model.JournalHeader;
  import org.silverpeas.core.personalorganizer.model.ParticipationStatus;
  import org.silverpeas.core.personalorganizer.model.Schedulable;
  import org.silverpeas.core.personalorganizer.model.SchedulableCount;
  import org.silverpeas.core.personalorganizer.model.ToDoHeader;
  import org.silverpeas.core.personalorganizer.model.TodoDetail;
  import org.silverpeas.core.personalorganizer.socialnetwork.SocialInformationEvent;
  import org.silverpeas.core.util.ArrayUtil;
  import org.silverpeas.core.util.SilverpeasList;
  import org.silverpeas.core.util.logging.SilverLogger;
  
  import javax.inject.Inject;
  import javax.transaction.Transactional;
  import java.sql.Connection;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Statement;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Date;
  import java.util.List;
  import java.util.Map;
  import java.util.function.Consumer;
  import java.util.stream.Collectors;
  
  import static java.util.Collections.emptyList;
  
  /**
   * Calendar service layer to manager calendars in Silverpeas
   */
  @Service
  @Transactional(Transactional.TxType.SUPPORTS)
  public class DefaultCalendarService implements SilverpeasCalendar, ComponentInstanceDeletion {
  
    private static final String CANNOT_GET_JOURNALS_OF_USER = "Cannot get journals of user ";
    private static final String NO_SUCH_JOURNAL = "No such journal ";
    private static final String ERROR_WHILE_PARSING_THE_DATES_OF_A_JOURNAL =
        "Error while parsing the dates of a journal";
    private static final String IDX_USER_PREFIX = "user@";
    private static final String CANNOT_GET_JOURNALS = "Cannot get journals";
    @Inject
    private JournalDAO journalDAO;
  
    // private methods to use in all this ejb methods
    private Connection getConnection() {
      try {
        return DBUtil.openConnection();
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot open connection");
      }
    }
  
    /**
     * methods for unresponded messages
     * @param userId the user identifier
     * @return
     */
    @Override
    public boolean hasTentativeSchedulablesForUser(String userId) {
  
      Connection con = getConnection();
      try {
        return getJournalDAO().hasTentativeJournalsForUser(con, userId);
      } catch (Exception e) {
        throw new CalendarRuntimeException(CANNOT_GET_JOURNALS_OF_USER + userId, e);
  
      } finally {
        DBUtil.close(con);
      }
    }
  
    @Override
    public Collection<JournalHeader> getTentativeSchedulablesForUser(String userId) {
  
      Connection con = getConnection();
      try {
        return getJournalDAO().getTentativeJournalHeadersForUser(con, userId);
      } catch (Exception e) {
        throw new CalendarRuntimeException(CANNOT_GET_JOURNALS_OF_USER + userId, e);
      } finally {
        DBUtil.close(con);
      }
    }
  
    /**
     * @param userId the user identifier
     * @return
     */
    @Override
    public SilverpeasList<ToDoHeader> getNotCompletedToDosForUser(String userId) {
      try {
        return ToDoDAO.getNotCompletedToDoHeadersForUser(userId);
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot get todos of user " + userId, e);
      }
    }
  
    @Override
    public List<String> getAllToDoForUser(final String userId) {
      try {
        return ToDoDAO.getAllTodoByUser(userId);
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot get todos of user " + userId, e);
      }
    }
  
    @Override
    public SilverpeasList<ToDoHeader> getOrganizerToDos(String organizerId) {
      try {
        return ToDoDAO.getOrganizerToDoHeaders(organizerId);
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot get journals from organizer " + organizerId, e);
      }
    }
  
    @Override
    public SilverpeasList<ToDoHeader> getClosedToDos(String organizerId) {
      try {
        return ToDoDAO.getClosedToDoHeaders(organizerId);
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot get journals from organizer " + organizerId, e);
      }
    }
  
    @Override
    public Collection<ToDoHeader> getExternalTodos(String spaceId, String componentId,
        String externalId) {
      try {
        return ToDoDAO.getToDoHeadersByExternalId(componentId, externalId);
      } catch (Exception e) {
        throw new CalendarRuntimeException(
            "Cannot get journals in space " + spaceId + ", application " + componentId +
                ", and external resource " + externalId, e);
      }
    }
  
    @Override
    public ToDoHeader getToDoHeader(String todoId) {
      try {
        return ToDoDAO.getToDoHeader(todoId);
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot get the todo " + todoId, e);
      }
    }
  
    @Override
    public TodoDetail getTodoDetail(String id) {
      try {
        TodoDetail detail =  TodoDetail.fromToDoHeader(getToDoHeader(id));
        List<Attendee> attendees = new ArrayList<>(getToDoAttendees(id));
        detail.setAttendees(attendees);
        return detail;
      } catch (Exception e) {
        SilverLogger.getLogger(this).error(e.getMessage(), e);
        return null;
      }
    }
  
    private Collection<ToDoHeader> getToDoHeadersByInstanceId(String instanceId) {
      try {
        return ToDoDAO.getToDoHeadersByInstanceId(instanceId);
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot get todos in application " + instanceId, e);
      }
    }
  
    @Override
    @Transactional(Transactional.TxType.REQUIRED)
    public void updateToDo(ToDoHeader todo) {
      checkTodo(todo);
  
      Connection con = getConnection();
      try {
        ToDoDAO.updateToDo(con, todo); // SQLEXCeption
  
        createIndex(todo, todo.getDelegatorId()); // vide
        Collection<Attendee> attendees = getToDoAttendees(todo.getId());
        for (Attendee attendee : attendees) {
          createIndex(todo, attendee.getUserId()); // vide
        }
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot update the todo " + todo.getId(), e);
      } finally {
        DBUtil.close(con);
      }
    }
  
    private void checkTodo(final ToDoHeader todo) {
      if (todo.getName() == null) {
        throw new CalendarRuntimeException("Todo's name is null!");
      }
      if (todo.getDelegatorId() == null) {
        throw new CalendarRuntimeException("Todo's delegator is null!");
      }
      if (todo.getEndDate() != null && todo.getStartDate() != null &&
          todo.getStartDate().after(todo.getEndDate())) {
        throw new CalendarRuntimeException("The todo period is incorrect!");
      }
    }
  
    @Override
    @Transactional(Transactional.TxType.REQUIRED)
    public String addToDo(ToDoHeader todo) {
      checkTodo(todo);
      Connection con = getConnection();
      try {
        String result = ToDoDAO.addToDo(con, todo);
        todo.setId(result);
        createIndex(todo, todo.getDelegatorId());
        return result;
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot create new todo", e);
      } finally {
        DBUtil.close(con);
      }
    }
  
    @Override
    @Transactional(Transactional.TxType.REQUIRED)
    public String addToDo(TodoDetail todo) {
      try {
        ToDoHeader header = ToDoHeader.fromTodoDetail(todo);
        String id = addToDo(header);
        if (todo.getAttendees() != null) {
          for (Attendee attendee : todo.getAttendees()) {
            addToDoAttendee(id, attendee);
          }
        }
        return id;
      } catch (Exception e) {
        SilverLogger.getLogger(this).error(e.getMessage(), e);
        return null;
      }
    }
  
    @Override
    @Transactional(Transactional.TxType.REQUIRED)
    public void removeToDo(String id) {
      // get the detail for desindexation
      ToDoHeader todo = getToDoHeader(id);
      try {
        // remove attendees and associated indexes
        setToDoAttendees(id, ArrayUtil.emptyStringArray());
        ToDoDAO.removeToDo(id);
      } catch (Exception e) {
        throw new CalendarRuntimeException("Cannot delete todo " + id, e);
      }
      removeIndex(todo, todo.getDelegatorId());
    }
  
    @Override
    @Transactional(Transactional.TxType.REQUIRED)
    public void removeToDoFromExternal(String spaceId, String componentId, String externalId) {
      try {
        Collection<ToDoHeader> headers = getExternalTodos(spaceId, componentId, externalId);
        for (ToDoHeader header : headers) {
          removeToDo(header.getId());
        }
      } catch (Exception e) {
        SilverLogger.getLogger(this).error(e.getMessage(), e);
      }
    }
  
    @Override
    @Transactional(Transactional.TxType.REQUIRED)
    public void removeAttendeeInToDoFromExternal(String componentId, String externalId,
        String userId) {
      try {
        Attendee attendee = new Attendee();
        attendee.setUserId(userId);
  
        Collection<ToDoHeader> headers = getExternalTodos("useless", componentId, externalId);
        for (ToDoHeader header : headers) {
  