add new property

Signed-off-by: Ryosuke Okada <ryosuke.okada@fujitsu.com>
diff --git a/appserver/admingui/concurrent/src/main/help/en/help/ref-executorserviceedit.html b/appserver/admingui/concurrent/src/main/help/en/help/ref-executorserviceedit.html
index 5003392..d39f8ba 100644
--- a/appserver/admingui/concurrent/src/main/help/en/help/ref-executorserviceedit.html
+++ b/appserver/admingui/concurrent/src/main/help/en/help/ref-executorserviceedit.html
@@ -58,6 +58,10 @@
 <dd>
 <p>The number of seconds tasks can execute before they are considered unresponsive. The default value is 0.</p>
 </dd>
+<dt>Hung Logger Print Once</dt>
+<dd>
+<p>Specifies whether to print the warning message once or repeatedly. The default value is false. If set to true, the warning message is printed only once when detect a hung task exceeds "Hung After".</p>
+</dd>
 <dt>Hung Logger Initial Delay</dt>
 <dd>
 <p>The number of seconds to delay logging the detection of hung tasks. The default value is 60.</p>
diff --git a/appserver/admingui/concurrent/src/main/help/en/help/ref-executorservicenew.html b/appserver/admingui/concurrent/src/main/help/en/help/ref-executorservicenew.html
index 55c28ac..863e69b 100644
--- a/appserver/admingui/concurrent/src/main/help/en/help/ref-executorservicenew.html
+++ b/appserver/admingui/concurrent/src/main/help/en/help/ref-executorservicenew.html
@@ -48,6 +48,10 @@
 <dd>
 <p>The number of seconds tasks can execute before they are considered unresponsive. The default value is 0.</p>
 </dd>
+<dt>Hung Logger Print Once</dt>
+<dd>
+<p>Specifies whether to print the warning message once or repeatedly. The default value is false. If set to true, the warning message is printed only once when detect a hung task exceeds "Hung After".</p>
+</dd>
 <dt>Hung Logger Initial Delay</dt>
 <dd>
 <p>The number of seconds to delay logging the detection of hung tasks. The default value is 60.</p>
diff --git a/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorserviceedit.html b/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorserviceedit.html
index 5e73b3e..6d45e98 100644
--- a/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorserviceedit.html
+++ b/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorserviceedit.html
@@ -58,6 +58,10 @@
 <dd>
 <p>The number of seconds tasks can execute before they are considered unresponsive. The default value is 0.</p>
 </dd>
+<dt>Hung Logger Print Once</dt>
+<dd>
+<p>Specifies whether to print the warning message once or repeatedly. The default value is false. If set to true, the warning message is printed only once when detect a hung task exceeds "Hung After".</p>
+</dd>
 <dt>Hung Logger Initial Delay</dt>
 <dd>
 <p>The number of seconds to delay logging the detection of hung tasks. The default value is 60.</p>
diff --git a/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorservicenew.html b/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorservicenew.html
index f1a6bb8..00813c4 100644
--- a/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorservicenew.html
+++ b/appserver/admingui/concurrent/src/main/help/en/help/ref-scheduledexecutorservicenew.html
@@ -48,6 +48,10 @@
 <dd>
 <p>The number of seconds tasks can execute before they are considered unresponsive. The default value is 0.</p>
 </dd>
+<dt>Hung Logger Print Once</dt>
+<dd>
+<p>Specifies whether to print the warning message once or repeatedly. The default value is false. If set to true, the warning message is printed only once when detect a hung task exceeds "Hung After".</p>
+</dd>
 <dt>Hung Logger Initial Delay</dt>
 <dd>
 <p>The number of seconds to delay logging the detection of hung tasks. The default value is 60.</p>
diff --git a/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceAttr.inc b/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceAttr.inc
index 54d6c11..8766289 100644
--- a/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceAttr.inc
+++ b/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceAttr.inc
@@ -65,6 +65,9 @@
             <sun:textField id="hungafter" styleClass="integer" columns="$int{55}" maxLength="#{sessionScope.fieldLengths['maxLength.common.description']}" text="#{pageSession.valueMap['hungAfterSeconds']}" />
             <sun:staticText id="sec" style="padding: 8pt" text="$resource{i18n.common.Seconds}"/>
        </sun:property>
