// Path: micro-core/src/main/java/sample/context/Timestamper.java
// public class Timestamper {
//     public static final String KeyDay = "system.businessDay.day";
// 
//     @Autowired(required = false)
//     private AppSettingHandler setting;
// 
//     private final Clock clock;
// 
//     public Timestamper() {
//         clock = Clock.systemDefaultZone();
//     }
// 
//     public Timestamper(final Clock clock) {
//         this.clock = clock;
//     }
// 
//     /** 営業日を返します。 */
//     public LocalDate day() {
//         return setting == null ? LocalDate.now(clock) : DateUtils.day(setting.setting(KeyDay).str());
//     }
// 
//     /** 日時を返します。 */
//     public LocalDateTime date() {
//         return LocalDateTime.now(clock);
//     }
// 
//     /** 営業日/日時を返します。 */
//     public TimePoint tp() {
//         return TimePoint.of(day(), date());
//     }
// 
//     /**
//      * 営業日を指定日へ進めます。
//      * <p>AppSettingHandlerを設定時のみ有効です。
//      * @param day 更新営業日
//      */
//     public Timestamper proceedDay(LocalDate day) {
//         if (setting != null)
//             setting.update(KeyDay, DateUtils.dayFormat(day));
//         return this;
//     }
// 
// }
// 
// Path: micro-core/src/main/java/sample/context/rest/RestActorSessionBindFilter.java
// public class RestActorSessionBindFilter extends GenericFilterBean {
//     
//     private final ActorSession session;
//     
//     public RestActorSessionBindFilter(ActorSession session) {
//         this.session = session;
//     }
// 
//     @Override
//     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
//             throws IOException, ServletException {
//         try {
//             String actorStr = ((HttpServletRequest)request).getHeader(RestActorSessionInterceptor.AttrActorSession);
//             Optional.ofNullable(actorStr).ifPresent((str) ->
//                 session.bind(RestActorSessionConverter.convert(str)));
//             chain.doFilter(request, response);
//         } finally {
//             session.unbind();
//         }
//     }
//     
// }


import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.health.*;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.*;
import org.springframework.transaction.PlatformTransactionManager;
import sample.context.Timestamper;
import sample.context.actor.ActorSession;
import sample.context.orm.DefaultRepository;
import sample.context.rest.RestActorSessionBindFilter;
import sample.model.*;
import sample.model.BusinessDayHandler.HolidayAccessor;
package sample;



/**
 * アプリケーションドメインのコンポーネント定義を表現します。
 */
@Configuration
@Import({ApplicationConfig.class})
public class MicroAppConfig {

    /** Domain 層のコンテナ管理を表現します。 */
    @Configuration
    static class DomainAutoConfig {
        
        /** データ生成ユーティリティ */
        @Bean
        @ConditionalOnProperty(prefix = DataFixtures.Prefix, name = "enabled", matchIfMissing = false)
        DataFixtures fixtures() {
            return new DataFixtures();
        }
        
        /** 休日情報アクセサ */
        @Bean
        HolidayAccessor holidayAccessor(
                DefaultRepository rep,
                @Qualifier(DefaultRepository.BeanNameTx)
                PlatformTransactionManager txm) {
            return new HolidayAccessor(txm, rep); //low: 定義側にスキーマ指定を委ねるときは外部から設定するアプローチで
        }
        
        /** 営業日ユーティリティ */
        @Bean
        BusinessDayHandler businessDayHandler(Timestamper time, HolidayAccessor holiday) {
            return BusinessDayHandler.of(time, holiday);
        }
    }
    
    /** プロセススコープの拡張定義を表現します。 */
    @Configuration
    static class ProcessAutoConfig {
        
