日をまたいだスケジュールの登録(データベースへの登録・表示)

1. データベースへの登録

ScheduleFormDaraはフォームデータを管理するための抽象クラスであるAbstractFormDataを継承している。
前回修正が必要と考えたメソッドの機能について、抽象クラスまで戻って考えてみた。

  • setFormData()
    AbstractFormData.javaのデータに値をセットするメソッドsetFormData()をオーバーライドしたもの。

  • insertFormData()
    AbstractFormData.javaのデータを新規登録する抽象メソッドinsertFormData()をオーバーライドしたもの。
    実装は継承側で行う。

  • loadFormData()
    AbstractFormData.javaのデータを読み込む抽象メソッドであるloadFormData()をオーバーライドしたもの。
    実装は継承側で行う。

loadFormData()はデータを読み込むものであるので、修正の必要はないと判断した。

JavaDocを見てみると、スケジュールの登録は/aipo/portlets/schedule/src/main/java/com/aimluck/eip/modules/actions/schedule/ScheduleAction.javaのdoSchedule_insert()から行われているようである。
このメソッドの最初でScheduleFormData型のインスタンスが生成され、doInsert()が呼び出されていることから判断した。

public void doSchedule_insert(RunData rundata, Context context) {
    try {
      ScheduleFormData formData = new ScheduleFormData();
      formData.initField();

      // ブラウザ名を受け渡す.
      boolean isMsie = ALEipUtils.isMsieBrowser(rundata);
      context.put("isMeie", Boolean.valueOf(isMsie));

      String afterBehavior = rundata.getRequest().getParameter(AFTER_BEHAVIOR);
      setTemplate(rundata, "schedule-form");
      if (formData.doInsert(this, rundata, context)) {
        if ("1".equals(afterBehavior)) {
          JetspeedLink jsLink = JetspeedLinkFactory.getInstance(rundata);
          rundata.setRedirectURI(jsLink.getPortletById(
            ALEipUtils.getPortlet(rundata, context).getID()).addQueryData(
            "action",
            "controls.Restore").toString());
          rundata.getResponse().sendRedirect(rundata.getRedirectURI());
          jsLink = null;
        } else {
          doSchedule_list(rundata, context);
          // rundata.setRedirectURI(jsLink.getPortletById(
          // ALEipUtils.getPortlet(rundata, context).getID()).addQueryData(
          // "eventSubmit_doSchedule_list", "1").toString());
        }

      } else {
        if ("1".equals(afterBehavior)) {
          // 追加処理後にノーマル画面に画面遷移することを指定.
          context.put(AFTER_BEHAVIOR, "1");
        }
      }
    } catch (Exception ex) {
      logger.error("[ScheduleAction] Exception.", ex);
      ALEipUtils.redirectDBError(rundata);
    }
  }

デバッグ機能を利用し、ブレークポイントを設定したところ、「追加する」ボタンを押すとScheduleFormDataのdoInsert()が呼び出されていることがわかった。
このメソッドはALAbstractFormDataのdoInsert()をオーバーライドしている。

 @Override
  public boolean doInsert(ALAction action, RunData rundata, Context context) {
    boolean res = super.doInsert(action, rundata, context);
    // post(action, rundata, context);
    return res;
  }

ALAbstractFormDataのdoInsert()の実装は次のようになっている。

public boolean doInsert(ALAction action, RunData rundata, Context context) {
    List<String> msgList = new ArrayList<String>();
    try {
      if (!doCheckSecurity(rundata, context)) {
        msgList.add(ALLocalizationUtils.getl10n("ERROR_SECID_UNMATCH"));
        action.addErrorMessages(msgList);
        action.putData(rundata, context);
        return false;
      }

      init(action, rundata, context);

      doCheckAclPermission(
        rundata,
        context,
        ALAccessControlConstants.VALUE_ACL_INSERT);

      doCheckAttachmentInsertAclPermission(rundata, context);
      doCheckAttachmentDeleteAclPermission(rundata, context);

      action.setMode(ALEipConstants.MODE_INSERT);
      mode = action.getMode();
      rundata.getParameters().add(
        ALEipConstants.MODE,
        ALEipConstants.MODE_INSERT);
      setValidator();

      boolean res = false;
      if (isOverQuota()) {
        msgList.add(ALLocalizationUtils
          .getl10n("COMMON_FULL_DISK_DELETE_DETA_OR_CHANGE_PLAN"));
      } else {
        res =
          (setFormData(rundata, context, msgList)
            && validate(msgList)
            && extValidate(rundata, context, msgList) && insertFormData(
            rundata,
            context,
            msgList));
      }
      if (!res) {
        action.setMode(ALEipConstants.MODE_NEW_FORM);
        mode = action.getMode();
      }
      action.setResultData(this);
      if (!msgList.isEmpty()) {
        action.addErrorMessages(msgList);
      } else if (!res) {
        msgList.add(ALLocalizationUtils.getl10n("ERROR_INSERT_FAILURE"));
        action.addErrorMessages(msgList);
      }
      action.putData(rundata, context);

      return res;
    } catch (ALPermissionException e) {
      ALEipUtils.redirectPermissionError(rundata);
      return false;
    } catch (ALPageNotFoundException e) {
      ALEipUtils.redirectPageNotFound(rundata);
      return false;
    } catch (ALDBErrorException e) {
      msgList.add(ALLocalizationUtils.getl10n("ERROR_INSERT_FAILURE"));
      action.addErrorMessages(msgList);
      action.putData(rundata, context);
      return false;
    }
  }