+       <sun:property id="hungLoggerPrintOnce"  labelAlign="left" noWrap="#{true}" overlapLabel="#{false}" label="$resource{i18ncon.hungLoggerPrintOnce}">
+            <sun:checkbox  selected="#{pageSession.valueMap['hungLoggerPrintOnce']}" selectedValue="true"  />
+       </sun:property>
        <sun:property id="hungLoggerInitialDelay" labelAlign="left" noWrap="#{true}" overlapLabel="#{false}" label="$resource{i18ncon.hungLoggerInitialDelaySeconds}"  helpText="$resource{i18ncon.hungLoggerInitialDelaySecondsHelp}">
             <sun:textField id="hungLoggerInitialDelay" styleClass="integer" columns="$int{55}" maxLength="#{sessionScope.fieldLengths['maxLength.common.description']}" text="#{pageSession.valueMap['hungLoggerInitialDelaySeconds']}" />
             <sun:staticText id="sec" style="padding: 8pt" text="$resource{i18n.common.Seconds}"/>
diff --git a/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceEdit.jsf b/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceEdit.jsf
index ff4e29a..4f50524 100644
--- a/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceEdit.jsf
+++ b/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceEdit.jsf
@@ -39,7 +39,7 @@
 
     gf.buildResourceUrl(base="#{pageSession.parentUrl}/#{pageSession.childType}", resourceName="#{pageSession.Name}", url="#{pageSession.selfUrl}");
     gf.getEntityAttrs(endpoint="#{pageSession.selfUrl}", valueMap="#{pageSession.valueMap}");
-    setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled", "longRunningTasks" });
+    setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled", "longRunningTasks", "hungLoggerPrintOnce" });
     setPageSessionAttribute(key="skipAttrsList", value={"jndiName"});
     
     gf.restRequest(endpoint="#{pageSession.selfUrl}/property" method="GET" result="#{requestScope.propTable}");
diff --git a/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceNew.jsf b/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceNew.jsf
index 672607e..324d768 100644
--- a/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceNew.jsf
+++ b/appserver/admingui/concurrent/src/main/resources/managedExecutorServiceNew.jsf
@@ -31,7 +31,7 @@
         setPageSessionAttribute(key="parentPage" value="#{request.contextPath}/concurrent/managedExecutorServices.jsf");
         setPageSessionAttribute(key="childType" value="managed-executor-service");
         setPageSessionAttribute(key="isConcurrent" value="true");
-        setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled","longRunningTasks" });
+        setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled","longRunningTasks", "hungLoggerPrintOnce" });
         setPageSessionAttribute(key="parentUrl", value="#{sessionScope.REST_URL}/resources");
         gf.getDefaultValues(endpoint="#{pageSession.parentUrl}/#{pageSession.childType}", valueMap="#{pageSession.valueMap}");
         setPageSessionAttribute(key="edit" value="#{false}" );
diff --git a/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceEdit.jsf b/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceEdit.jsf
index cd8f0ce..330fb96 100644
--- a/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceEdit.jsf
+++ b/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceEdit.jsf
@@ -39,7 +39,7 @@
 
     gf.buildResourceUrl(base="#{pageSession.parentUrl}/#{pageSession.childType}", resourceName="#{pageSession.Name}", url="#{pageSession.selfUrl}");
     gf.getEntityAttrs(endpoint="#{pageSession.selfUrl}", valueMap="#{pageSession.valueMap}");
-    setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled", "longRunningTasks" });
+    setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled", "longRunningTasks", "hungLoggerPrintOnce" });
     setPageSessionAttribute(key="skipAttrsList", value={"jndiName"});
     
     gf.restRequest(endpoint="#{pageSession.selfUrl}/property" method="GET" result="#{requestScope.propTable}");