        /**
         * リクエストに利用者情報が設定されていた時はそのままスレッドローカルへ紐づけます。
         * <p>同期Servletでのみ適切に動きます。
         */
        @Bean
// Path: micro-core/src/main/java/sample/context/Timestamper.java
// public class Timestamper {
//     public static final String KeyDay = "system.businessDay.day";
// 
//     @Autowired(required = false)
//     private AppSettingHandler setting;
// 
//     private final Clock clock;
// 
//     public Timestamper() {
//         clock = Clock.systemDefaultZone();
//     }
// 
//     public Timestamper(final Clock clock) {
//         this.clock = clock;
//     }
// 
//     /** 営業日を返します。 */
//     public LocalDate day() {
//         return setting == null ? LocalDate.now(clock) : DateUtils.day(setting.setting(KeyDay).str());
//     }
// 
//     /** 日時を返します。 */
//     public LocalDateTime date() {
//         return LocalDateTime.now(clock);
//     }
// 
//     /** 営業日/日時を返します。 */
//     public TimePoint tp() {
//         return TimePoint.of(day(), date());
//     }
// 
//     /**
//      * 営業日を指定日へ進めます。
//      * <p>AppSettingHandlerを設定時のみ有効です。
//      * @param day 更新営業日
//      */
//     public Timestamper proceedDay(LocalDate day) {
//         if (setting != null)
//             setting.update(KeyDay, DateUtils.dayFormat(day));
//         return this;
//     }
// 
// }
// 
// Path: micro-core/src/main/java/sample/context/rest/RestActorSessionBindFilter.java
// public class RestActorSessionBindFilter extends GenericFilterBean {
//     
//     private final ActorSession session;
//     
//     public RestActorSessionBindFilter(ActorSession session) {
//         this.session = session;
//     }
// 
//     @Override
//     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
//             throws IOException, ServletException {
//         try {
//             String actorStr = ((HttpServletRequest)request).getHeader(RestActorSessionInterceptor.AttrActorSession);
//             Optional.ofNullable(actorStr).ifPresent((str) ->
//                 session.bind(RestActorSessionConverter.convert(str)));
//             chain.doFilter(request, response);
//         } finally {
//             session.unbind();
//         }
//     }
//     
// }


// Path: micro-app/src/main/java/sample/MicroAppConfig.java
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.actuate.health.*;
import org.springframework.boot.actuate.health.Health.Builder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.*;
import org.springframework.transaction.PlatformTransactionManager;
import sample.context.Timestamper;
import sample.context.actor.ActorSession;
import sample.context.orm.DefaultRepository;
import sample.context.rest.RestActorSessionBindFilter;
import sample.model.*;
import sample.model.BusinessDayHandler.HolidayAccessor;

package sample;



/**
 * アプリケーションドメインのコンポーネント定義を表現します。
 */
@Configuration
@Import({ApplicationConfig.class})
public class MicroAppConfig {

    /** Domain 層のコンテナ管理を表現します。 */
    @Configuration
    static class DomainAutoConfig {
        
        /** データ生成ユーティリティ */
        @Bean
        @ConditionalOnProperty(prefix = DataFixtures.Prefix, name = "enabled", matchIfMissing = false)
        DataFixtures fixtures() {
            return new DataFixtures();
        }
        
        /** 休日情報アクセサ */
        @Bean
        HolidayAccessor holidayAccessor(
                DefaultRepository rep,
                @Qualifier(DefaultRepository.BeanNameTx)
                PlatformTransactionManager txm) {
            return new HolidayAccessor(txm, rep); //low: 定義側にスキーマ指定を委ねるときは外部から設定するアプローチで
        }
        
        /** 営業日ユーティリティ */
        @Bean
        BusinessDayHandler businessDayHandler(Timestamper time, HolidayAccessor holiday) {
            return BusinessDayHandler.of(time, holiday);
        }
    }
    
    /** プロセススコープの拡張定義を表現します。 */
    @Configuration
    static class ProcessAutoConfig {
        
        /**
         * リクエストに利用者情報が設定されていた時はそのままスレッドローカルへ紐づけます。
         * <p>同期Servletでのみ適切に動きます。
         */
        @Bean
        public RestActorSessionBindFilter restActorSessionBindFilter(ActorSession session) {