diff --git a/src/main/java/act/metric/MetricEnhancer.java b/src/main/java/act/metric/MetricEnhancer.java
index e4cb7efff..ce3e521d0 100644
--- a/src/main/java/act/metric/MetricEnhancer.java
+++ b/src/main/java/act/metric/MetricEnhancer.java
@@ -81,7 +81,7 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = super.visitAnnotation(desc, visible);
if (DESC_MEASURE_TIME.equals(desc)) {
- timeLabel = methodName;
+ timeLabel = metricsLabel();
return new AnnotationVisitor(ASM5, av) {
@Override
public void visit(String name, Object value) {
@@ -92,7 +92,7 @@ public void visit(String name, Object value) {
}
};
} else if (DESC_MEASURE_COUNT.equals(desc)) {
- countLabel = methodName;
+ countLabel = metricsLabel();
return new AnnotationVisitor(ASM5, av) {
@Override
public void visit(String name, Object value) {
@@ -162,6 +162,10 @@ private void onFinally(int opcode) {
mv.visitVarInsn(ALOAD, posTimer);
mv.visitMethodInsn(INVOKEINTERFACE, "act/metric/Timer", "close", "()V", true);
}
+
+ private String metricsLabel() {
+ return S.pathConcat(className, '.', methodName);
+ }
};
}
}
diff --git a/src/main/java/act/test/TestSession.java b/src/main/java/act/test/TestSession.java
index 918c27b62..f62ea52eb 100644
--- a/src/main/java/act/test/TestSession.java
+++ b/src/main/java/act/test/TestSession.java
@@ -432,8 +432,20 @@ private Object getVal(String key) {
return evalFunc(key);
} catch (Exception e) {
try {
- return getLastVal(key);
+ o = getLastVal(key);
+ if (null == o) {
+ o = App.instance().config().get(key);
+ if (null != o) {
+ return o;
+ }
+ throw E.unexpected("Unable to get value by key: %s", key);
+ }
+ return o;
} catch (Exception e1) {
+ o = App.instance().config().get(key);
+ if (null != o) {
+ return o;
+ }
throw E.unexpected("Unable to get value by key: %s", key);
}
}
diff --git a/testapps/GH1332/pack b/testapps/GH1332/pack
new file mode 100755
index 000000000..d4daf2bc9
--- /dev/null
+++ b/testapps/GH1332/pack
@@ -0,0 +1,6 @@
+#!/bin/sh
+echo build ...
+mvn -q compile
+echo run test and then package ...
+mvn -q package
+echo package has been built up and stored in target/dist dir
\ No newline at end of file
diff --git a/testapps/GH1332/pack.bat b/testapps/GH1332/pack.bat
new file mode 100644
index 000000000..44b5e3aa2
--- /dev/null
+++ b/testapps/GH1332/pack.bat
@@ -0,0 +1,5 @@
+echo build ...
+mvn -q compile
+echo run test and then package ...
+mvn -q package
+echo package has been built up and stored in target/dist dir
\ No newline at end of file
diff --git a/testapps/GH1332/pom.xml b/testapps/GH1332/pom.xml
new file mode 100644
index 000000000..28f03db51
--- /dev/null
+++ b/testapps/GH1332/pom.xml
@@ -0,0 +1,52 @@
+
+
+ 4.0.0
+
+ com.mycom.helloworld
+ GH1332
+ 1.0-SNAPSHOT
+
+ My Awesome Application
+
+
+ org.actframework
+ act-starter-parent
+ 1.9.2.0
+
+
+
+ com.mycom.gh1322.AppEntry
+
+
+
+
+
+
+
+
+
+
+
+ org.actframework
+ act
+ 1.9.3-SNAPSHOT
+
+
+
+
\ No newline at end of file
diff --git a/testapps/GH1332/run_dev b/testapps/GH1332/run_dev
new file mode 100755
index 000000000..56d7f76cd
--- /dev/null
+++ b/testapps/GH1332/run_dev
@@ -0,0 +1,3 @@
+#!/bin/sh
+echo building ...
+mvn -q compile act:run
\ No newline at end of file
diff --git a/testapps/GH1332/run_dev.bat b/testapps/GH1332/run_dev.bat
new file mode 100755
index 000000000..28b0270e1
--- /dev/null
+++ b/testapps/GH1332/run_dev.bat
@@ -0,0 +1,2 @@
+echo building ...
+mvn -q compile act:run
\ No newline at end of file
diff --git a/testapps/GH1332/run_prod b/testapps/GH1332/run_prod
new file mode 100755
index 000000000..451f36553
--- /dev/null
+++ b/testapps/GH1332/run_prod
@@ -0,0 +1,13 @@
+#!/bin/sh
+if [ ! -f target/dist/start ]; then
+ echo building ...
+ mvn -q clean package
+ cd target/dist
+ tar xzf *.tar.gz
+else
+ cd target/dist
+fi
+# we want to disable session secure as this is running
+# in the local host, we don't expect there are SSL
+# certificate enabled.
+./run -Dsession.secure=false $*
\ No newline at end of file
diff --git a/testapps/GH1332/src/main/java/com/mycom/gh1322/AppEntry.java b/testapps/GH1332/src/main/java/com/mycom/gh1322/AppEntry.java
new file mode 100644
index 000000000..b1546f4fe
--- /dev/null
+++ b/testapps/GH1332/src/main/java/com/mycom/gh1322/AppEntry.java
@@ -0,0 +1,49 @@
+package com.mycom.gh1322;
+
+import act.Act;
+import act.metric.MeasureCount;
+import act.metric.MeasureTime;
+import org.osgl.logging.LogManager;
+import org.osgl.logging.Logger;
+import org.osgl.mvc.annotation.GetAction;
+import org.osgl.util.S;
+import osgl.version.Version;
+import osgl.version.Versioned;
+
+/**
+ * A simple hello world app entry
+ *
+ * Run this app, try to update some of the code, then
+ * press F5 in the browser to watch the immediate change
+ * in the browser!
+ */
+@SuppressWarnings("unused")
+@Versioned
+public class AppEntry {
+
+ /**
+ * Version of this application
+ */
+ public static final Version VERSION = Version.of(AppEntry.class);
+
+ /**
+ * A logger instance that could be used throughout the application
+ */
+ public static final Logger LOGGER = LogManager.get(AppEntry.class);
+
+ @GetAction
+ public String getFoo() {
+ return foo();
+ }
+
+ @MeasureCount
+ @MeasureTime
+ private String foo() {
+ return S.random();
+ }
+
+ public static void main(String[] args) throws Exception {
+ Act.start();
+ }
+
+}
diff --git a/testapps/GH1332/src/main/resources/com/mycom/gh1322/.version b/testapps/GH1332/src/main/resources/com/mycom/gh1322/.version
new file mode 100644
index 000000000..ea0c26126
--- /dev/null
+++ b/testapps/GH1332/src/main/resources/com/mycom/gh1322/.version
@@ -0,0 +1,3 @@
+artifact=${project.artifactId}
+version=${project.version}
+build=${buildNumber}
\ No newline at end of file
diff --git a/testapps/GH1332/src/main/resources/conf/app.properties b/testapps/GH1332/src/main/resources/conf/app.properties
new file mode 100644
index 000000000..2cc17c62b
--- /dev/null
+++ b/testapps/GH1332/src/main/resources/conf/app.properties
@@ -0,0 +1,933 @@
+# Application configuration
+# act-1.9.2
+
+# When `api_doc` is enabled it can navigate to
+# http://localhost:5460/~/api
+# for API Document.
+#
+# API doc is enabled by default
+#
+# uncomment to disable API doc
+#api_doc=false
+
+# When `api_doc.built_in.hide` is enabled the API document
+# will not display built-in endpoints, e.g.
+# `/~/info`
+#
+# built-in endpoints is visible in API doc by default
+#
+# uncomment to hide built-in endpoints in API doc
+#api_doc.built_in.hide=true
+
+# `app.name` set application name
+#
+# default value: archetype-quickstart
+#app.name=archetype-quickstart
+
+# `basic_authentication` is not used by actframework
+# core, however plugins like `act-aaa-plugin` use
+# this configuration to check if HTTP basic
+# authentication is allowed.
+#
+# basic authentication is disabled by default
+#
+# uncomment to enable basic authentication
+#basic_authentication=true
+
+# When `built_in_req_handler` is disabled it will
+# not be able to access framework built-in endpoints
+# including `/~/info`, `/~/version` etc.
+# However the following built-in endpoints is still
+# available:
+# * GET /~/job/{id}/progress - required by runtime application
+# * GET /~/api/book/** - only available in dev mode
+#
+# built-in endpoints is enabled by default
+#
+# uncomment to disable built endpoints
+#built_in_req_handler=false
+
+# Configure the cache implementation used by ActFramework.
+# The cache class specified must implement
+# `org.osgl.cache.CacheServiceProvider` interface.
+#
+# If not specified cache implementation is determined by
+# osgl-cache library automatically depending on the
+# libraries available in the following order:
+# 1. Memcached service
+# 2. EhCache service
+# 3. OSGL implemented Simple Cache service based on concurrent hash map
+#
+# uncomment to set your own cache implementation
+#cache.impl=
+
+# Specify the default cache name
+#
+# default value: _act_app_
+#cache.name=
+
+# Specify session cache name
+#
+# If not specified then the name is the value of 'cache.name'
+#
+# default value: configuration of 'cache.name'
+#cache.name.session=
+
+# By default @CacheFor annotation is not effective in `dev` mode.
+# the `cacheFor.dev` configuration can be used to turn on
+# @CacheFor in `dev` mode.
+#
+# uncomment to enable @CacheFor annotation in `dev` mode
+#cacheFor.dev=true
+
+# CLI service listens to local ip addresses to provide telent
+# access for command line access to the running app.
+#
+# CLI service is enabled by default
+#
+# uncomment to disable CLI service
+#cli=false
+
+# By default CLI port is `5461`
+#
+# uncomment to set CLI port
+#cli.port=
+
+# `cli.page.size.json` specifies the number of records to display
+# per page for CLI JSON view.
+#
+# Default CLI JSON view page size is 10 records
+#
+# uncomment to set CLI JSON view page size
+#cli.page.size.json=
+
+# `cli.page.size.table` specifies the number of records to display
+# per page for CLI tabular view.
+#
+# Default CLI table view page size is 22 records
+#
+# uncomment to set CLI table view page size
+#cli.page.size.table=
+
+# `cli.progress-bar.style` specifies how the CLI progress bar
+# should be rendered.
+#
+# At the moment there are two options:
+# * unicode - default option, use unicode chars to render progress bar
+# * ascii - use ASCII char to render progress bar
+#
+# Default value: block
+#
+#cli.progress-bar.style=block|ascii
+
+# `cli.session.ttl` specifies the number of seconds a CLI
+# session will be terminated without interaction.
+#
+# The default CLI session ttl is 300 seconds, i.e. 5 minutes
+#
+# uncomment to set CLI session ttl
+#cli.session.ttl
+
+# `cli.session.max.int` specifies the maximum concurrent CLI session
+#
+# The default limits is 3
+#
+# uncomment to set CLI session max
+#cli.session.max.int
+
+# `conf-loader.impl`
+# specify customized application configuration loader.
+# it should be a class name of an implementation of
+# `act.conf.ExtendedAppConfLoader`
+#
+# Default value: `act.conf.ExtendedAppConfLoader.DumbLoader`
+#conf-loader.impl=
+
+# `conf-server.endpoint` specify the remote configuration server endpoint
+# Once this is set when app configuration initialised it will send a GET
+# request to `${conf-server.endpoint}?key=${app.key}
+#
+# Note once `conf-server.endpoint` is configured then it assume the
+# `conf.private-key` is configured correctly, otherwise the framework
+# will refuse to pull configuration from the `conf-server.endpont` and
+# raise an exception.
+#
+# Default value: null
+#conf-server.endpoint=https://conf-server/conf
+
+# `conf.id` set application key - could be used to fetch configuration
+# from configuration server.
+#
+# Default value: ${app.name}-${profile}
+#conf.id=${app.name}-${profile}
+
+# `conf.private-key` set the private key for the app_key.
+# the private key is used to decrypt the response coming from
+# `conf-server.endpoint`.
+#
+# Default value: null
+#conf.private-key=...
+
+# `cookie.prefix` specifies the session/flash cookie prefix.
+#
+# The default cookie prefix is the `shortId` of the application.
+#
+# uncomment to customize session/flash cookie prefix.
+#cookie.prefix=
+
+# When `cors` is enabled ActFramework will automatically populate the
+# CORS relevant headers in HTTP response.
+#
+# When `cors` is disabled all other `cors` relevant settings is not effective.
+#
+# By default `CORS` is disabled
+#
+# uncomment to enable CORS support
+#cors=true
+
+
+# `cors.origin` set the `Access-Control-Allow-Origin` response header.
+#
+# Default CORS origin header value is `*`
+#cors.origin=
+
+# `cors.headers`
+#
+# THIS CONFIGURATION IS DEPRECATED SINCE 1.8.29
+#cors.headers=
+
+# `cors.headers.expose` set the `Access-Control-Expose-Headers` response header.
+#
+# Default value: `Act-Session-Expires, Authorization, X-XSRF-Token, X-CSRF-Token, Location, Link, Content-Disposition, Content-Length`.
+#cors.headers.expose=Act-Session-Expires, Authorization, X-XSRF-Token, X-CSRF-Token, Location, Link, Content-Disposition, Content-Length
+
+# `cors.headers.allowed` set the `Access-Control-Allow-Headers` response header.
+#
+# Default value: `X-HTTP-Method-Override, X-Requested-With, Authorization, X-XSRF-Token, X-CSRF-Token`.
+#cors.headers.allowed=X-HTTP-Method-Override, X-Requested-With, Authorization, X-XSRF-Token, X-CSRF-Token
+
+# `cors.max_age` set the `Access-Control-Max-Age` response header
+#
+# Default value is `30*60` i.e. 30 minutes
+#cors.max_age
+
+# `cors.allow_credentials.enabled` set the `Access-Control-Allow-Credential` response header
+#
+# By default this setting is disabled
+#
+# Uncomment the set `Access-Control-Allow-Credential` to `true`
+#cors.allow_credentials=true
+
+# If `content_suffix.aware` is enabled the framework adjust Request `Accept`
+# header based on URL suffix.
+#
+# E.g. `/customer/123/json` will match the route `/customer/123`
+# and set the `Accept` header of the incoming request to `application/json`
+#
+# By default `content_suffix.aware` is disabled.
+#
+# Uncomment to enable `content_suffix.aware.enabled`
+#content_suffix.aware.enabled=true
+
+# `csp` set the `Content-Security-Policy` response header value.
+#
+# By default `csp` is not set.
+#csp=
+
+# `csrf` turn on/off the CSRF protection.
+# See https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
+#
+# By default `csrf` protection is disabled
+#
+# uncomment to turn on CSRF protection.
+#csrf=true
+
+# `csrf.param_name` specifies the http request param name
+# used to convey the csrf token.
+#
+# Default value: `__csrf__`
+#csrf.param_name
+
+# `csrf.header.name` specifies name of the http request header
+# used to convey the csrf token sent from AJAX client.
+#
+# Default value: `X-Xsrf-Token`
+#csrf.header_name=
+
+# `csrf.cookie_name` specify the name of the cookie used to
+# convey the csrf token generated on the server for the first GET
+# request coming from a client.
+#
+# Default value: `XSRF-TOKEN`
+#csrf.cookie_name
+
+# `csrf.protector` specifies the implementation of `act.security.CSRFProtector`.
+#
+# Default protector implementation is `HMAC`
+#
+# uncomment to set csrf protector implementation
+#csrf.protector=RANDOM|className
+
+# `db.seq_gen` specifies the implementation of `act.db.util._SequenceNumberGenerator`
+#
+# Default value is `null` or an implementation specified by db plugin
+#db.seq_gen=
+
+# `dsp.token` specifies the name of "double submission protect token"
+#
+# Default value: `act_dsp_token`
+#dsp.token=
+
+# `enum.resolving.exact_match` specify whether it shall resolve enum value
+# in exact matching way or Keyword based variation way.
+#
+# Keyword based variation matching explain:
+#
+# Suppose we have an enum defination: `enum TestEnum {FOO_BAR}
+# All the following string variations can be resolved to `TestEnum.FOO_BAR`:
+#
+# * FOO_BAR
+# * Foo-Bar
+# * Foo.Bar
+# * foo-bar
+# * foo_bar
+# * FooBar
+# * fooBar
+#
+# Default value is `false` meaning enum type value resolving is
+# non-exact matching
+#
+# uncomment to make Enum type parameter resolving be exact matching
+#enum.resolving.exact_match=false
+
+# `fmt.date` specifies the pattern for Date type value resolving
+#
+# The setting can be any one of
+# - long
+# - medium
+# - short
+# - custom pattern, e.g. `EEE yyyy MMM dd`
+#
+# Note custom pattern shall not contain any symbol for time, e.g. `H` or `m`
+# Default value: `medium`
+#fmt.date=
+
+# `fmt..date` specifies the pattern for Date type for specific locale
+#
+# It can specify date formats for multiple locales
+#
+# Default value: `medium`
+# see also: `fmt.date`
+#fmt.zh_cn.date=yyyy年MM月dd日
+
+
+# `fmt.data_time` specifies the pattern for DataTime type value resolving.
+#
+# The setting can be any one of
+# - long
+# - medium
+# - short
+# - custom pattern, e.g. `EEE yyyy MMM dd`
+#
+# Default value: `medium`
+#fmt.date_time=
+
+# `fmt..date_time` specifies the pattern for DateTime type for specific locale
+#
+# It can specify date_time formats for multiple locales
+#
+# Default value: `medium`
+# see also: `fmt.date_time`
+#fmt.zh_cn.date_time=yyyy年MM月dd日 HH:mm
+
+# `fmt.time` specifies the pattern for Time type value resolving
+#
+# The setting can be any one of
+# - long
+# - medium
+# - short
+# - custom pattern, e.g. `HHmmss`
+#
+# Note custom pattern shall not contain any symbol for date, e.g. `y` or `M`
+# Default value: `medium`
+#fmt.time=
+
+# `fmt..time` specifies the pattern for Time type for specific locale.
+#
+# It can specify time formats for multiple locales
+#
+# Default value: `medium`
+# see also: `fmt.time`
+#fmt.zh_cn.time=HH:mm
+
+# `globalReturnValueAdvice` specifies the global `ReturnValueAdvice` implementation
+#
+# Default value: `null`
+#globalReturnValueAdvice=ghissues.Gh835$GlobalAdvice
+
+# `handler.csrf_check_failure` specifies the implemetation of `MissingAuthenticationHandler`
+# to be called when CSRF checking failed.
+#
+# Default value is the setting of `handler.missing_authentication`
+#handler.csrf_check_failure=
+
+# `handler.missing_authentication` specifies the implemetation of `MissingAuthenticationHandler`
+# to be called when authentication is failed on an non-AJAX request.
+#
+# Default value is `act.util.RedirectToLoginUrl` if login URL is in the route table.
+# otherwise it is `act.util.ReturnUnauthorized`
+#handler.missing_authentication=
+
+# `handler.missing_authentication` specifies the implemetation of `MissingAuthenticationHandler`
+# to be called when authentication is failed on an AJAX request.
+#
+# Default value is the setting of `handler.missing_authentication`
+#handler.missing_authentication.ajax=
+
+# `handler.unknown_http_method` specifies the handler implementation to be called
+# when ActFramework found the HTTP method of an incoming request is not supported
+#
+# Default value is `UnknownHttpMethodProcessor.METHOD_NOT_ALLOWED`, i.e.
+# respond `405 Method Not Allowed` response.
+#handler.unknown_http_method=
+
+# `act.header.overwrite` turn on/off HTTP HEADER overwrite.
+#
+# Once this config is turned on, then it can overwrite header
+# with HTTP Query parameter or HTTP post form field. The naming
+# convention of the param/field is:
+#
+# ```
+# act_header_
+# ```
+#
+# For example, if it needs to overwrite `Content-Type`, use
+# `act_header_content_type` as the query parameter name.
+#
+# Default value: `false`
+#header.overwrite=true
+
+
+# `header.session.expiration` specifies name of the HTTP response header to be
+# used to convey the JWT/session cookie expiration time.
+#
+# Default value is `Act-Session-Expires`
+#header.session.expiration=
+
+# `host` specifies the hostname of the application.
+#
+# This setting is often used to concatentate full URL including host
+# in email template.
+#
+# Default value: `localhost`
+#host=
+
+# `http.external_server` specify if the app is running behind a frontend
+# http server, e.g. nginx.
+#
+# Default value: `true` when running in `prod` mode or `false` when running in `dev` mode
+#http.external_server=true|false
+
+# `http.params.max` specifies the maximum number of http parameters.
+#
+# This setting can be to prevent the hash collision DOS attack.
+#
+# Default value: 128
+#http.params.max=
+
+# `http.port` specifies the default HTTP port number
+#
+# Default value: 5460
+#http.port=
+
+# `http.port.external` specifies the default HTTP port number of
+# frontend HTTP server (if exists).
+#
+# Default value: 80
+#http.port.external=
+
+# `http.port.external.secure` specifies the default HTTPS port number of
+# the frontend HTTP server (if exists)
+#
+# Default value: 443
+#http.port.external.secure=
+
+# `http.secure` specifies whether the default http port is running in
+# an secure HTTP channel
+#
+# Default value: `true` when running in `prod` mode or `false` in `dev` mode
+#http.secure=true|false
+
+# `https.port` specify the https port - only effect
+# when `ssl` is enabled.
+#
+# Default value: `5443`
+#https.port=
+
+# `i18n` turn on/off i18n support in ActFramework.
+#
+# Default value: false
+#i18n=true|false
+
+# `i18n.locale.param_name` specifies the param name to set client locale
+# in http request
+#
+# Default value: `act_locale`
+#i18n.locale.param_name=
+
+# `i18n.locale.cookie_name` specifies the name for the locale cookie
+#
+# Default value: `act_locale`
+#i18n.locale.cookie_name=
+
+# `idgen.node_id.provider` specifies the implementation of
+# `act.util.IdGenerator.NodeIdProvider` which is called when generating the
+# CUID (Custer Unique Identifier)
+#
+# Default value: `act.util.IdGenerator.NodeIdProvider.IpProvider`
+#idgen.node_id.provider=
+
+# `idgen.node_id.effective_ip_bytes.size` specifies how many bytes in the ip address
+# will be used to calculate node ID. Usually in a cluster environment, the ip address will
+# be different at only (last) one byte or (last) two bytes, in which case it could set this
+# configuration to `1` or `2`. When the configuration is set to `4` then it means all 4 IP
+# bytes will be used to calculate the node ID
+#
+# Default value: 4
+#idgen.node_id.effective_ip_bytes.size=1|2|3|4
+
+# `idgen.start_id.provider` specifies the `act.util.IdGenerator.StartIdProvider`
+# implementation which is called when generating the CUID
+#
+# Default value: `act.util.IdGenerator.StartIdProvider.DefaultStartIdProvider`
+# which read/write the file specified by `idgen.start_id.file` setting in
+# the project dir.
+#idgen.start_id.provider=
+
+# `idgen.start_id.file` specifies the start id persistent file.
+# This setting is used by `act.util.IdGenerator.StartIdProvider.DefaultStartIdProvider`
+#
+# Default value: `.act.id-app`
+#idgen.start_id.file=
+
+# `idgen.seq_id.provider` specifies the `act.util.IdGenerator.SequenceProvider`
+# implementation which is called when generating the CUID.
+#
+# Default value: `act.util.IdGenerator.SequenceProvider.AtomicLongSeq`
+#idgen.seq_id.provider=
+
+# `idgen.encoder` specifies the `act.util.IdGenerator.LongEncoder` implementation
+# which is called when generating the CUID.
+#
+# Default value: `act.util.IdGenerator.SafeLongEncoder` which generates URL
+# safe and slighty longer string for long value encoding.
+#idgen.encoder=act.util.IdGenerator.SafeLongEncoder|act.util.IdGenerator.UnsafeLongEncoder
+
+# `job.pool.size` specifies the maximum number of threads
+# can exists in the application's job manager's thread pool
+#
+# Default value: 10
+#job.pool.size=
+
+# `jwt` enable/disable JWT support.
+# This is actually a combination of the following settings:
+# * session.codec=act.session.JsonWebTokenSessionCodec
+# * session.header.payload.prefix="Bearer " # note the space after `Bearer`
+# * session.header=Authorization
+#jwt=true|false
+
+# `jwt.algo` specifies the algorithm used to encrypt/decrypt JWT.
+#
+# Default value: SHA256
+#jwt.algo=SHA256|SHA384|SHA512
+
+# `jwt.issuer` specify `iss` payload of JWT
+#
+# Default value: the setting of `cookie.prefix`
+#jwt.issuer=
+
+# `json_body_patch` enable/disable JSON body patch
+#
+# Default value: `true`
+#json_body_patch.enabled=true
+
+# `locale` specifies the application default locale
+#
+# Default value: the result of calling `java.util.Locale#getDefault()`
+#locale=
+
+# `metric` turn on/off internal metrics.
+#
+# Default value: true
+#metric=true|false
+
+# `modules` declare additional app base (for multi-module maven projects)
+#modules=
+
+# `monitor.enabled` specifies whether turn on monitor thread
+#
+# default value: `false`
+# monitor.enabled=true
+
+# `namedPorts` specifies a list of port names this
+# application listen to. These are additional ports other than
+# the default `http.port` setting.
+#
+# Default value: null
+#namedPorts=admin:8888;ipc:8899;...
+
+# `param_binding.keyword_matching` turn on/off keyword matching in HTTP param binding
+# process.
+#
+# When this configuration is turned on the framework is able to do keyword matching
+# to bind the HTTP parameter, e.g. when it declare to bind a parameter named `fooBar`,
+# when request is sending with parameter named `foo_bar`, it can still finish the bind.
+#
+# **Note** turning on this configuration might cause slightly performance degrade.
+#
+# Default value: `false`
+#param_binding.keyword_matching=false
+
+# `password.spec` specify default password spec which is used to
+# validate user password.
+#
+# Default value:
+# * dev mode: `a[3,]`, meaning require lower case letter and min length is 3 characters.
+# * prod mode: `aA0[6,]`, meaning require lower case letter, uppercase letter, digit and min length is 6 characters.
+#
+# Developer can also specify a `Password.Validator` implementation
+# class for this configuration, in which case, the framework will instantiate the user
+# specified validator instead of `act.validation.PasswordSpec` as the default
+# password validator.
+#
+#password.spec=
+
+# `ping.path` specify the ping path.
+# If this setting is specified, then when session resolving, system
+# will check if the current URL matches the setting. If matched
+# then session cookie expiration time will not be changed. Otherwise
+# the expiration time will refresh
+#
+# Default value: `null`
+#ping.path=
+
+# `req.throttle` specifies the maximum number of requests
+# that can be handled per second from the same ip address
+# when `@Throttled` annotation is presented without `value`
+# specified on a request handler method.
+#
+# Default value: 2
+#req.throttle=
+
+# `req.throttle.expire.scale` turn on/off request throttle
+# expiry time increment.
+#
+# Default value: `false`
+#req.throttle.expire.scale=true|false
+
+# `render.json.content_type.ie` specify whether the content type
+# of JSON response on request initiated from an IE browser.
+#
+# Note early IE browser does not support the `application/json` content type.
+#
+# Default value: `null`
+#render.json.content_type.ie=
+
+# `resolver.template_path` specifies the class that extends
+# `TemplatePathResolver`. Application developer could use this
+# configuration to add some flexibility to
+# template path resolving logic, e.g. different home
+# for different locale or different home for different device
+# type etc
+#
+# Default value: `TemplatePathResolver`
+#resolver.template_path
+
+#
+# Enable/disable resource filtering (only impact dev mode)
+#
+# Default value: `true`
+#resource.filtering=true
+
+# `resource.preload.size.limit` Specifies the maximum number of bytes of
+# a resource that can be preload into memory. Specify the setting to
+# `0` or negative value disable resource preload feature.
+#
+# Default value: `1024 * 10`, i.e. 10KB
+#resource.preload.size.limit=
+
+# `resource_bundle.encoding` specifies encoding of resource bundles.
+# This configuration allows override the default resource bundle
+# encoding setting used by specific Java runtime:
+# - Before Java 9: ISO-8859-1
+# - Java 9 and above: UTF-8
+#
+# Default value: `null` meaning follow JDK default encoding setting
+#resource_bundle.encoding=utf-8
+
+# `scan_package` specify the app package in which all classes is subject
+# to bytecode processing, e.g enhancement and injection.
+#
+# By default ActFramework will infer the scan package
+# from the app entry class which contains the main method
+# starting act.
+#
+#scan_package=
+
+# `act.secret` Specifies the secret key the application used to do general
+# encrypt/decrypt/sign etc
+#
+# Note application must set this configuration to secure the communication
+act.secret=xCGE8jBC3v1KUm38gnqLoJAQ23l25rcYXJ1ExpLqtZjshUhyZ6LwVRmkHJvXV6WK
+
+# `secret.rotate` turn on app secret rotation for session/flash
+# token signing and encrypt. This feature makes it even harder
+# to crack as secret changes regularly.
+#
+# Default value: false
+#secret.rotate=true|false
+
+# `secret.rotate.period` set the secret rotate period in terms of minute.
+#
+# **Note** the number of minute must be a factor of 60. Any number that
+# is not the factor of 60 then it will be up rounded:
+#
+# * 1 -> 1
+# * 2 -> 2
+# * 3 -> 4
+# * 4 -> 4
+# * 5 -> 5
+# * 6 -> 6
+# * 7 -> 10
+# * 8 -> 10
+# * 33 -> 30
+# * 50 -> 60
+#
+# the rotation period less than hour will be count from the beginning of
+# the current hour.
+#
+# If the number minutes exceeds 60, then it must be a factor of 60 * 24. Any
+# number if not will be rounded:
+#
+# * 65 -> 60
+# * 60 * 3 -> 60 * 3
+# * 60 * 5 -> 60 * 6
+# * 60 * 7 -> 60 * 6
+# * 60 * 10 -> 60 * 12 (half day)
+#
+# if the number of minutes equals of exceeds 120, the rotation period will
+# be counted from the beginning of the day.
+#
+# The maximum period is `60 * 24`, i.e. 24 hours. Any setting exceed that number
+# will be cut off down to 24 hours.
+#
+# Default value: `30` minutes, ie. half an hour
+#secret.rotate.period=
+
+# `server.header` specifies the server header to be output to the response
+#
+# Default value: `act/${act-version}`
+#server.header=
+
+#`session.outputExpiration.enabled` turn on/off expiration output to
+# response header.
+#
+# This setting only effective when it is using token to
+# map session payload.
+#
+# Default value: `true`
+#session.outputExpiration=true|false
+
+# `session.ttl` specifies the session duration in seconds.
+# If user failed to interact with server for amount of time that
+# exceeds the setting then the session will be destroyed
+#
+# Default value: `60 * 30` i.e half an hour
+#session.ttl=
+
+# `session.persistent` specify whether the system
+# should treat session cookie as persistent cookie. If this setting
+# is enabled, then the user's session will not be destroyed after
+# browser closed.
+#
+# Refer to http://en.wikipedia.org/wiki/HTTP_cookie#Persistent_cookie
+#
+# Default value: `false`
+#session.persistent=true|false
+
+# `session.encrypt` specify whether the system should
+# encrypt the key/value pairs in the session cookie. Enable session
+# encryption will greatly improve the security but with the cost
+# of additional CPU usage and a little bit longer time on request
+# processing.
+#
+# Default value: `false`
+#session.encrypt=true|false
+
+# `session.key.username` specifies the session key for username
+#
+# Default value: `username`
+#session.key.username=
+
+# `session.mapper` specifies the implementation of `act.session.SessionMapper`
+# Predefined session mappers:
+# * `act.session.CookieSessionMapper` - map session data to session cookie
+# * `act.session.HeaderTokenSessionMapper` - map session data to header token
+# * `act.session.CookieAndHeaderSessionMapper` - map session data to both cookie and header
+#
+# Default value:`act.session.CookieSessionMapper`
+#session.mapper=
+
+# `session.codec` specifies the implementation of `act.session.SessionCodec`
+# Predefined session codec:
+# * `act.session.DefaultSessionCodec`
+# * `act.session.JsonWebTokenSessionCodec`
+#
+# Default value: `act.session.DefaultSessionCodec` when `jwt` is `false`
+# or `act.session.JsonWebTokenSessionCodec` when `jwt` is `true`
+#session.codec=
+
+# `session.header` - specify the session header name.
+#
+# Effective only when `act.session.SessionMapper` is `act.session.HeaderTokenSessionMapper`
+#
+# Default value: X-Act-Session when `jwt` is `false`
+# or `Authorization` when `jwt` is `true`
+#session.header=
+
+# `session.header.payload.prefix` set the session payload prefix, e.g. `Bearer `
+#
+# Default value: `null` when `jwt` is `false`
+# or `Bearer ` when `jwt` is `true`
+#session.header.payload.prefix=
+
+# `session.secure` specifies whether the session cookie should
+# be set as secure. Enable secure session will cause session cookie only
+# effective in https connection. Literally this will enforce the web site to run
+# default by https.
+#
+# Default value: `true`
+#
+# **Note** when {@link Act Act server} is running in {@link Act.Mode#DEV mode}
+# session http only will be disabled without regarding to the `session.secure.enabled`
+# setting
+#session.secure=true|false
+
+# `source.version` specifies the java version
+# of the src code. This configuration is used only
+# in dev mode.
+#
+# Default value: 1.7
+#source.version=
+
+# `ssl` turn on/off SSL support.
+#
+# Default value: `false`
+#
+# **Note** this is experimental feature
+#ssl=true|false
+
+# `system.self-healing` turn on/off system self healing.
+# Refer GH #1234
+#
+# Default value: `false`
+#
+#system.self-healing=true|false
+
+# `target.version` specifies the java version of the compile
+# target code. This configuration is used only in dev mode.
+#
+# Default value: 1.7
+#target.version=
+
+# `template.home` specifies where the view templates resides.
+# If not specified then will use the {@link View#name() view name
+# in lower case} as the template home if that view is used.
+#
+# Default value: the result of `View.name()`
+#template.home=
+
+# `threadlocal_buf.limit` set the maximum buffer size of thread local instance
+# of `org.osgl.util.S.Buffer` and `org.osgl.util.ByteArrayBuffer`. If the buffer
+# size exceeds the limit, the thread local instance will be dropped and new
+# instance will be created as the thread local instance.
+#
+# Default value: 1024 * 8 (i.e. 8k)
+#threadlocal_buf.limit=
+
+# `trace.handler` turn on/off handle invocation calls.
+#
+# When this configuration is turned on, every call to the
+# action handler/job handler/mail sender method will be logged.
+#
+# Default value: `false`
+#trace.handler=true|false
+
+# `trace.request` turn on/off incoming request log
+#
+# When this configuration is turned on, every incoming request
+# will be logged
+#
+# default value: `false`
+#trace.request=true|false
+
+# `upload.in_memory.threshold`
+#
+# If file upload content length is less than this configuration then
+# the file will not get written into disk, instead it will get cached
+# into a in memory byte array
+#
+# Default value: `1024 * 10`
+#upload.in_memory.threshold
+
+# `url.context` specifies the app global URL context.
+#
+# If this configuration is specified then all route configured will
+# be attached to the configured context path.
+#
+# Default value: `null`
+#url.context=
+
+# `url.login` specifies the login URL which is used
+# by {@link act.util.RedirectToLoginUrl}
+#
+# Default value: `/login`
+#url.login=
+
+# `url.login.ajax` specifies the login URL which is used
+# by {@link act.util.RedirectToLoginUrl} when request is AJAX
+#
+# Default value: the value of `url.login` setting
+#url.login.ajax
+
+# `view.default` specifies the default view solution. If there
+# are multiple views registered and default view are available, then
+# it will be used at priority to load the templates
+#
+# Default value: `rythm`
+#view.default=
+
+# `ws.key.ticket`
+#
+# Specifies the parameter variable name to get websocket ticket
+#
+# Default value: `ws_ticket`
+#ws.key.ticket=ws_ticket
+
+# `ws.purge-closed-conn.period`
+#
+# Specifies the waiting period in seconds to purge closed websocket connections
+#
+# Default value: `10` in PROD mode, `1` in DEV mode
+#ws.purge-closed-conn.period=10
+
+
+# `xio.worker_threads.max` specifies the maximum worker thread for XIO.
+#
+# Default value: `0`, meaning let system to decide the number of worker threads
+#xio.worker_threads.max=0
+
+# `xio.statistics.enabled` turn on/off statistics in XIO layer
+#
+# Default value: `false`
+#xio.statistics.enabled=false
diff --git a/testapps/GH1332/src/main/resources/conf/cron.properties b/testapps/GH1332/src/main/resources/conf/cron.properties
new file mode 100644
index 000000000..eb2031340
--- /dev/null
+++ b/testapps/GH1332/src/main/resources/conf/cron.properties
@@ -0,0 +1,24 @@
+# A few sample cron settings that could be
+# referred by app
+#
+# act-1.9.2
+
+# NOTE - this file is deprecated
+# It recommend to use the constant
+# defined in act.job.Cron annotation
+# e.g. Cron.CRON_2AM or Cron.CRON_12PM etc
+
+# triggered at 12am every day
+#cron.midnight=0 0 0 * * *
+
+# triggered at 12am every weekdays (Mon to Fri)
+#cron.midnight.weekdays=0 0 0 * * 1-5
+
+# triggered at 12am every last day of a month
+#cron.midnight.last-day-of-mon=0 0 0 * * L
+
+# triggered at 12pm every day
+#cron.noon=0 0 12 * * *
+
+# triggered at 12pm every weekdays (Mon to Fri)
+#cron.noon=0 0 12 * * 1-5
diff --git a/testapps/GH1332/src/main/resources/conf/prod/app.properties b/testapps/GH1332/src/main/resources/conf/prod/app.properties
new file mode 100644
index 000000000..d836ad62f
--- /dev/null
+++ b/testapps/GH1332/src/main/resources/conf/prod/app.properties
@@ -0,0 +1,3 @@
+# Application configuration for prod profile
+# act-1.9.2
+act.secret=znC2CEqPCYfU5OF5DRB5n7GIN5syhFZC8lg7AyEUue7PxKxqEjgF4vuGGjYAvj9s
\ No newline at end of file
diff --git a/testapps/GH1332/src/main/resources/conf/test.properties b/testapps/GH1332/src/main/resources/conf/test.properties
new file mode 100644
index 000000000..8636c1273
--- /dev/null
+++ b/testapps/GH1332/src/main/resources/conf/test.properties
@@ -0,0 +1,52 @@
+# Application configuration for test support
+# act-1.9.2
+
+# Specify application model package here.
+# once this is set it can refer to model class name
+# directly in fixture.yml files, no need for
+# full qualified class name
+#
+# default value: null
+#test.model-packages=demo.models
+
+# Specify application issue template URL
+# once this is set, it will enable link test scenario to
+# application issue in issue tracking system automatically
+#
+# default value null
+#test.issueUrlTemplate=https://github.com/act-gallery/bookmark/issues/%s
+#test.issueUrlTemplate=https://www.atlassian.com/software/jira/%s
+
+# Specify common URL context used in scenario files
+#
+# default value: null
+#test.urlContext=/api/v1
+
+# `test.delay` specifies the seconds it shall wait before starting automate test.
+# the value must be in integer, the unit of the value is second.
+#
+# Default value: 0
+#test.delay=5
+#test.delay=0
+
+# `test.timeout` specifies automate test http agent timeout in seconds.
+#
+# Default value: 10 in automate test mode, 60 * 60 in dev mode (for debugging purpose)
+#test.timeout=60
+
+# Specify where the framework should load data fixtures
+# the folder will be used to patch fixture file name
+# specified in scenario.yml file when loading it.
+#
+# default value: /test/fixtures/
+#test.fixture-folder=/test/fixtures/
+
+#
+# The following are test inbox SMTP settings
+# Once they are set, then framework can login
+# to the inbox and verify email sending
+#test.inbox.account=your-testing-email
+#test.inbox.password=your-secret-password
+test.inbox.protocol=imaps # current imaps is the only supported protocol
+#test.inbox.host=your-inbox-host.com
+#test.inbox.port=your-inbox-port
diff --git a/testapps/GH1332/src/main/resources/conf/uat/app.properties b/testapps/GH1332/src/main/resources/conf/uat/app.properties
new file mode 100644
index 000000000..41e5515f2
--- /dev/null
+++ b/testapps/GH1332/src/main/resources/conf/uat/app.properties
@@ -0,0 +1,3 @@
+# Application configuration for uat profile
+# act-1.9.2
+act.secret=klpXODEAKtJFn3WPE8GYGQIyAKebPTiaFj6c18wXczTmipF4pvBQDFPe9CfIodOt
\ No newline at end of file
diff --git a/testapps/GH1332/src/main/resources/logback.xml b/testapps/GH1332/src/main/resources/logback.xml
new file mode 100644
index 000000000..953d7d90d
--- /dev/null
+++ b/testapps/GH1332/src/main/resources/logback.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+ true
+
+ %date %highlight(%-5level) %cyan(%logger{5}@[%-4.30thread]) - %msg%n
+
+
+
+
+
+
+ true
+
+ %msg%n
+
+
+
+
+
+ act.log
+
+ %d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+ /act.%i.log.zip
+ 1
+ 10
+
+
+
+ 2MB
+
+
+
+
+
+ test.log
+
+ %msg%n
+
+
+
+
+ act-db.log
+
+ %d{yyyy-MM-dd_HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+ /act-db.%i.log.zip
+ 1
+ 10
+
+
+
+ 2MB
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testapps/GH1332/test b/testapps/GH1332/test
new file mode 100755
index 000000000..e32ec2e85
--- /dev/null
+++ b/testapps/GH1332/test
@@ -0,0 +1,3 @@
+#!/bin/sh
+echo building ...
+mvn -q compile act:test
\ No newline at end of file
diff --git a/testapps/GH1332/test.bat b/testapps/GH1332/test.bat
new file mode 100644
index 000000000..a324f34a0
--- /dev/null
+++ b/testapps/GH1332/test.bat
@@ -0,0 +1,2 @@
+echo building ...
+mvn -q compile act:test
\ No newline at end of file
diff --git a/testapps/GHIssues/.gitignore b/testapps/GHIssues/.gitignore
index 0577ee63e..0f3be5cec 100644
--- a/testapps/GHIssues/.gitignore
+++ b/testapps/GHIssues/.gitignore
@@ -17,4 +17,5 @@ test.trace.db
act.pid
.workspace
*.geany
-upload*
\ No newline at end of file
+*.db
+upload*
diff --git a/testapps/GHIssues/pom.xml b/testapps/GHIssues/pom.xml
index d9ba8cb88..64bb9b455 100644
--- a/testapps/GHIssues/pom.xml
+++ b/testapps/GHIssues/pom.xml
@@ -25,7 +25,7 @@
org.actframework
act
- 1.9.2-SNAPSHOT
+ 1.9.3-SNAPSHOT
org.actframework
diff --git a/testapps/GHIssues/src/main/java/ghissues/Gh1429.java b/testapps/GHIssues/src/main/java/ghissues/Gh1429.java
new file mode 100644
index 000000000..2553b8cbf
--- /dev/null
+++ b/testapps/GHIssues/src/main/java/ghissues/Gh1429.java
@@ -0,0 +1,17 @@
+package ghissues;
+
+import act.controller.annotation.UrlContext;
+import act.util.JsonView;
+import act.util.PropertySpec;
+import org.osgl.mvc.annotation.GetAction;
+import org.osgl.util.N;
+import org.osgl.util.S;
+
+@UrlContext("1429")
+public class Gh1429 extends BaseController {
+
+ @GetAction
+ public String echo(String message) {
+ return message;
+ }
+}
diff --git a/testapps/GHIssues/src/main/resources/conf/1429.properties b/testapps/GHIssues/src/main/resources/conf/1429.properties
new file mode 100644
index 000000000..eb90551bf
--- /dev/null
+++ b/testapps/GHIssues/src/main/resources/conf/1429.properties
@@ -0,0 +1 @@
+gh1429.message=hello
\ No newline at end of file
diff --git a/testapps/GHIssues/src/test/resources/scenarios/1429.yml b/testapps/GHIssues/src/test/resources/scenarios/1429.yml
new file mode 100644
index 000000000..3f95fab37
--- /dev/null
+++ b/testapps/GHIssues/src/test/resources/scenarios/1429.yml
@@ -0,0 +1,8 @@
+Scenario(1429):
+ description: "Test sceanrio yaml file shall be able to refer values defined in app config properties file"
+ interactions:
+ - description: test
+ request:
+ get: 1429?message=${gh1429.message}
+ response:
+ result: ${gh1429.message}
\ No newline at end of file