/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.samza.application.descriptors;

import java.io.Serializable;
import java.util.Map;
import org.apache.samza.annotation.InterfaceStability;
import org.apache.samza.application.SamzaApplication;
import org.apache.samza.application.StreamApplication;
import org.apache.samza.application.TaskApplication;
import org.apache.samza.config.Config;
import org.apache.samza.context.ApplicationContainerContext;
import org.apache.samza.context.ApplicationContainerContextFactory;
import org.apache.samza.context.ApplicationTaskContext;
import org.apache.samza.context.ApplicationTaskContextFactory;
import org.apache.samza.context.Context;
import org.apache.samza.metrics.MetricsReporter;
import org.apache.samza.metrics.MetricsReporterFactory;
import org.apache.samza.operators.MessageStream;
import org.apache.samza.runtime.ProcessorLifecycleListenerFactory;
import org.apache.samza.system.descriptors.SystemDescriptor;


/**
 * An {@link ApplicationDescriptor} contains the description of inputs, outputs, state, configuration and the processing
 * logic for a {@link SamzaApplication}.
 * <p>
 * This is the base {@link ApplicationDescriptor} and provides functionality common to all {@link SamzaApplication}.
 * {@link StreamApplication#describe} will provide access to a {@link StreamApplicationDescriptor} with additional
 * functionality for describing High Level API applications. Similarly, {@link TaskApplication#describe} will provide
 * access to a {@link TaskApplicationDescriptor} with additional functionality for describing Low Level API
 * applications.
 * <p>
 * Use the {@link ApplicationDescriptor} to set the container scope context factory using
 * {@link ApplicationDescriptor#withApplicationContainerContextFactory}, and task scope context factory using
 * {@link ApplicationDescriptor#withApplicationTaskContextFactory}. Please note that the terms {@code container} and
 * {@code task} here refer to the units of physical and logical parallelism, not the programming API.
 */
@InterfaceStability.Evolving
public interface ApplicationDescriptor<S extends ApplicationDescriptor> {

  /**
   * Get the configuration for the application.
   *
   * @return config for the application
   */
  Config getConfig();

  /**
   * Sets the {@link SystemDescriptor} for the default system for the application.
   * <p>
   * The default system is used by the framework for creating any internal (e.g., coordinator, changelog, checkpoint)
   * streams. In an {@link StreamApplication}, it is also used for creating any intermediate streams; e.g., those
   * created by the {@link MessageStream#partitionBy} and {@link MessageStream#broadcast} operators.
   * <p>
   * If the default system descriptor is set, it must be set <b>before</b> creating any input/output/intermediate
   * streams.
   *
   * @param defaultSystemDescriptor the {@link SystemDescriptor} for the default system for the application
   * @return this {@link ApplicationDescriptor}
   */
  S withDefaultSystem(SystemDescriptor<?> defaultSystemDescriptor);

  /**
   * Sets the {@link ApplicationContainerContextFactory} for this application. Each task will be given access to a
   * different instance of the {@link ApplicationContainerContext} that this creates. The context can be accessed
   * through the {@link Context}.
   * <p>
   * Setting this is optional.
   * <p>
   * The provided {@code factory} instance must be {@link Serializable}.
   *
   * @param factory the {@link ApplicationContainerContextFactory} for this application
   * @return this {@link ApplicationDescriptor}
   */
  S withApplicationContainerContextFactory(ApplicationContainerContextFactory<?> factory);

  /**
   * Sets the {@link ApplicationTaskContextFactory} for this application. Each task will be given access to a different
   * instance of the {@link ApplicationTaskContext} that this creates. The context can be accessed through the
   * {@link Context}.
   * <p>
   * Setting this is optional.
   * <p>
   * The provided {@code factory} instance must be {@link java.io.Serializable}.
   *
   * @param factory the {@link ApplicationTaskContextFactory} for this application
   * @return this {@link ApplicationDescriptor}
   */
  S withApplicationTaskContextFactory(ApplicationTaskContextFactory<?> factory);

  /**
   * Sets the {@link ProcessorLifecycleListenerFactory} for this application.
   * <p>
   * Setting a {@link ProcessorLifecycleListenerFactory} is optional to a user application. It allows users to plug in
   * optional code to be invoked in different stages before/after the main processing logic is started/stopped in the
   * application.
   * <p>
   * The provided {@code factory} instance must be {@link java.io.Serializable}.
   *
   * @param listenerFactory the user implemented {@link ProcessorLifecycleListenerFactory} that creates lifecycle
   *                        listener with callback methods before and after the start/stop of each StreamProcessor in
   *                        the application
   * @return this {@link ApplicationDescriptor}
   */
  S withProcessorLifecycleListenerFactory(ProcessorLifecycleListenerFactory listenerFactory);

  /**
   * Sets the {@link MetricsReporterFactory}s for creating the {@link MetricsReporter}s to use for the application.
   * <p>
   * The provided {@link MetricsReporterFactory} instances must be {@link java.io.Serializable}.
   *
   * @param reporterFactories a map of {@link MetricsReporter} names to their factories.
   * @return this {@link ApplicationDescriptor}
   */
  S withMetricsReporterFactories(Map<String, MetricsReporterFactory> reporterFactories);

}

@@ -3935,141 +3935,258 @@
 on. 
-Each task will be given access to a%0A   * different instance of the %7B@link ApplicationContainerContext%7D that this creates. The c
+This will be used to create one instance%0A   * of an %7B@link ApplicationContainerContext%7D for each container. All tasks in the same container will share the same%0A   * %7B@link ApplicationContainerContext%7D instance. The %7B@link ApplicationContainerC
 ontext
+%7D
  can
@@ -4197,21 +4197,16 @@
 accessed
-%0A   *
  through
@@ -4205,24 +4205,29 @@
  through the
+%0A   *
  %7B@link Cont
@@ -4798,22 +4798,50 @@
 The 
-c
+%7B@link ApplicationTaskC
 ontext
+%7D
  can be
+%0A   *
  acc
@@ -4849,37 +4849,32 @@
 ssed through the
-%0A   *
  %7B@link Context%7D

fix misleading javadoc for context factories in ApplicationDescriptor (#1096)