スッテプオーバーで進めていくと、ScheduleFormDataのsetFormData()が呼び出されていることがわかった。
このときにはstart_data、end_data共にフォームに入力した時刻が正しく格納されていることが確認できた。

doInsert()のisOverQuota()でif~else文が生成され分岐している箇所のelseに実行が移った際に、validate()が呼び出されると、start_dataとend_dataの値が初期化されてしまうことがわかった。
ScheduleFormDataで実装されたvalidate()を見てみると、ScheduleUtilsクラスのvalidateDelegate()が呼び出されている。

@Override
  protected boolean validate(List<String> msgList) throws ALDBErrorException,
      ALPageNotFoundException {

    try {
      ScheduleUtils.validateDelegate(
        getStartDate(),
        getEndDate(),
        getRepeatType(),
        is_repeat,
        is_span,
        getWeek0(),
        getWeek1(),
        getWeek2(),
        getWeek3(),
        getWeek4(),
        getWeek5(),
        getWeek6(),
        getRepeatWeek(),
        getLimitFlag(),
        getLimitStartDate(),
        getLimitEndDate(),
        getMonthDay(),
        getYearMonth(),
        getYearDay(),
        loginUser,
        null,
        msgList,
        false);
    } catch (NumberFormatException nfe) {
      logger
        .error("[ScheduleFormData] NumberFormatException: Limit Date is wrong.");
      throw new ALPageNotFoundException();
    }

    // タイトル
    name.validate(msgList);
    // 場所
    place.validate(msgList);
    // 内容
    note.validate(msgList);

    common_category_id.validate(msgList);

    return (msgList.size() == 0);
  }

validateDelegate()メソッドを見てみると、is_spanがtrueの場合に、開始日時と終了日時の時間を0時0分0秒に設定する箇所がある。

if (is_span) {
      // 開始日時 と 終了日時 の時間を 0時0分0秒 に設定する
      Calendar tmp_start_date = Calendar.getInstance();
      tmp_start_date.setTime(start_date.getValue());
      tmp_start_date.set(Calendar.HOUR_OF_DAY, Integer.valueOf(start_date
        .getHour()));
      tmp_start_date.set(Calendar.MINUTE, Integer.valueOf(start_date
        .getMinute()));
      tmp_start_date.set(Calendar.SECOND, 0);
      start_date.setValue(tmp_start_date.getTime());

      Calendar tmp_end_date = Calendar.getInstance();
      tmp_end_date.setTime(end_date.getValue());
      tmp_end_date.set(Calendar.HOUR_OF_DAY, Integer
        .valueOf(end_date.getHour()));
      tmp_end_date.set(Calendar.MINUTE, Integer.valueOf(end_date.getMinute()));
      tmp_end_date.set(Calendar.SECOND, 0);
      end_date.setValue(tmp_end_date.getTime());
    }

ここを削除した。
さらにinsertFormData()のis_spanがtrueの場合に実行される箇所を、時間と分が格納されるように修正した。

 if (is_span) {
        Calendar startDate = Calendar.getInstance();
        startDate.setTime(start_date.getValue());
        startDate.set(Calendar.HOUR_OF_DAY, Integer.parseInt(start_date
          .getHour()));
        startDate
          .set(Calendar.MINUTE, Integer.parseInt(start_date.getMinute()));

        Calendar endDate = Calendar.getInstance();
        endDate.setTime(end_date.getValue());
        endDate.set(Calendar.HOUR_OF_DAY, Integer.parseInt(end_date.getHour()));
        endDate.set(Calendar.MINUTE, Integer.parseInt(end_date.getMinute()));

        start_date.setValue(startDate.getTime());
        end_date.setValue(endDate.getTime());

以上の修正により、日をまたいだ登録を行った場合にも、データベースに開始時間と終了時間が登録されるようになった。

登録時だけでなく、更新時についても正しく更新されるようにupdateFormDataについても同様の処理を追加することで更新にも対応。

2.表示

詳細画面での表示がうまくいかない。
詳細画面において、時間の表示を行う際にvmファイルが呼び出しているgetDate()は/aipo/portlets/schedule/src/main/java/com/aimluck/eip/schedule/ScheduleResultData.javaにある。

開始日と終了日の全ての値が等しい場合にのみ、開始時間と終了時間を入力された値で返すような仕様になっていたので、次のように修正することで正しく表示されるようにした。

public String getDate() {
    if (start_date.getValue().equals(end_date.getValue())) {
      return start_date.toString();
    } /*
       * else if ((start_date.getYear().equals(end_date.getYear()) &&
       * start_date.getMonth().equals(end_date.getMonth()) &&
       * start_date.getDay().equals(end_date.getDay())) || is_repeat) { return
       * new StringBuffer() .append(start_date.toString()) .append(" ")
       * .append('-') .append(" ") .append(end_date.toString()) .toString(); }
       * else { return new StringBuffer() .append(start_date.toString())
       * .append(" ") .append('-') .append(" ") .append("24:00") .toString(); }
       */
    // 開始と終了の全ての値が等しくない場合は開始時間と終了時間を返すように変更
    else {
      return new StringBuffer()
        .append(start_date.toString())
        .append(" ")
        .append('-')
        .append(" ")
        .append(end_date.toString())
        .toString();
    }
  }