diff --git a/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceNew.jsf b/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceNew.jsf
index dd70ce9..29d4e3a 100644
--- a/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceNew.jsf
+++ b/appserver/admingui/concurrent/src/main/resources/managedScheduledExecutorServiceNew.jsf
@@ -31,7 +31,7 @@
         setPageSessionAttribute(key="parentPage" value="#{request.contextPath}/concurrent/managedScheduledExecutorServices.jsf");
         setPageSessionAttribute(key="childType" value="managed-scheduled-executor-service");
         setPageSessionAttribute(key="isConcurrent" value="true");
-        setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled", "longRunningTasks" });
+        setPageSessionAttribute(key="convertToFalseList" value={"enabled", "contextInfoEnabled", "longRunningTasks", "hungLoggerPrintOnce" });
         setPageSessionAttribute(key="parentUrl", value="#{sessionScope.REST_URL}/resources");
         gf.getDefaultValues(endpoint="#{pageSession.parentUrl}/#{pageSession.childType}", valueMap="#{pageSession.valueMap}");
         setPageSessionAttribute(key="edit" value="#{false}" );
diff --git a/appserver/admingui/concurrent/src/main/resources/org/glassfish/concurrent/admingui/Strings.properties b/appserver/admingui/concurrent/src/main/resources/org/glassfish/concurrent/admingui/Strings.properties
index bddf532..6bc8ebe 100644
--- a/appserver/admingui/concurrent/src/main/resources/org/glassfish/concurrent/admingui/Strings.properties
+++ b/appserver/admingui/concurrent/src/main/resources/org/glassfish/concurrent/admingui/Strings.properties
@@ -94,6 +94,8 @@
 longRunningTasksHelp=Use the resource for long-running tasks. If enabled, long-running tasks are not reported as stuck.
 hungAfterSeconds=Hung After:
 hungAfterSecondsHelp=Number of seconds tasks can execute before they are considered unresponsive
+hungLoggerPrintOnce=Hung Logger Print Once:
+hungLoggerPrintOnceHelp=Print the warning message only once when hung tasks is detect a hung task exceeds "Hung After".
 hungLoggerInitialDelaySeconds=Hung Logger Initial Delay:
 hungLoggerInitialDelaySecondsHelp=Number of seconds to delay logging the detection of hung tasks.
 hungLoggerIntervalSeconds=Hung Logger Interval:
diff --git a/appserver/concurrent/concurrent-connector/src/main/java/org/glassfish/concurrent/config/ManagedExecutorServiceBase.java b/appserver/concurrent/concurrent-connector/src/main/java/org/glassfish/concurrent/config/ManagedExecutorServiceBase.java
index c84a8b1..b9fc91c 100644
--- a/appserver/concurrent/concurrent-connector/src/main/java/org/glassfish/concurrent/config/ManagedExecutorServiceBase.java
+++ b/appserver/concurrent/concurrent-connector/src/main/java/org/glassfish/concurrent/config/ManagedExecutorServiceBase.java
@@ -89,6 +89,23 @@
     void setHungAfterSeconds(String value) throws PropertyVetoException;
 
     /**
+     * Gets the value of the hungLoggerPrintOnce property.
+     *
+     * @return possible object is
+     *         {@link String }
+     */
+    @Attribute(defaultValue="false", dataType=Boolean.class)
+    String getHungLoggerPrintOnce();
+
+    /**
+     * Sets the value of the hungLoggerPrintOnce property.
+     *
+     * @param value allowed object is
+     *              {@link String }
+     */
+    void setHungLoggerPrintOnce(String value) throws PropertyVetoException;
+
+    /**
      * Gets the value of the hungLoggerInitialDelaySeconds property.
      *
      * @return possible object is {@link String }
diff --git a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/CreateManagedExecutorServiceBase.java b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/CreateManagedExecutorServiceBase.java
index 948a7d6..5472f76 100644
--- a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/CreateManagedExecutorServiceBase.java
+++ b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/CreateManagedExecutorServiceBase.java
@@ -56,6 +56,9 @@
     @Param(name="hungafterseconds", alias="hungAfterSeconds", defaultValue="0", optional=true)
     protected Integer hungafterseconds;
 
+    @Param(name="hungloggerprintonce", alias="hungLoggerPrintOnce", defaultValue="false", optional=true)
+    protected Boolean hungloggerprintonce;
+
     @Param(name = "hungloggerinitialdelayseconds", alias = "hungLoggerInitialDelaySeconds", defaultValue = "60", optional = true)
     protected Integer hungloggerinitialdelayseconds;
 
@@ -90,6 +93,8 @@
             longrunningtasks.toString());
         attrList.put(ResourceConstants.HUNG_AFTER_SECONDS,
             hungafterseconds.toString());
+        attrList.put(ResourceConstants.HUNG_LOGGER_PRINT_ONCE,
+            hungloggerprintonce.toString());
         attrList.put(ResourceConstants.HUNG_LOGGER_INITIAL_DELAY_SECONDS, hungloggerinitialdelayseconds.toString());
         attrList.put(ResourceConstants.HUNG_LOGGER_INTERVAL_SECONDS, hungloggerintervalseconds.toString());
         attrList.put(ResourceConstants.CORE_POOL_SIZE,
diff --git a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/ManagedExecutorServiceBaseManager.java b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/ManagedExecutorServiceBaseManager.java
index 42d0fbe..1dad077 100644
--- a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/ManagedExecutorServiceBaseManager.java
+++ b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/admin/ManagedExecutorServiceBaseManager.java
@@ -61,6 +61,7 @@
     protected String contextInfo = CONTEXT_INFO_DEFAULT_VALUE;
     protected String longRunningTasks = Boolean.FALSE.toString();
     protected String hungAfterSeconds = "0";
+    protected String hungLoggerPrintOnce = Boolean.FALSE.toString();
     protected String hungLoggerInitialDelaySeconds = "60";
     protected String hungLoggerIntervalSeconds = "60";
     protected String corePoolSize = "0";
@@ -144,6 +145,7 @@
         threadPriority = (String) attributes.get(THREAD_PRIORITY);
         longRunningTasks = (String) attributes.get(LONG_RUNNING_TASKS);
         hungAfterSeconds = (String) attributes.get(HUNG_AFTER_SECONDS);
+        hungLoggerPrintOnce = (String) attributes.get(HUNG_LOGGER_PRINT_ONCE);
         hungLoggerInitialDelaySeconds = (String) attributes.get(HUNG_LOGGER_INITIAL_DELAY_SECONDS);
         hungLoggerIntervalSeconds = (String) attributes.get(HUNG_LOGGER_INTERVAL_SECONDS);
         corePoolSize = (String) attributes.get(CORE_POOL_SIZE);
@@ -174,6 +176,7 @@
         managedExecutorService.setContextInfo(contextInfo);
         managedExecutorService.setThreadPriority(threadPriority);
         managedExecutorService.setHungAfterSeconds(hungAfterSeconds);
+        managedExecutorService.setHungLoggerPrintOnce(hungLoggerPrintOnce);
         managedExecutorService.setHungLoggerInitialDelaySeconds(hungLoggerInitialDelaySeconds);
         managedExecutorService.setHungLoggerIntervalSeconds(hungLoggerIntervalSeconds);
         managedExecutorService.setCorePoolSize(corePoolSize);
diff --git a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ConcurrentRuntime.java b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ConcurrentRuntime.java
index 6f8f538..87a8a5a 100644
--- a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ConcurrentRuntime.java
+++ b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/ConcurrentRuntime.java
@@ -172,7 +172,7 @@
         }
         managedExecutorServiceMap.put(jndiName, mes);
         if (config.getHungAfterSeconds() > 0L && !config.isLongRunningTasks()) {
-            scheduleInternalTimer(config.getHungLoggerInitialDelaySeconds(), config.getHungLoggerIntervalSeconds());
+            scheduleInternalTimer(config.getHungLoggerInitialDelaySeconds(), config.getHungLoggerIntervalSeconds(), config.isHungLoggerPrintOnce());
         }
         return mes;
     }
@@ -214,7 +214,7 @@
         }
         managedScheduledExecutorServiceMap.put(jndiName, mes);
         if (config.getHungAfterSeconds() > 0L && !config.isLongRunningTasks()) {
-            scheduleInternalTimer(config.getHungLoggerInitialDelaySeconds(), config.getHungLoggerIntervalSeconds());
+            scheduleInternalTimer(config.getHungLoggerInitialDelaySeconds(), config.getHungLoggerIntervalSeconds(), config.isHungLoggerPrintOnce());
         }
         return mes;
     }
@@ -300,7 +300,7 @@
         return contextTypeArray.toArray(contextTypes);
     }
 
-    private void scheduleInternalTimer(long initialDelay, long interval) {
+    private void scheduleInternalTimer(long initialDelay, long interval, boolean logOnce) {
         if (internalScheduler == null) {
             String name = "glassfish-internal";
             ManagedThreadFactoryImpl managedThreadFactory = new ManagedThreadFactoryImpl(
@@ -317,7 +317,7 @@
                     createContextService(name + "-contextservice",
                             CONTEXT_INFO_CLASSLOADER, "true", false),
                     AbstractManagedExecutorService.RejectPolicy.ABORT);
-            internalScheduler.scheduleAtFixedRate(new HungTasksLogger(), initialDelay, interval, TimeUnit.SECONDS);
+            internalScheduler.scheduleAtFixedRate(new HungTasksLogger(logOnce), initialDelay, interval, TimeUnit.SECONDS);
         }
     }
 
@@ -332,6 +332,13 @@
 
     class HungTasksLogger implements Runnable {
 
+        private Boolean logOnce;
+        private Map<String, Collection<AbstractManagedThread>> cachedHungThreadsMap = new HashMap<>();
+
+        HungTasksLogger(Boolean logOnce) {
+            this.logOnce = logOnce;
+        }
+
         public void run() {
             ArrayList<ManagedExecutorServiceImpl> executorServices = new ArrayList();
             ArrayList<ManagedScheduledExecutorServiceImpl> scheduledExecutorServices = new ArrayList();
@@ -358,6 +365,25 @@
         }
 
         private void logHungThreads(Collection<AbstractManagedThread> hungThreads, ManagedThreadFactoryImpl mtf, String mesName) {
+             if (!logOnce){
+                 logRawHungThreads(hungThreads, mtf, mesName);
+                 return;
+             }
+             if (hungThreads == null) {
+                 cachedHungThreadsMap.remove(mesName);
+                 return;
+             }
+             Collection<AbstractManagedThread> targetHungThreads = new HashSet<>();
+             targetHungThreads.addAll(hungThreads);
+             Collection<AbstractManagedThread> cachedHungThreads = cachedHungThreadsMap.get(mesName);
+             if (cachedHungThreads != null) {
+                 targetHungThreads.removeAll(cachedHungThreads);
+             }
+             logRawHungThreads(targetHungThreads, mtf, mesName);
+             cachedHungThreadsMap.put(mesName, hungThreads);
+        }
+
+        private void logRawHungThreads(Collection<AbstractManagedThread> hungThreads, ManagedThreadFactoryImpl mtf, String mesName) {
             if (hungThreads != null) {
                 for (AbstractManagedThread hungThread: hungThreads) {
                     Object[] params = {hungThread.getTaskIdentityName(),
diff --git a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedExecutorServiceConfig.java b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedExecutorServiceConfig.java
index a351bb0..ac367f5 100644
--- a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedExecutorServiceConfig.java
+++ b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedExecutorServiceConfig.java
@@ -25,6 +25,7 @@
 public class ManagedExecutorServiceConfig extends BaseConfig  {
 
     private int hungAfterSeconds;
+    private boolean hungLoggerPrintOnce;
     private long hungLoggerInitialDelaySeconds;
     private long hungLoggerIntervalSeconds;
     private boolean longRunningTasks;
@@ -38,6 +39,7 @@
     public ManagedExecutorServiceConfig(ManagedExecutorService config) {
         super(config.getJndiName(), config.getContextInfo(), config.getContextInfoEnabled());
         hungAfterSeconds = parseInt(config.getHungAfterSeconds(), 0);
+        hungLoggerPrintOnce = Boolean.valueOf(config.getHungLoggerPrintOnce());
         hungLoggerInitialDelaySeconds = parseLong(config.getHungLoggerInitialDelaySeconds(), 60);
         hungLoggerIntervalSeconds = parseLong(config.getHungLoggerIntervalSeconds(), 60);
         longRunningTasks = Boolean.valueOf(config.getLongRunningTasks());
@@ -53,6 +55,10 @@
         return hungAfterSeconds;
     }
 
+    public boolean isHungLoggerPrintOnce() {
+        return hungLoggerPrintOnce;
+    }
+
     public long getHungLoggerInitialDelaySeconds() {
         return hungLoggerInitialDelaySeconds;
     }
diff --git a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedScheduledExecutorServiceConfig.java b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedScheduledExecutorServiceConfig.java
index 9536298..d1d3b45 100644
--- a/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedScheduledExecutorServiceConfig.java
+++ b/appserver/concurrent/concurrent-impl/src/main/java/org/glassfish/concurrent/runtime/deployer/ManagedScheduledExecutorServiceConfig.java
@@ -25,6 +25,7 @@
 public class ManagedScheduledExecutorServiceConfig extends BaseConfig {
 
     private int hungAfterSeconds;
+    private boolean hungLoggerPrintOnce;
     private long hungLoggerInitialDelaySeconds;
     private long hungLoggerIntervalSeconds;
     private boolean longRunningTasks;
@@ -36,6 +37,7 @@
     public ManagedScheduledExecutorServiceConfig(ManagedScheduledExecutorService config) {
         super(config.getJndiName(), config.getContextInfo(), config.getContextInfoEnabled());
         hungAfterSeconds = parseInt(config.getHungAfterSeconds(), 0);
+        hungLoggerPrintOnce = Boolean.valueOf(config.getHungLoggerPrintOnce());
         hungLoggerInitialDelaySeconds = parseLong(config.getHungLoggerInitialDelaySeconds(), 60);
         hungLoggerIntervalSeconds = parseLong(config.getHungLoggerIntervalSeconds(), 60);
         longRunningTasks = Boolean.valueOf(config.getLongRunningTasks());
@@ -49,6 +51,10 @@
         return hungAfterSeconds;
     }
 
+    public boolean isHungLoggerPrintOnce() {
+        return hungLoggerPrintOnce;
+    }
+
     public long getHungLoggerInitialDelaySeconds() {
         return hungLoggerInitialDelaySeconds;
     }
diff --git a/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-executor-service.1 b/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-executor-service.1
index 33663bf..e488e7b 100644
--- a/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-executor-service.1
+++ b/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-executor-service.1
@@ -12,6 +12,7 @@
            [--threadpriority threadpriority]
            [--longrunningtasks={false|true}]
            [--hungafterseconds hungafterseconds]
+           [--hungloggerprintonce={false|true}]
            [--hungloggerinitialdelayseconds hungloggerinitialdelayseconds]
            [--hungloggerintervalseconds hungloggerintervalseconds]
            [--corepoolsize corepoolsize]
@@ -64,6 +65,11 @@
            is considered unresponsive. The default value is 0, which means
            that tasks are never considered unresponsive.
 
+       --hungloggerprintonce
+           Specifies whether to print the warning message once or repeatedly.
+           The default value is false. If set to true, the warning message is
+           printed only once when detect a hung task exceeds "hungafterseconds".
+
        --hungloggerinitialdelayseconds
            Specifies the number of seconds to delay logging the detection of
            hung tasks. The default value is 60.
diff --git a/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-scheduled-executor-service.1 b/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-scheduled-executor-service.1
index c75990b..d7e250d 100644
--- a/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-scheduled-executor-service.1
+++ b/appserver/concurrent/concurrent-impl/src/main/manpages/org/glassfish/concurrent/admin/create-managed-scheduled-executor-service.1
@@ -12,6 +12,7 @@
            [--threadpriority threadpriority]
            [--longrunningtasks={false|true}]
            [--hungafterseconds hungafterseconds]
+           [--hungloggerprintonce={false|true}]
            [--hungloggerinitialdelayseconds hungloggerinitialdelayseconds]
            [--hungloggerintervalseconds hungloggerintervalseconds]
            [--corepoolsize corepoolsize]
@@ -62,6 +63,11 @@
            is considered unresponsive. The default value is 0, which means
            that tasks are never considered unresponsive.
 
+       --hungloggerprintonce
+           Specifies whether to print the warning message once or repeatedly.
+           The default value is false. If set to true, the warning message is
+           printed only once when detect a hung task exceeds "hungafterseconds".
+
        --hungloggerinitialdelayseconds
            Specifies the number of seconds to delay logging the detection of
            hung tasks. The default value is 60.
diff --git a/appserver/resources/resources-connector/src/main/java/org/glassfish/resources/admin/cli/ResourceConstants.java b/appserver/resources/resources-connector/src/main/java/org/glassfish/resources/admin/cli/ResourceConstants.java
index 60f538c..1ee8206 100644
--- a/appserver/resources/resources-connector/src/main/java/org/glassfish/resources/admin/cli/ResourceConstants.java
+++ b/appserver/resources/resources-connector/src/main/java/org/glassfish/resources/admin/cli/ResourceConstants.java
@@ -224,6 +224,7 @@
     public static final String THREAD_PRIORITY = "thread-priority";
     public static final String LONG_RUNNING_TASKS = "long-runnings-tasks";
     public static final String HUNG_AFTER_SECONDS = "hung-after-seconds";
+    public static final String HUNG_LOGGER_PRINT_ONCE = "hung-logger-print-once";
     public static final String HUNG_LOGGER_INITIAL_DELAY_SECONDS = "hung-logger-initial-delay-seconds";
     public static final String HUNG_LOGGER_INTERVAL_SECONDS = "hung-logger-interval-seconds";
     public static final String CORE_POOL_SIZE = "core-pool-size";
diff --git a/docs/reference-manual/src/main/asciidoc/create-managed-executor-service.adoc b/docs/reference-manual/src/main/asciidoc/create-managed-executor-service.adoc
index 2b4be15..8865a18 100644
--- a/docs/reference-manual/src/main/asciidoc/create-managed-executor-service.adoc
+++ b/docs/reference-manual/src/main/asciidoc/create-managed-executor-service.adoc
@@ -26,6 +26,7 @@
 [--threadpriority threadpriority]
 [--longrunningtasks={false|true}]
 [--hungafterseconds hungafterseconds]
+[--hungloggerprintonce={false|true}]
 [--hungloggerinitialdelayseconds hungloggerinitialdelayseconds]
 [--hungloggerintervalseconds hungloggerintervalseconds]
 [--corepoolsize corepoolsize]
@@ -82,6 +83,10 @@
   Specifies the number of seconds that a task can execute before it is
   considered unresponsive. The default value is 0, which means that
   tasks are never considered unresponsive.
+`--hungloggerprintonce`::
+  Specifies whether to print the warning message once or repeatedly.
+  The default value is false. If set to true, the warning message is
+  printed only once when detect a hung task exceeds "hungafterseconds".
 `--hungloggerinitialdelayseconds`::
   Specifies the number of seconds to delay logging the detection of hung
   tasks. The default value is 60.
diff --git a/docs/reference-manual/src/main/asciidoc/create-managed-scheduled-executor-service.adoc b/docs/reference-manual/src/main/asciidoc/create-managed-scheduled-executor-service.adoc
index 45f8bf5..6d4ee78 100644
--- a/docs/reference-manual/src/main/asciidoc/create-managed-scheduled-executor-service.adoc
+++ b/docs/reference-manual/src/main/asciidoc/create-managed-scheduled-executor-service.adoc
@@ -26,6 +26,7 @@
 [--threadpriority threadpriority]
 [--longrunningtasks={false|true}]
 [--hungafterseconds hungafterseconds]
+[--hungloggerprintonce={false|true}]
 [--hungloggerinitialdelayseconds hungloggerinitialdelayseconds]
 [--hungloggerintervalseconds hungloggerintervalseconds]
 [--corepoolsize corepoolsize]
@@ -80,6 +81,10 @@
   Specifies the number of seconds that a task can execute before it is
   considered unresponsive. The default value is 0, which means that
   tasks are never considered unresponsive.
+`--hungloggerprintonce`::
+  Specifies whether to print the warning message once or repeatedly.
+  The default value is false. If set to true, the warning message is
+  printed only once when detect a hung task exceeds "hungafterseconds".
 `--hungloggerinitialdelayseconds`::
   Specifies the number of seconds to delay logging the detection of hung
   tasks. The default value is 60.