You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/09/24 19:54:17 UTC
[2/2] incubator-juneau git commit: Improve debugging support in
microservice.
Improve debugging support in microservice.
Project: http://git-wip-us.apache.org/repos/asf/incubator-juneau/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-juneau/commit/720e7ff6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-juneau/tree/720e7ff6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-juneau/diff/720e7ff6
Branch: refs/heads/master
Commit: 720e7ff6eece9535023cb6706bfc083e17d84b7c
Parents: ab8f0fa
Author: JamesBognar <ja...@apache.org>
Authored: Sun Sep 24 15:54:11 2017 -0400
Committer: JamesBognar <ja...@apache.org>
Committed: Sun Sep 24 15:54:11 2017 -0400
----------------------------------------------------------------------
juneau-doc/src/main/javadoc/overview.html | 71 ++-
.../juneau-examples-rest/examples.cfg | 140 ++++--
juneau-examples/juneau-examples-rest/jetty.xml | 15 +-
.../juneau/examples/rest/DirectoryResource.java | 3 +-
.../juneau/examples/rest/RootResources.java | 1 +
.../examples/rest/SampleRemoteableServlet.java | 8 +-
.../rest/addressbook/AddressBookResource.java | 7 +-
.../apache/juneau/microservice/JettyLogger.java | 198 +++++++++
.../juneau/microservice/Microservice.java | 199 ++++++++-
.../apache/juneau/microservice/Resource.java | 12 +-
.../juneau/microservice/ResourceGroup.java | 12 +-
.../juneau/microservice/ResourceJenaGroup.java | 12 +-
.../juneau/microservice/RestMicroservice.java | 429 +++++++------------
.../microservice/resources/DebugResource.java | 74 ++++
.../resources/DirectoryResource.java | 3 +-
.../microservice/resources/LogsResource.java | 3 +-
.../juneau-microservice-template/jetty.xml | 17 +-
.../my-microservice.cfg | 78 +++-
.../juneau-microservice-test/jetty.xml | 15 +-
.../juneau-microservice-test.cfg | 39 +-
.../juneau/rest/test/AcceptCharsetResource.java | 8 +-
.../juneau/rest/test/ContentResource.java | 6 +-
.../apache/juneau/rest/test/ParamsResource.java | 5 +-
.../java/org/apache/juneau/rest/test/Root.java | 4 +-
.../rest/test/ThirdPartyProxyResource.java | 62 ++-
.../apache/juneau/rest/test/HeadersTest.java | 5 +-
.../juneau/rest/test/TestMicroservice.java | 17 +-
.../juneau/rest/test/ThirdPartyProxyTest.java | 43 +-
.../java/org/apache/juneau/rest/CallMethod.java | 10 +-
.../org/apache/juneau/rest/RestCallHandler.java | 2 +-
.../java/org/apache/juneau/rest/RestConfig.java | 113 +++++
.../org/apache/juneau/rest/RestContext.java | 257 ++---------
.../org/apache/juneau/rest/RestException.java | 5 +-
.../juneau/rest/RestResourceResolver.java | 2 +-
.../apache/juneau/rest/RestServletDefault.java | 7 +-
.../apache/juneau/rest/annotation/FormData.java | 2 +-
.../apache/juneau/rest/annotation/Query.java | 2 +-
.../juneau/rest/annotation/RestMethod.java | 47 ++
.../juneau/rest/annotation/RestResource.java | 142 +++++-
.../java/org/apache/juneau/rest/package.html | 22 +-
40 files changed, 1403 insertions(+), 694 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-doc/src/main/javadoc/overview.html
----------------------------------------------------------------------
diff --git a/juneau-doc/src/main/javadoc/overview.html b/juneau-doc/src/main/javadoc/overview.html
index 2ea98dc..2304c63 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -5439,12 +5439,12 @@
}
),
+ <jc>// Allow INIT as a method parameter.</jc>
+ allowMethodParam=<js>"*"</js>,
+
<jc>// Properties that get applied to all serializers and parsers.</jc>
properties={
- <jc>// Allow INIT as a method parameter.</jc>
- <ja>@Property</ja>(name=<jsf>REST_allowMethodParam</jsf>, value=<js>"*"</js>),
-
<jc>// Use single quotes.</jc>
<ja>@Property</ja>(name=<jsf>SERIALIZER_quoteChar</jsf>, value=<js>"'"</js>),
@@ -6122,7 +6122,7 @@
</p>
<p>
The ability to overload methods is enabled through the
- {@link org.apache.juneau.rest.RestContext#REST_allowMethodParam} property.
+ {@link org.apache.juneau.rest.annotation.RestResource#allowMethodParam()} setting.
</p>
</div>
</div>
@@ -6163,10 +6163,8 @@
<js>"options: servlet:/?method=OPTIONS"</js>
}
),
- properties={
- <jc>// Allow us to use method=POST from a browser.</jc>
- <ja>@Property</ja>(name=<jsf>REST_allowMethodParam</jsf>, value=<js>"*"</js>)
- }
+ <jc>// Allow us to use method=POST from a browser.</jc>
+ allowMethodParam=<js>"*"</js>
)
<jk>public class</jk> SampleRemoteableServlet <jk>extends</jk> RemoteableServlet {
@@ -7448,6 +7446,7 @@
<h6 class='topic'>juneau-dto</h6>
<ul class='spaced-list'>
</ul>
+
</div>
<!-- =========================================================================================================== -->
@@ -7845,13 +7844,35 @@
{@link org.apache.juneau.rest.RestResourceResolver} instances are now inherited from parent resources to child resources
unless explicitly overridden at the child level.
<br>It's also been changed to an interface.
- <li>
- New setting: {@link org.apache.juneau.rest.RestContext#REST_resourceResolver}.
- <br>Allows you to specify a resource resolver on the servlet context to make it easier to work with
- dependency injection frameworks.
- <li>
- New annotation: {@link org.apache.juneau.rest.annotation.RestResource#contextPath()}.
- <br>Allows you to override the context path value inherited from the servlet container.
+ <li>New annotations on {@link org.apache.juneau.rest.annotation.RestResource @RestResource}:
+ <ul>
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#resourceResolver() resourceResolver()}
+ <br>Allows you to specify a resource resolver on the servlet context to make it easier to work with
+ dependency injection frameworks.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#contextPath() contextPath()} -
+ <br>Allows you to override the context path value inherited from the servlet container.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#allowHeaderParams() allowHeaderParams()} -
+ <br>Replaces the <code>RestContext.REST_allowHeaderParams</code> setting.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#allowMethodParam() allowMethodParam()} -
+ <br>Replaces the <code>RestContext.REST_allowMethodParam</code> setting.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#allowBodyParam() allowBodyParam()} -
+ <br>Replaces the <code>RestContext.REST_allowBodyParam</code> setting.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#renderResponseStackTraces() renderResponseStackTraces()} -
+ <br>Replaces the <code>RestContext.REST_xxx</code> setting.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#useStackTraceHashes() useStackTraceHashes()} -
+ <br>Replaces the <code>RestContext.REST_useStackTraceHashes</code> setting.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#defaultCharset() defaultCharset()} -
+ <br>Replaces the <code>RestContext.REST_defaultCharset</code> setting.
+ <li>{@link org.apache.juneau.rest.annotation.RestResource#paramFormat() paramFormat()} -
+ <br>Replaces the <code>RestContext.REST_paramFormat</code> setting.
+ </ul>
+ <li>New annotations on {@link org.apache.juneau.rest.annotation.RestMethod @RestMethod}:
+ <ul>
+ <li>{@link org.apache.juneau.rest.annotation.RestMethod#defaultCharset() defaultCharset()} -
+ <br>Replaces the <code>RestContext.REST_defaultCharset</code> setting.
+ <li>{@link org.apache.juneau.rest.annotation.RestMethod#paramFormat() paramFormat()} -
+ <br>Replaces the <code>RestContext.REST_paramFormat</code> setting.
+ </ul>
<li>
The following implementation classes can now be defined as non-static inner classes of servlets/resources:
<ul>
@@ -7884,12 +7905,32 @@
<h6 class='topic'>juneau-microservice</h6>
<ul class='spaced-list'>
<li>
+ The microservice has been significantly modified to be configured via a <code>jetty.xml</code> file
+ for maximum flexibility instead of the hodge-podge of support in the config file.
+ <br>Top-level servlets should now be defined in the provided <code>jetty.xml</code> file.
+ <li>
New methods on {@link org.apache.juneau.microservice.RestMicroservice}:
<ul>
<li>{@link org.apache.juneau.microservice.RestMicroservice#addServlet(Servlet,String) addServlet(Servlet,String)}
<li>{@link org.apache.juneau.microservice.RestMicroservice#addServletAttribute(String,Object) addServletAttribute(String,Object)}
<li>{@link org.apache.juneau.microservice.RestMicroservice#getServer() getServer()}
+ <li>{@link org.apache.juneau.microservice.RestMicroservice#getInstance() getInstance()}
+ <li>{@link org.apache.juneau.microservice.RestMicroservice#getPort() getPort()}
+ <li>{@link org.apache.juneau.microservice.RestMicroservice#getContextPath() getContextPath()}
+ <li>{@link org.apache.juneau.microservice.RestMicroservice#getProtocol() getProtocol()}
+ <li>{@link org.apache.juneau.microservice.RestMicroservice#getHostName() getHostName()}
</ul>
+ <li>
+ New methods on {@link org.apache.juneau.microservice.Microservice}:
+ <ul>
+ <li>{@link org.apache.juneau.microservice.Microservice#getInstance() getInstance()}
+ </ul>
+ <li>
+ New class {@link org.apache.juneau.microservice.JettyLogger} for directing Jetty logging to the
+ java.util.logging framework.
+ <li>
+ New class {@link org.apache.juneau.microservice.resources.DebugResource} for viewing and generating
+ Jetty thread dumps through REST calls.
</ul>
<h6 class='topic'>org.apache.juneau.rest.examples</h6>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/examples.cfg
----------------------------------------------------------------------
diff --git a/juneau-examples/juneau-examples-rest/examples.cfg b/juneau-examples/juneau-examples-rest/examples.cfg
index b54711b..4a8e528 100755
--- a/juneau-examples/juneau-examples-rest/examples.cfg
+++ b/juneau-examples/juneau-examples-rest/examples.cfg
@@ -11,18 +11,40 @@
# * specific language governing permissions and limitations under the License. *
# ***************************************************************************************************************************
-#================================================================================
+#=======================================================================================================================
# Basic configuration file for SaaS microservices
# Subprojects can use this as a starting point.
-#================================================================================
+#=======================================================================================================================
-#================================================================================
+# What to do when the config file is saved.
+# Possible values:
+# NOTHING - Don't do anything.
+# RESTART_SERVER - Restart the Jetty server.
+# RESTART_SERVICE - Shutdown and exit with code '3'.
+saveConfigAction = RESTART_SERVER
+
+#=======================================================================================================================
+# Jetty settings
+#=======================================================================================================================
+[Jetty]
+
+# Path of the jetty.xml file used to configure the Jetty server.
+config = jetty.xml
+
+# Resolve Juneau variables in the jetty.xml file.
+resolveVars = true
+
+# Port to use for the jetty server.
+# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
+# The resulting available port gets set as the system property "availablePort" which can be referenced in the
+# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).
+port = 10000,0,0,0
+
+#=======================================================================================================================
# REST settings
-#================================================================================
+#=======================================================================================================================
[REST]
-jettyXml = jetty.xml
-
# Stylesheet to use for HTML views.
# The default options are:
# - styles/juneau.css
@@ -31,53 +53,107 @@ jettyXml = jetty.xml
# directory.
stylesheet = styles/devops.css
-# What to do when the config file is saved.
-# Possible values:
-# NOTHING - Don't do anything.
-# RESTART_SERVER - Restart the Jetty server.
-# RESTART_SERVICE - Shutdown and exit with code '3'.
-saveConfigAction = RESTART_SERVER
-
-#================================================================================
+#=======================================================================================================================
# Logger settings
+#-----------------------------------------------------------------------------------------------------------------------
# See FileHandler Java class for details.
-#================================================================================
+#=======================================================================================================================
[Logging]
-logDir = $S{user.dir}/target/logs
-logFile = sample.%g.log
-dateFormat = yyyy.MM.dd hh:mm:ss
-format = [{date} {level}] {msg}%n
-append = false
+
+# The directory where to create the log file.
+# Default is "."
+logDir = ./target/logs
+
+# The name of the log file to create for the main logger.
+# The logDir and logFile make up the pattern that's passed to the FileHandler
+# constructor.
+# If value is not specified, then logging to a file will not be set up.
+logFile = microservice.%g.log
+
+# Whether to append to the existing log file or create a new one.
+# Default is false.
+append =
+
+# The SimpleDateFormat format to use for dates.
+# Default is "yyyy.MM.dd hh:mm:ss".
+dateFormat =
+
+# The log message format.
+# The value can contain any of the following variables:
+# {date} - The date, formatted per dateFormat.
+# {class} - The class name.
+# {method} - The method name.
+# {logger} - The logger name.
+# {level} - The log level name.
+# {msg} - The log message.
+# {threadid} - The thread ID.
+# {exception} - The localized exception message.
+# Default is "[{date} {level}] {msg}%n".
+format =
+
+# The maximum log file size.
+# Suffixes available for numbers.
+# See ConfigFile.getInt(String,int) for details.
+# Default is 1M.
limit = 10M
+
+# Max number of log files.
+# Default is 1.
count = 5
-levels = { org.apache.juneau:'INFO' }
+
+# Default log levels.
+# Format is lax-JSON.
+# Keys are logger names.
+# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
+levels =
+ {
+ '': 'WARNING',
+ org.apache.juneau: 'WARNING',
+ org.eclipse.jetty: 'WARNING'
+ }
+
+# Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
+# Useful for preventing log files from filling up with duplicate stack traces.
+# Default is false.
useStackTraceHashes = true
+
+# The default level for the console logger.
+# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
+# Default is WARNING.
consoleLevel = WARNING
-#================================================================================
+# The default level for the file logger.
+# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
+# Default is INFO.
+fileLevel = INFO
+
+#=======================================================================================================================
# System properties
-#--------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------------------------------------------------
# These are arbitrary system properties that can be set during startup.
-#================================================================================
+#=======================================================================================================================
[SystemProperties]
# Configure Jetty for StdErrLog Logging
-org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
+# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
+
+# Configure Jetty to log using java-util logging
+org.eclipse.jetty.util.log.class = org.apache.juneau.microservice.JettyLogger
# Jetty logging level
org.eclipse.jetty.LEVEL = WARN
-derby.stream.error.file = $S{user.dir}/target/logs/derby.log
+derby.stream.error.file = $C{Logging/logDir}/derby-errors.log
-#================================================================================
+#=======================================================================================================================
# DockerRegistryResource properties
-#================================================================================
+#=======================================================================================================================
[DockerRegistry]
url = http://docker.apache.org:5000/v1
-#================================================================================
+#=======================================================================================================================
# SqlQueryResource properties
-#================================================================================
+#=======================================================================================================================
[SqlQueryResource]
driver = org.apache.derby.jdbc.EmbeddedDriver
directory = $S{user.dir}/target/derby/testDB
@@ -85,9 +161,9 @@ connectionUrl = jdbc:derby:$C{SqlQueryResource/directory};create=true
allowTempUpdates = true
includeRowNums = true
-#================================================================================
+#=======================================================================================================================
# Source code location
-#================================================================================
+#=======================================================================================================================
[Source]
gitHub = https://github.com/apache/incubator-juneau/blob/master/juneau-examples-rest/src/main/java
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/jetty.xml
----------------------------------------------------------------------
diff --git a/juneau-examples/juneau-examples-rest/jetty.xml b/juneau-examples/juneau-examples-rest/jetty.xml
index 2cac2e9..d3ff1aa 100644
--- a/juneau-examples/juneau-examples-rest/jetty.xml
+++ b/juneau-examples/juneau-examples-rest/jetty.xml
@@ -24,7 +24,7 @@
<Arg>
<Ref refid="ExampleServer" />
</Arg>
- <Set name="port">10000</Set>
+ <Set name="port">$S{availablePort,8080}</Set>
</New>
</Item>
</Array>
@@ -58,7 +58,18 @@
</Set>
</New>
</Set>
-
+
+ <Set name="requestLog">
+ <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
+ <Set name="filename"><Property name="jetty.logs" default="$C{Logging/logDir,logs}"/>/jetty-requests.log</Set>
+ <Set name="filenameDateFormat">yyyy_MM_dd</Set>
+ <Set name="LogTimeZone">GMT</Set>
+ <Set name="retainDays">90</Set>
+ <Set name="append">false</Set>
+ <Set name="LogLatency">true</Set>
+ </New>
+ </Set>
+
<Get name="ThreadPool">
<Set name="minThreads" type="int">10</Set>
<Set name="maxThreads" type="int">100</Set>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java
----------------------------------------------------------------------
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java
index 0b3799f..e72b17e 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/DirectoryResource.java
@@ -17,7 +17,6 @@ import static org.apache.juneau.rest.annotation.HookEvent.*;
import static java.util.logging.Level.*;
import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.html.HtmlDocSerializerContext.*;
-import static org.apache.juneau.rest.RestContext.*;
import java.io.*;
import java.net.*;
@@ -51,9 +50,9 @@ import org.apache.juneau.utils.*;
"source: $C{Source/gitHub}/org/apache/juneau/examples/rest/$R{servletClassSimple}.java"
}
),
+ allowMethodParam="*",
properties={
@Property(name=HTML_uriAnchorText, value=PROPERTY_NAME),
- @Property(name=REST_allowMethodParam, value="*"),
@Property(name="rootDir", value="$S{java.io.tmpdir}"),
@Property(name="allowViews", value="false"),
@Property(name="allowDeletes", value="false"),
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
----------------------------------------------------------------------
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
index 9ee9abe..5520b5b 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/RootResources.java
@@ -68,6 +68,7 @@ import org.apache.juneau.rest.widget.*;
ConfigResource.class,
LogsResource.class,
DockerRegistryResource.class,
+ DebugResource.class,
ShutdownResource.class
}
)
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java
----------------------------------------------------------------------
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java
index 1306d97..a5b0aa0 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/SampleRemoteableServlet.java
@@ -12,8 +12,6 @@
// ***************************************************************************************************************************
package org.apache.juneau.examples.rest;
-import static org.apache.juneau.rest.RestContext.*;
-
import java.util.*;
import org.apache.juneau.examples.addressbook.*;
@@ -44,10 +42,8 @@ import org.apache.juneau.rest.remoteable.*;
"</div>"
}
),
- properties={
- // Allow us to use method=POST from a browser.
- @Property(name=REST_allowMethodParam, value="*")
- },
+ // Allow us to use method=POST from a browser.
+ allowMethodParam="*",
config="$S{juneau.configFile}" // So we can resolve $C{Source/gitHub} above.
)
public class SampleRemoteableServlet extends RemoteableServlet {
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
----------------------------------------------------------------------
diff --git a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
index 5569388..8776322 100644
--- a/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
+++ b/juneau-examples/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/addressbook/AddressBookResource.java
@@ -16,7 +16,6 @@ import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.html.HtmlDocSerializerContext.*;
import static org.apache.juneau.jena.RdfCommonContext.*;
import static org.apache.juneau.jena.RdfSerializerContext.*;
-import static org.apache.juneau.rest.RestContext.*;
import java.util.*;
@@ -82,12 +81,12 @@ import org.apache.juneau.utils.*;
footer="$W{PoweredByJuneau}"
),
+ // Allow INIT as a method parameter.
+ allowMethodParam="*",
+
// Properties that get applied to all serializers and parsers.
properties={
- // Allow INIT as a method parameter.
- @Property(name=REST_allowMethodParam, value="*"),
-
// Use single quotes.
@Property(name=SERIALIZER_quoteChar, value="'"),
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java
new file mode 100644
index 0000000..1c011e8
--- /dev/null
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/JettyLogger.java
@@ -0,0 +1,198 @@
+// ***************************************************************************************************************************
+// * 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.juneau.microservice;
+
+import static java.util.logging.Level.*;
+import java.util.logging.*;
+
+import org.apache.juneau.internal.*;
+import org.eclipse.jetty.util.log.AbstractLogger;
+
+/**
+ * Implementation of Jetty {@link Logger} based on {@link java.util.logging.Logger}.
+ *
+ * <p>
+ * Allows Jetty to log to the Java Util logging framework (and thus to the main log file defined in the
+ * <cc>[Logging]</cc> section).
+ *
+ * <p>
+ * Can be used by setting the following system property in the microservice config file.
+ *
+ * <p class='bcode'>
+ * <cs>[SystemProperties]</cs>
+ *
+ * <cc># Configure Jetty to log using java-util logging</cc>
+ * <ck>org.eclipse.jetty.util.log.class</ck> = org.apache.juneau.microservice.JettyLogger
+ * </p>
+ *
+ */
+public class JettyLogger extends AbstractLogger {
+ private final static boolean SHOW_SOURCE = SystemUtils.getFirstBoolean(true, "org.eclipse.jetty.util.log.SOURCE", "org.eclipse.jetty.util.log.javautil.SOURCE");
+
+ private Level configuredLevel;
+ private Logger logger;
+
+ /**
+ * Default constructor.
+ *
+ * <p>
+ * Returns the logger with name <js>"org.eclipse.jetty.util.log.javautil"</js>.
+ */
+ public JettyLogger() {
+ this("org.eclipse.jetty.util.log.javautil");
+ }
+
+ /**
+ * Normal constructor.
+ *
+ * @param name The logger name.
+ */
+ public JettyLogger(String name) {
+ logger = Logger.getLogger(name);
+ configuredLevel = logger.getLevel();
+ }
+
+ @Override
+ public String getName() {
+ return logger.getName();
+ }
+
+ @Override
+ public void warn(String msg, Object... args) {
+ if (isLoggable(WARNING))
+ log(WARNING, format(msg, args), null);
+ }
+
+ @Override
+ public void warn(Throwable thrown) {
+ if (isLoggable(WARNING))
+ log(WARNING, "", thrown);
+ }
+
+ @Override
+ public void warn(String msg, Throwable thrown) {
+ if (isLoggable(WARNING))
+ log(WARNING, msg, thrown);
+ }
+
+ @Override
+ public void info(String msg, Object... args) {
+ if (isLoggable(INFO))
+ log(INFO, format(msg, args), null);
+ }
+
+ @Override
+ public void info(Throwable thrown) {
+ if (isLoggable(INFO))
+ log(INFO, "", thrown);
+ }
+
+ @Override
+ public void info(String msg, Throwable thrown) {
+ if (isLoggable(INFO))
+ log(INFO, msg, thrown);
+ }
+
+ @Override
+ public boolean isDebugEnabled() {
+ return isLoggable(FINE);
+ }
+
+ @Override
+ public void setDebugEnabled(boolean enabled) {
+ if (enabled) {
+ configuredLevel = logger.getLevel();
+ logger.setLevel(FINE);
+ } else {
+ logger.setLevel(configuredLevel);
+ }
+ }
+
+ @Override
+ public void debug(String msg, Object... args) {
+ if (isLoggable(FINE))
+ log(FINE, format(msg, args), null);
+ }
+
+ @Override
+ public void debug(String msg, long arg) {
+ if (isLoggable(FINE))
+ log(FINE, format(msg, arg), null);
+ }
+
+ @Override
+ public void debug(Throwable thrown) {
+ if (isLoggable(FINE))
+ log(FINE, "", thrown);
+ }
+
+ @Override
+ public void debug(String msg, Throwable thrown) {
+ if (isLoggable(FINE))
+ log(FINE, msg, thrown);
+ }
+
+ @Override
+ protected org.eclipse.jetty.util.log.Logger newLogger(String fullname) {
+ return new JettyLogger(fullname);
+ }
+
+ @Override
+ public void ignore(Throwable ignored) {
+ if (isLoggable(FINEST))
+ log(FINEST, org.eclipse.jetty.util.log.Log.IGNORED, ignored);
+ }
+
+ private static String format(String msg, Object... args) {
+ msg = String.valueOf(msg);
+ if (args.length == 0)
+ return msg;
+ StringBuilder sb = new StringBuilder();
+ int start = 0;
+ for (Object arg : args) {
+ int bi = msg.indexOf("{}", start);
+ if (bi < 0) {
+ sb.append(msg.substring(start)).append(" ").append(arg);
+ start = msg.length();
+ } else {
+ sb.append(msg.substring(start, bi)).append(String.valueOf(arg));
+ start = bi + 2;
+ }
+ }
+ sb.append(msg.substring(start));
+ return sb.toString();
+ }
+
+ private void log(Level level, String msg, Throwable thrown) {
+ LogRecord r = new LogRecord(level, msg);
+ if (thrown != null)
+ r.setThrown(thrown);
+ r.setLoggerName(logger.getName());
+ if (SHOW_SOURCE) {
+ StackTraceElement[] stack = new Throwable().getStackTrace();
+ for (int i = 0; i < stack.length; i++) {
+ StackTraceElement e = stack[i];
+ if (!e.getClassName().equals(getClass().getName())) {
+ r.setSourceClassName(e.getClassName());
+ r.setSourceMethodName(e.getMethodName());
+ break;
+ }
+ }
+ }
+ logger.log(r);
+ }
+
+ private boolean isLoggable(Level level) {
+ return logger.isLoggable(level);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java
index 1e7ca26..c60187b 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Microservice.java
@@ -12,16 +12,20 @@
// ***************************************************************************************************************************
package org.apache.juneau.microservice;
+import static org.apache.juneau.internal.FileUtils.*;
import static org.apache.juneau.internal.IOUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.jar.*;
+import java.util.logging.*;
import org.apache.juneau.*;
import org.apache.juneau.ini.*;
import org.apache.juneau.internal.*;
+import org.apache.juneau.microservice.resources.*;
import org.apache.juneau.svl.*;
import org.apache.juneau.svl.vars.*;
import org.apache.juneau.utils.*;
@@ -101,21 +105,47 @@ import org.apache.juneau.utils.*;
*/
public abstract class Microservice {
- private static Args args;
- private static ConfigFile cf;
- private static ManifestFile mf;
+ private static volatile Microservice INSTANCE;
+
+ private Logger logger;
+ private Args args;
+ private ConfigFile cf;
+ private ManifestFile mf;
+ private VarResolver vr;
private String cfPath;
/**
+ * Returns the Microservice instance.
+ * <p>
+ * This method only works if there's only one Microservice instance in a JVM.
+ * Otherwise, it's just overwritten by the last call to {@link #Microservice(String...)}.
+ *
+ * @return The Microservice instance, or <jk>null</jk> if there isn't one.
+ */
+ public static Microservice getInstance() {
+ synchronized(Microservice.class) {
+ return INSTANCE;
+ }
+ }
+
+ /**
* Constructor.
*
* @param args Command line arguments.
* @throws Exception
*/
protected Microservice(String...args) throws Exception {
- Microservice.args = new Args(args);
+ setInstance(this);
+ this.args = new Args(args);
}
+
+ private static void setInstance(Microservice m) {
+ synchronized(Microservice.class) {
+ INSTANCE = m;
+ }
+ }
+
/**
* Specifies the path of the config file for this microservice.
@@ -158,8 +188,8 @@ public abstract class Microservice {
*
* @param cf The config file for this application, or <jk>null</jk> if no config file is needed.
*/
- public static void setConfig(ConfigFile cf) {
- Microservice.cf = cf;
+ public void setConfig(ConfigFile cf) {
+ this.cf = cf;
}
/**
@@ -176,8 +206,8 @@ public abstract class Microservice {
*
* @param mf The manifest file of this microservice.
*/
- public static void setManifest(Manifest mf) {
- Microservice.mf = new ManifestFile(mf);
+ public void setManifest(Manifest mf) {
+ this.mf = new ManifestFile(mf);
}
/**
@@ -189,7 +219,7 @@ public abstract class Microservice {
*/
public Microservice setManifestContents(String...contents) throws IOException {
String s = StringUtils.join(contents, "\n") + "\n";
- Microservice.mf = new ManifestFile(new Manifest(new ByteArrayInputStream(s.getBytes("UTF-8"))));
+ this.mf = new ManifestFile(new Manifest(new ByteArrayInputStream(s.getBytes("UTF-8"))));
return this;
}
@@ -199,8 +229,8 @@ public abstract class Microservice {
* @param f The manifest file of this microservice.
* @throws IOException If a problem occurred while trying to read the manifest file.
*/
- public static void setManifest(File f) throws IOException {
- Microservice.mf = new ManifestFile(f);
+ public void setManifest(File f) throws IOException {
+ this.mf = new ManifestFile(f);
}
/**
@@ -210,8 +240,8 @@ public abstract class Microservice {
* @param c The class whose jar file contains the manifest to use for this microservice.
* @throws IOException If a problem occurred while trying to read the manifest file.
*/
- public static void setManifest(Class<?> c) throws IOException {
- Microservice.mf = new ManifestFile(c);
+ public void setManifest(Class<?> c) throws IOException {
+ this.mf = new ManifestFile(c);
}
/**
@@ -285,7 +315,7 @@ public abstract class Microservice {
*
* @return The command-line arguments passed into the application.
*/
- protected static Args getArgs() {
+ public Args getArgs() {
return args;
}
@@ -382,7 +412,7 @@ public abstract class Microservice {
*
* @return The config file for this application, or <jk>null</jk> if no config file is configured.
*/
- protected static ConfigFile getConfig() {
+ public ConfigFile getConfig() {
return cf;
}
@@ -406,11 +436,30 @@ public abstract class Microservice {
*
* @return The manifest file from the main jar, or <jk>null</jk> if the manifest file could not be retrieved.
*/
- protected static ManifestFile getManifest() {
+ public ManifestFile getManifest() {
return mf;
}
+ /**
+ * Returns the variable resolver for resolving variables in strings and files.
+ * <p>
+ * See the {@link #createVarResolver()} method for the list of available resolution variables.
+ *
+ * @return The VarResolver used by this Microservice, or <jk>null</jk> if it was never created.
+ */
+ public VarResolver getVarResolver() {
+ return vr;
+ }
+ /**
+ * Returns the logger for this microservice.
+ *
+ * @return The logger for this microservice.
+ */
+ public Logger getLogger() {
+ return logger;
+ }
+
//--------------------------------------------------------------------------------
// Abstract lifecycle methods.
//--------------------------------------------------------------------------------
@@ -492,9 +541,11 @@ public abstract class Microservice {
}
}
+ vr = createVarResolver().build();
+
if (cfPath != null)
System.setProperty("juneau.configFile", cfPath);
-
+
// --------------------------------------------------------------------------------
// Set system properties.
// --------------------------------------------------------------------------------
@@ -504,6 +555,16 @@ public abstract class Microservice {
System.setProperty(key, cf.get("SystemProperties", key));
// --------------------------------------------------------------------------------
+ // Initialize logging.
+ // --------------------------------------------------------------------------------
+ try {
+ initLogging();
+ } catch (Exception e) {
+ // If logging can be initialized, just print a stack trace and continue.
+ e.printStackTrace();
+ }
+
+ // --------------------------------------------------------------------------------
// Add a config file change listener.
// --------------------------------------------------------------------------------
cf.addListener(new ConfigFileListener() {
@@ -550,6 +611,110 @@ public abstract class Microservice {
}
/**
+ * Initialize the logging for this microservice.
+ *
+ * <p>
+ * Subclasses can override this method to provide customized logging.
+ *
+ * <p>
+ * The default implementation uses the <cs>Logging</cs> section in the config file to set up logging:
+ * <p class='bcode'>
+ * <cc>#================================================================================
+ * # Logger settings
+ * # See FileHandler Java class for details.
+ * #================================================================================</cc>
+ * <cs>[Logging]</cs>
+ *
+ * <cc># The directory where to create the log file.
+ * # Default is ".".</cc>
+ * <ck>logDir</ck> = logs
+ *
+ * <cc># The name of the log file to create for the main logger.
+ * # The logDir and logFile make up the pattern that's passed to the FileHandler
+ * # constructor.
+ * # If value is not specified, then logging to a file will not be set up.</cc>
+ * <ck>logFile</ck> = microservice.%g.log
+ *
+ * <cc># Whether to append to the existing log file or create a new one.
+ * # Default is false.</cc>
+ * <ck>append</ck> =
+ *
+ * <cc># The SimpleDateFormat format to use for dates.
+ * # Default is "yyyy.MM.dd hh:mm:ss".</cc>
+ * <ck>dateFormat</ck> =
+ *
+ * <cc># The log message format.
+ * # The value can contain any of the following variables:
+ * # {date} - The date, formatted per dateFormat.
+ * # {class} - The class name.
+ * # {method} - The method name.
+ * # {logger} - The logger name.
+ * # {level} - The log level name.
+ * # {msg} - The log message.
+ * # {threadid} - The thread ID.
+ * # {exception} - The localized exception message.
+ * # Default is "[{date} {level}] {msg}%n".</cc>
+ * <ck>format</ck> =
+ *
+ * <cc># The maximum log file size.
+ * # Suffixes available for numbers.
+ * # See ConfigFile.getInt(String,int) for details.
+ * # Default is 1M.</cc>
+ * <ck>limit</ck> = 10M
+ *
+ * <cc># Max number of log files.
+ * # Default is 1.</cc>
+ * <ck>count</ck> = 5
+ *
+ * <cc># Default log levels.
+ * # Keys are logger names.
+ * # Values are serialized Level POJOs.</cc>
+ * <ck>levels</ck> = { org.apache.juneau:'INFO' }
+ *
+ * <cc># Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
+ * # Useful for preventing log files from filling up with duplicate stack traces.
+ * # Default is false.</cc>
+ * <ck>useStackTraceHashes</ck> = true
+ *
+ * <cc># The default level for the console logger.
+ * # Default is WARNING.</cc>
+ * <ck>consoleLevel</ck> = WARNING
+ * </p>
+ *
+ * @throws Exception
+ */
+ protected void initLogging() throws Exception {
+ ConfigFile cf = getConfig();
+ logger = Logger.getLogger("");
+ String logFile = cf.getString("Logging/logFile");
+ if (! isEmpty(logFile)) {
+ LogManager.getLogManager().reset();
+ String logDir = cf.getString("Logging/logDir", ".");
+ mkdirs(new File(logDir), false);
+ boolean append = cf.getBoolean("Logging/append");
+ int limit = cf.getInt("Logging/limit", 1024*1024);
+ int count = cf.getInt("Logging/count", 1);
+ FileHandler fh = new FileHandler(logDir + '/' + logFile, limit, count, append);
+
+ boolean useStackTraceHashes = cf.getBoolean("Logging/useStackTraceHashes");
+ String format = cf.getString("Logging/format", "[{date} {level}] {msg}%n");
+ String dateFormat = cf.getString("Logging/dateFormat", "yyyy.MM.dd hh:mm:ss");
+ fh.setFormatter(new LogEntryFormatter(format, dateFormat, useStackTraceHashes));
+ fh.setLevel(cf.getObjectWithDefault("Logging/fileLevel", Level.INFO, Level.class));
+ logger.addHandler(fh);
+
+ ConsoleHandler ch = new ConsoleHandler();
+ ch.setLevel(cf.getObjectWithDefault("Logging/consoleLevel", Level.WARNING, Level.class));
+ ch.setFormatter(new LogEntryFormatter(format, dateFormat, false));
+ logger.addHandler(ch);
+ }
+ ObjectMap loggerLevels = cf.getObject("Logging/levels", ObjectMap.class);
+ if (loggerLevels != null)
+ for (String l : loggerLevels.keySet())
+ Logger.getLogger(l).setLevel(loggerLevels.get(l, Level.class));
+ }
+
+ /**
* Joins the application with the current thread.
*
* <p>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java
index 0579d4b..2bb1632 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/Resource.java
@@ -13,7 +13,6 @@
package org.apache.juneau.microservice;
import static org.apache.juneau.rest.annotation.HookEvent.*;
-import static javax.servlet.http.HttpServletResponse.*;
import org.apache.juneau.rest.*;
import org.apache.juneau.rest.annotation.*;
@@ -64,11 +63,12 @@ public abstract class Resource extends RestServletDefault {
*/
@RestHook(INIT)
public void addConfigVars(RestConfig config) throws Exception {
- if (Microservice.getArgs() == null || Microservice.getConfig() == null)
- throw new RestException(SC_INTERNAL_SERVER_ERROR, "Attempting to use Resource class outside of RestMicroservice.");
- config
+ Microservice m = Microservice.getInstance();
+ if (m != null) {
+ config
.addVars(ArgsVar.class, ManifestFileVar.class)
- .addVarContextObject(ArgsVar.SESSION_args, Microservice.getArgs())
- .addVarContextObject(ManifestFileVar.SESSION_manifest, Microservice.getManifest());
+ .addVarContextObject(ArgsVar.SESSION_args, m.getArgs())
+ .addVarContextObject(ManifestFileVar.SESSION_manifest, m.getManifest());
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
index f3293cc..eab4048 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceGroup.java
@@ -12,7 +12,6 @@
// ***************************************************************************************************************************
package org.apache.juneau.microservice;
-import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.rest.annotation.HookEvent.*;
import org.apache.juneau.rest.*;
@@ -65,11 +64,12 @@ public abstract class ResourceGroup extends RestServletGroupDefault {
*/
@RestHook(INIT)
public void addConfigVars(RestConfig config) throws Exception {
- if (Microservice.getArgs() == null || Microservice.getConfig() == null)
- throw new RestException(SC_INTERNAL_SERVER_ERROR, "Attempting to use ResourceGroup class outside of RestMicroservice.");
- config
+ Microservice m = Microservice.getInstance();
+ if (m != null) {
+ config
.addVars(ArgsVar.class, ManifestFileVar.class)
- .addVarContextObject(ArgsVar.SESSION_args, Microservice.getArgs())
- .addVarContextObject(ManifestFileVar.SESSION_manifest, Microservice.getManifest());
+ .addVarContextObject(ArgsVar.SESSION_args, m.getArgs())
+ .addVarContextObject(ManifestFileVar.SESSION_manifest, m.getManifest());
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java
index 50f2075..80e31f8 100644
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/ResourceJenaGroup.java
@@ -12,7 +12,6 @@
// ***************************************************************************************************************************
package org.apache.juneau.microservice;
-import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.rest.annotation.HookEvent.*;
import org.apache.juneau.jena.*;
@@ -79,11 +78,12 @@ public abstract class ResourceJenaGroup extends RestServletGroupDefault {
*/
@RestHook(INIT)
public void addConfigVars(RestConfig config) throws Exception {
- if (Microservice.getArgs() == null || Microservice.getConfig() == null)
- throw new RestException(SC_INTERNAL_SERVER_ERROR, "Attempting to use ResourceJenaGroup class outside of RestMicroservice.");
- config
+ Microservice m = Microservice.getInstance();
+ if (m != null) {
+ config
.addVars(ArgsVar.class, ManifestFileVar.class)
- .addVarContextObject(ArgsVar.SESSION_args, Microservice.getArgs())
- .addVarContextObject(ManifestFileVar.SESSION_manifest, Microservice.getManifest());
+ .addVarContextObject(ArgsVar.SESSION_args, m.getArgs())
+ .addVarContextObject(ManifestFileVar.SESSION_manifest, m.getManifest());
+ }
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
index 8dfda47..39ce7c7 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/RestMicroservice.java
@@ -12,10 +12,6 @@
// ***************************************************************************************************************************
package org.apache.juneau.microservice;
-import static org.apache.juneau.internal.StringUtils.*;
-import static org.apache.juneau.internal.FileUtils.*;
-import static org.apache.juneau.internal.ClassUtils.*;
-
import java.io.*;
import java.net.*;
import java.util.*;
@@ -25,11 +21,11 @@ import javax.servlet.*;
import org.apache.juneau.*;
import org.apache.juneau.ini.*;
-import org.apache.juneau.json.*;
-import org.apache.juneau.microservice.resources.*;
-import org.apache.juneau.parser.*;
-import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.internal.*;
+import org.apache.juneau.svl.*;
import org.eclipse.jetty.server.*;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.handler.*;
import org.eclipse.jetty.servlet.*;
import org.eclipse.jetty.xml.*;
@@ -43,8 +39,7 @@ import org.eclipse.jetty.xml.*;
*
* <h6 class='topic'>Defining REST Resources</h6>
*
- * Top-level REST resources are defined by the {@link #getResourceMap()} method.
- * This method can be overridden to provide a customized list of REST resources.
+ * Top-level REST resources are defined in the <code>jetty.xml</code> file as normal servlets.
*
* <h6 class='topic'>Logging</h6>
*
@@ -72,12 +67,24 @@ import org.eclipse.jetty.xml.*;
*/
public class RestMicroservice extends Microservice {
- ServletContextHandler servletContextHandler;
- Server server;
- int port;
- String contextPath;
- Logger logger;
- Object jettyXml;
+ private Server server;
+ private Object jettyXml;
+
+ private static volatile RestMicroservice INSTANCE;
+
+ /**
+ * Returns the Microservice instance.
+ * <p>
+ * This method only works if there's only one Microservice instance in a JVM.
+ * Otherwise, it's just overwritten by the last call to {@link #RestMicroservice(String...)}.
+ *
+ * @return The Microservice instance, or <jk>null</jk> if there isn't one.
+ */
+ public static RestMicroservice getInstance() {
+ synchronized(RestMicroservice.class) {
+ return INSTANCE;
+ }
+ }
/**
* Main method.
@@ -100,8 +107,14 @@ public class RestMicroservice extends Microservice {
*/
public RestMicroservice(String...args) throws Exception {
super(args);
+ setInstance(this);
+ }
+
+ private static void setInstance(RestMicroservice rm) {
+ synchronized(RestMicroservice.class) {
+ INSTANCE = rm;
+ }
}
-
//--------------------------------------------------------------------------------
// Methods implemented on Microservice API
@@ -110,12 +123,6 @@ public class RestMicroservice extends Microservice {
@Override /* Microservice */
public RestMicroservice start() throws Exception {
super.start();
- try {
- initLogging();
- } catch (Exception e) {
- // If logging can be initialized, just print a stack trace and continue.
- e.printStackTrace();
- }
createServer();
startServer();
return this;
@@ -132,6 +139,7 @@ public class RestMicroservice extends Microservice {
Thread t = new Thread() {
@Override /* Thread */
public void run() {
+ Logger logger = getLogger();
try {
if (server.isStopping() || server.isStopped())
return;
@@ -162,131 +170,85 @@ public class RestMicroservice extends Microservice {
/**
* Returns the port that this microservice started up on.
+ * <p>
+ * The value is determined by looking at the <code>Server/Connectors[ServerConnector]/port</code> value in the
+ * Jetty configuration.
+ *
* @return The port that this microservice started up on.
*/
public int getPort() {
- return port;
+ for (Connector c : getServer().getConnectors())
+ if (c instanceof ServerConnector)
+ return ((ServerConnector)c).getPort();
+ throw new RuntimeException("Could not locate ServerConnector in Jetty server.");
+ }
+
+ /**
+ * Returns the context path that this microservice is using.
+ * <p>
+ * The value is determined by looking at the <code>Server/Handlers[ServletContextHandler]/contextPath</code> value
+ * in the Jetty configuration.
+ *
+ * @return The context path that this microservice is using.
+ */
+ public String getContextPath() {
+ for (Handler h : getServer().getHandlers()) {
+ if (h instanceof HandlerCollection) {
+ for (Handler h2 : ((HandlerCollection)h).getChildHandlers())
+ if (h2 instanceof ServletContextHandler)
+ return ((ServletContextHandler)h2).getContextPath();
+ }
+ if (h instanceof ServletContextHandler)
+ return ((ServletContextHandler)h).getContextPath();
+ }
+ throw new RuntimeException("Could not locate ServletContextHandler in Jetty server.");
+ }
+
+ /**
+ * Returns whether this microservice is using <js>"http"</js> or <js>"https"</js>.
+ * <p>
+ * The value is determined by looking for the existence of an SSL Connection Factorie by looking for the
+ * <code>Server/Connectors[ServerConnector]/ConnectionFactories[SslConnectionFactory]</code> value in the Jetty
+ * configuration.
+ *
+ * @return Whether this microservice is using <js>"http"</js> or <js>"https"</js>.
+ */
+ public String getProtocol() {
+ for (Connector c : getServer().getConnectors())
+ if (c instanceof ServerConnector)
+ for (ConnectionFactory cf : ((ServerConnector)c).getConnectionFactories())
+ if (cf instanceof SslConnectionFactory)
+ return "https";
+ return "http";
}
/**
- * Returns the URI where this microservice is listening on.
- * @return The URI where this microservice is listening on.
+ * Returns the hostname of this microservice.
+ * <p>
+ * Simply uses <code>InetAddress.getLocalHost().getHostName()</code>.
+ *
+ * @return The hostname of this microservice.
*/
- public URI getURI() {
- String scheme = getConfig().getBoolean("REST/useSsl") ? "https" : "http";
+ public String getHostName() {
String hostname = "localhost";
- String ctx = "/".equals(contextPath) ? null : contextPath;
try {
hostname = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {}
- try {
- return new URI(scheme, null, hostname, port, ctx, null, null);
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
+ return hostname;
}
-
+
/**
- * Initialize the logging for this microservice.
- *
- * <p>
- * Subclasses can override this method to provide customized logging.
+ * Returns the URI where this microservice is listening on.
*
- * <p>
- * The default implementation uses the <cs>Logging</cs> section in the config file to set up logging:
- * <p class='bcode'>
- * <cc>#================================================================================
- * # Logger settings
- * # See FileHandler Java class for details.
- * #================================================================================</cc>
- * <cs>[Logging]</cs>
- *
- * <cc># The directory where to create the log file.
- * # Default is ".".</cc>
- * <ck>logDir</ck> = logs
- *
- * <cc># The name of the log file to create for the main logger.
- * # The logDir and logFile make up the pattern that's passed to the FileHandler
- * # constructor.
- * # If value is not specified, then logging to a file will not be set up.</cc>
- * <ck>logFile</ck> = microservice.%g.log
- *
- * <cc># Whether to append to the existing log file or create a new one.
- * # Default is false.</cc>
- * <ck>append</ck> =
- *
- * <cc># The SimpleDateFormat format to use for dates.
- * # Default is "yyyy.MM.dd hh:mm:ss".</cc>
- * <ck>dateFormat</ck> =
- *
- * <cc># The log message format.
- * # The value can contain any of the following variables:
- * # {date} - The date, formatted per dateFormat.
- * # {class} - The class name.
- * # {method} - The method name.
- * # {logger} - The logger name.
- * # {level} - The log level name.
- * # {msg} - The log message.
- * # {threadid} - The thread ID.
- * # {exception} - The localized exception message.
- * # Default is "[{date} {level}] {msg}%n".</cc>
- * <ck>format</ck> =
- *
- * <cc># The maximum log file size.
- * # Suffixes available for numbers.
- * # See ConfigFile.getInt(String,int) for details.
- * # Default is 1M.</cc>
- * <ck>limit</ck> = 10M
- *
- * <cc># Max number of log files.
- * # Default is 1.</cc>
- * <ck>count</ck> = 5
- *
- * <cc># Default log levels.
- * # Keys are logger names.
- * # Values are serialized Level POJOs.</cc>
- * <ck>levels</ck> = { org.apache.juneau:'INFO' }
- *
- * <cc># Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
- * # Useful for preventing log files from filling up with duplicate stack traces.
- * # Default is false.</cc>
- * <ck>useStackTraceHashes</ck> = true
- *
- * <cc># The default level for the console logger.
- * # Default is WARNING.</cc>
- * <ck>consoleLevel</ck> = WARNING
- * </p>
- *
- * @throws Exception
+ * @return The URI where this microservice is listening on.
*/
- protected void initLogging() throws Exception {
- ConfigFile cf = getConfig();
- logger = Logger.getLogger("");
- String logFile = cf.getString("Logging/logFile");
- if (! isEmpty(logFile)) {
- LogManager.getLogManager().reset();
- String logDir = cf.getString("Logging/logDir", ".");
- mkdirs(new File(logDir), false);
- boolean append = cf.getBoolean("Logging/append");
- int limit = cf.getInt("Logging/limit", 1024*1024);
- int count = cf.getInt("Logging/count", 1);
- FileHandler fh = new FileHandler(logDir + '/' + logFile, limit, count, append);
-
- boolean useStackTraceHashes = cf.getBoolean("Logging/useStackTraceHashes");
- String format = cf.getString("Logging/format", "[{date} {level}] {msg}%n");
- String dateFormat = cf.getString("Logging/dateFormat", "yyyy.MM.dd hh:mm:ss");
- fh.setFormatter(new LogEntryFormatter(format, dateFormat, useStackTraceHashes));
- logger.addHandler(fh);
-
- ConsoleHandler ch = new ConsoleHandler();
- ch.setLevel(Level.parse(cf.getString("Logging/consoleLevel", "WARNING")));
- ch.setFormatter(new LogEntryFormatter(format, dateFormat, false));
- logger.addHandler(ch);
+ public URI getURI() {
+ String cp = getContextPath();
+ try {
+ return new URI(getProtocol(), null, getHostName(), getPort(), "/".equals(cp) ? null : cp, null, null);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e);
}
- ObjectMap loggerLevels = cf.getObject("Logging/levels", ObjectMap.class);
- if (loggerLevels != null)
- for (String l : loggerLevels.keySet())
- Logger.getLogger(l).setLevel(loggerLevels.get(l, Level.class));
}
/**
@@ -300,22 +262,22 @@ public class RestMicroservice extends Microservice {
* if a jetty.xml is not specified via a <code>REST/jettyXml</code> setting:
* <p class='bcode'>
* <cc>#================================================================================
- * # REST settings
+ * # Jetty settings
* #================================================================================</cc>
- * <cs>[REST]</cs>
- *
- * <cc># The HTTP port number to use.
- * # Default is Rest-Port setting in manifest file, or 8000.
- * # Can also specify a comma-delimited lists of ports to try, including 0 meaning
- * # try a random port.</cc>
- * <ck>port</ck> = 10000
- *
- * <cc># The context root of the Jetty server.
- * # Default is Rest-ContextPath in manifest file, or "/".</cc>
- * <ck>contextPath</ck> =
- *
- * <cc># Enable SSL support.</cc>
- * <ck>useSsl</ck> = false
+ * <cs>[Jetty]</cs>
+ *
+ * <cc># Path of the jetty.xml file used to configure the Jetty server.</cc>
+ * <ck>config</ck> = jetty.xml
+ *
+ * <cc># Resolve Juneau variables in the jetty.xml file.</cc>
+ * <ck>resolveVars</ck> = true
+ *
+ * <cc># Port to use for the jetty server.
+ * # You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
+ * # The resulting available port gets set as the system property "availablePort" which can be referenced in the
+ * # jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).</cc>
+ * <ck>port</ck> = 10000,0,0,0
+ * </p>
*
* @return The newly-created server.
* @throws Exception
@@ -325,47 +287,41 @@ public class RestMicroservice extends Microservice {
ConfigFile cf = getConfig();
ObjectMap mf = getManifest();
+ VarResolver vr = getVarResolver();
+
+ int[] ports = cf.getObjectWithDefault("Jetty/port", mf.getWithDefault("Jetty-Port", new int[]{8000}, int[].class), int[].class);
+ int availablePort = findOpenPort(ports);
+ System.setProperty("availablePort", String.valueOf(availablePort));
+
if (jettyXml == null)
- jettyXml = cf.getString("REST/jettyXml", mf.getString("Rest-JettyXml", null));
- if (jettyXml != null) {
- InputStream is = null;
- if (jettyXml instanceof String) {
- jettyXml = new File(jettyXml.toString());
- }
- if (jettyXml instanceof File) {
- File f = (File)jettyXml;
- if (f.exists())
- is = new FileInputStream((File)jettyXml);
- else
- throw new FormattedRuntimeException("Jetty.xml file ''{0}'' was specified but not found on the file system.", jettyXml);
- } else if (jettyXml instanceof InputStream) {
- is = (InputStream)jettyXml;
- }
-
- XmlConfiguration config = new XmlConfiguration(is);
- server = (Server)config.configure();
+ jettyXml = cf.getString("Jetty/config", mf.getString("Jetty-Config", null));
+ if (jettyXml == null)
+ throw new FormattedRuntimeException("Jetty.xml file location was not specified in the configuration file (Jetty/config) or manifest file (Jetty-Config).");
+
+ String xmlConfig = null;
+
+ if (jettyXml instanceof String)
+ jettyXml = new File(jettyXml.toString());
+
+ if (jettyXml instanceof File) {
+ File f = (File)jettyXml;
+ if (f.exists())
+ xmlConfig = IOUtils.read((File)jettyXml);
+ else
+ throw new FormattedRuntimeException("Jetty.xml file ''{0}'' was specified but not found on the file system.", jettyXml);
} else {
- int[] ports = cf.getObjectWithDefault("REST/port", mf.getWithDefault("Rest-Port", new int[]{8000}, int[].class), int[].class);
-
- port = findOpenPort(ports);
- if (port == 0) {
- System.err.println("Open port not found. Tried " + JsonSerializer.DEFAULT_LAX.toString(ports));
- System.exit(1);
- }
-
- contextPath = cf.getString("REST/contextPath", mf.getString("Rest-ContextPath", "/"));
- server = new Server(port);
-
- servletContextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
-
- servletContextHandler.setContextPath(contextPath);
- server.setHandler(servletContextHandler);
-
- for (Map.Entry<String,Class<? extends Servlet>> e : getResourceMap().entrySet())
- servletContextHandler.addServlet(e.getValue(), e.getKey()).setInitOrder(0);
+ xmlConfig = IOUtils.read(jettyXml);
}
+ if (cf.getBoolean("Jetty/resolveVars", false))
+ xmlConfig = vr.resolve(xmlConfig);
+
+ getLogger().info(xmlConfig);
+
+ XmlConfiguration config = new XmlConfiguration(new ByteArrayInputStream(xmlConfig.getBytes()));
+ server = (Server)config.configure();
+
return server;
}
@@ -378,11 +334,14 @@ public class RestMicroservice extends Microservice {
* @throws RuntimeException if {@link #createServer()} has not previously been called.
*/
public RestMicroservice addServlet(Servlet servlet, String pathSpec) {
- if (servletContextHandler == null)
- throw new RuntimeException("Servlet context handler not found. createServer() must be called first.");
- ServletHolder sh = new ServletHolder(servlet);
- servletContextHandler.addServlet(sh, pathSpec);
- return this;
+ for (Handler h : getServer().getHandlers()) {
+ if (h instanceof ServletContextHandler) {
+ ServletHolder sh = new ServletHolder(servlet);
+ ((ServletContextHandler)h).addServlet(sh, pathSpec);
+ return this;
+ }
+ }
+ throw new RuntimeException("Servlet context handler not found in jetty server.");
}
/**
@@ -394,9 +353,7 @@ public class RestMicroservice extends Microservice {
* @throws RuntimeException if {@link #createServer()} has not previously been called.
*/
public RestMicroservice addServletAttribute(String name, Object value) {
- if (server == null)
- throw new RuntimeException("Server not found. createServer() must be called first.");
- server.setAttribute(name, value);
+ getServer().setAttribute(name, value);
return this;
}
@@ -406,6 +363,8 @@ public class RestMicroservice extends Microservice {
* @return The underlying Jetty server, or <jk>null</jk> if {@link #createServer()} has not yet been called.
*/
public Server getServer() {
+ if (server == null)
+ throw new RuntimeException("Server not found. createServer() must be called first.");
return server;
}
@@ -435,85 +394,9 @@ public class RestMicroservice extends Microservice {
protected int startServer() throws Exception {
onStartServer();
server.start();
- this.port = ((ServerConnector)server.getConnectors()[0]).getLocalPort();
- logger.warning("Server started on port " + port);
+ getLogger().warning("Server started on port " + getPort());
onPostStartServer();
- return port;
- }
-
- /**
- * Returns the resource map to use for this microservice.
- *
- * <p>
- * Subclasses can override this method to programmatically specify their resources.
- *
- * <p>
- * The default implementation is configured by the following values in the config file:
- * <p class='bcode'>
- *
- * <cc>#================================================================================
- * # REST settings
- * #================================================================================</cc>
- * <cs>[REST]</cs>
- *
- * <cc># A JSON map of servlet paths to servlet classes.
- * # Example:
- * # resourceMap = {'/*':'com.foo.MyServlet'}
- * # Either resourceMap or resources must be specified if it's not defined in
- * # the manifest file.</cc>
- * <ck>resourceMap</ck> =
- *
- * <cc># A comma-delimited list of names of classes that extend from Servlet.
- * # Resource paths are pulled from @RestResource.path() annotation, or
- * # "/*" if annotation not specified.
- * # Example:
- * # resources = com.foo.MyServlet
- * * # Default is Rest-Resources in manifest file.
- * # Either resourceMap or resources must be specified if it's not defined in
- * # the manifest file.</cc>
- * <ck>resources</ck> =
- * </p>
- *
- * <p>
- * In most cases, the rest resources will be specified in the manifest file since it's not likely to be a
- * configurable property:
- * <p class='bcode'>
- * <mk>Rest-Resources:</mk> org.apache.juneau.microservice.sample.RootResources
- * </p>
- *
- * @return The map of REST resources.
- * @throws ClassNotFoundException
- * @throws ParseException
- */
- @SuppressWarnings("unchecked")
- protected Map<String,Class<? extends Servlet>> getResourceMap() throws ClassNotFoundException, ParseException {
- ConfigFile cf = getConfig();
- ObjectMap mf = getManifest();
- Map<String,Class<? extends Servlet>> rm = new LinkedHashMap<String,Class<? extends Servlet>>();
-
- ObjectMap resourceMap = cf.getObject("REST/resourceMap", ObjectMap.class);
- String[] resources = cf.getStringArray("REST/resources", mf.getStringArray("Rest-Resources"));
-
- if (resourceMap != null && ! resourceMap.isEmpty()) {
- for (Map.Entry<String,Object> e : resourceMap.entrySet()) {
- Class<?> c = Class.forName(e.getValue().toString());
- if (! isParentClass(Servlet.class, c))
- throw new ClassNotFoundException("Invalid class specified as resource. Must be a Servlet. Class='"+c.getName()+"'");
- rm.put(e.getKey(), (Class<? extends Servlet>)c);
- }
- } else if (resources.length > 0) {
- for (String resource : resources) {
- Class<?> c = Class.forName(resource);
- if (! isParentClass(Servlet.class, c))
- throw new ClassNotFoundException("Invalid class specified as resource. Must be a Servlet. Class='"+c.getName()+"'");
- RestResource rr = c.getAnnotation(RestResource.class);
- String path = rr == null ? "/*" : rr.path();
- if (! path.endsWith("*"))
- path += (path.endsWith("/") ? "*" : "/*");
- rm.put(path, (Class<? extends Servlet>)c);
- }
- }
- return rm;
+ return getPort();
}
/**
@@ -522,8 +405,6 @@ public class RestMicroservice extends Microservice {
* <p>
* The default behavior is configured by the following value in the config file:
* <p class='bcode'>
- * <cs>[REST]</cs>
- *
* <cc># What to do when the config file is saved.
* # Possible values:
* # NOTHING - Don't do anything. (default)
@@ -535,7 +416,7 @@ public class RestMicroservice extends Microservice {
@Override /* Microservice */
protected void onConfigSave(ConfigFile cf) {
try {
- String saveConfigAction = cf.getString("REST/saveConfigAction", "NOTHING");
+ String saveConfigAction = cf.getString("saveConfigAction", "NOTHING");
if (saveConfigAction.equals("RESTART_SERVER")) {
new Thread() {
@Override /* Thread */
@@ -544,7 +425,7 @@ public class RestMicroservice extends Microservice {
RestMicroservice.this.stop();
RestMicroservice.this.start();
} catch (Exception e) {
- logger.log(Level.SEVERE, e.getLocalizedMessage(), e);
+ getLogger().log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
}.start();
@@ -573,7 +454,7 @@ public class RestMicroservice extends Microservice {
* @return This object (for method chaining).
*/
public RestMicroservice setJettyXml(Object jettyXml) {
- if (jettyXml instanceof String || jettyXml instanceof File || jettyXml instanceof InputStream)
+ if (jettyXml instanceof String || jettyXml instanceof File || jettyXml instanceof InputStream || jettyXml instanceof Reader)
this.jettyXml = jettyXml;
else
throw new FormattedRuntimeException("Invalid object type passed to setJettyXml()", jettyXml == null ? null : jettyXml.getClass().getName());
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java
new file mode 100644
index 0000000..8051a72
--- /dev/null
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DebugResource.java
@@ -0,0 +1,74 @@
+// ***************************************************************************************************************************
+// * 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.juneau.microservice.resources;
+
+import java.io.*;
+
+import org.apache.juneau.internal.*;
+import org.apache.juneau.microservice.*;
+import org.apache.juneau.rest.*;
+import org.apache.juneau.rest.annotation.*;
+import org.apache.juneau.rest.labels.*;
+
+/**
+ * Microservice debug utilities.
+ */
+@RestResource(
+ path="/debug",
+ title="Debug",
+ description="Debug Utilities.",
+ htmldoc=@HtmlDoc(
+ links={
+ "up: request:/..",
+ "jetty-thread-dump: servlet:/jetty/dump?method=POST",
+ "options: servlet:/?method=OPTIONS"
+ }
+ ),
+ allowMethodParam="OPTIONS,POST"
+)
+@SuppressWarnings("javadoc")
+public class DebugResource extends Resource {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * [GET /] - Shows child utilities.
+ *
+ * @return Child utility links.
+ * @throws Exception
+ */
+ @RestMethod(name="GET", path="/", description="Show contents of config file.")
+ public ResourceDescription[] getChildren() throws Exception {
+ return new ResourceDescription[] {
+ new ResourceDescription("jetty/dump", "Jetty thread dump")
+ };
+ }
+
+ /**
+ * [GET /jetty/dump] - Generates and retrieves the jetty thread dump.
+ */
+ @RestMethod(name="GET", path="/jetty/dump", description="Generates and retrieves the jetty thread dump.")
+ public Reader getJettyDump(RestRequest req, RestResponse res) {
+ res.setContentType("text/plain");
+ return new StringReader(RestMicroservice.getInstance().getServer().dump());
+ }
+
+ /**
+ * [POST /jetty/dump] - Generates and saves the jetty thread dump file to jetty-thread-dump.log.
+ */
+ @RestMethod(name="POST", path="/jetty/dump", description="Generates and saves the jetty thread dump file to jetty-thread-dump.log.")
+ public String createJettyDump(RestRequest req, RestResponse res) throws Exception {
+ String dump = RestMicroservice.getInstance().getServer().dump();
+ IOUtils.pipe(dump, new FileWriter(req.getConfigFile().getString("Logging/logDir") + "/jetty-thread-dump.log"));
+ return "OK";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
index 0c0edc4..744b3a1 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/DirectoryResource.java
@@ -15,7 +15,6 @@ package org.apache.juneau.microservice.resources;
import static java.util.logging.Level.*;
import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.html.HtmlDocSerializerContext.*;
-import static org.apache.juneau.rest.RestContext.*;
import java.io.*;
import java.net.*;
@@ -69,9 +68,9 @@ import org.apache.juneau.utils.*;
"options: servlet:/?method=OPTIONS"
}
),
+ allowMethodParam="*",
properties={
@Property(name=HTML_uriAnchorText, value=PROPERTY_NAME),
- @Property(name=REST_allowMethodParam, value="*"),
@Property(name="DirectoryResource.rootDir", value="")
}
)
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
index d98b77d..4e9938f 100755
--- a/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
+++ b/juneau-microservice/juneau-microservice-server/src/main/java/org/apache/juneau/microservice/resources/LogsResource.java
@@ -14,7 +14,6 @@ package org.apache.juneau.microservice.resources;
import static javax.servlet.http.HttpServletResponse.*;
import static org.apache.juneau.html.HtmlDocSerializerContext.*;
-import static org.apache.juneau.rest.RestContext.*;
import static org.apache.juneau.rest.annotation.HookEvent.*;
import static org.apache.juneau.internal.StringUtils.*;
@@ -44,7 +43,7 @@ import org.apache.juneau.transforms.*;
properties={
@Property(name=HTML_uriAnchorText, value=PROPERTY_NAME),
},
- flags={REST_allowMethodParam},
+ allowMethodParam="*",
pojoSwaps={
IteratorSwap.class, // Allows Iterators and Iterables to be serialized.
DateSwap.ISO8601DT.class // Serialize Date objects as ISO8601 strings.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-template/jetty.xml
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-template/jetty.xml b/juneau-microservice/juneau-microservice-template/jetty.xml
index 77c5cf0..3fc3408 100644
--- a/juneau-microservice/juneau-microservice-template/jetty.xml
+++ b/juneau-microservice/juneau-microservice-template/jetty.xml
@@ -24,7 +24,7 @@
<Arg>
<Ref refid="ExampleServer" />
</Arg>
- <Set name="port">10000</Set>
+ <Set name="port">$S{availablePort,8080}</Set>
</New>
</Item>
</Array>
@@ -55,11 +55,22 @@
</Set>
</New>
</Set>
-
+
+ <Set name="requestLog">
+ <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
+ <Set name="filename"><Property name="jetty.logs" default="$C{Logging/logDir,logs}"/>/jetty-requests.log</Set>
+ <Set name="filenameDateFormat">yyyy_MM_dd</Set>
+ <Set name="LogTimeZone">GMT</Set>
+ <Set name="retainDays">90</Set>
+ <Set name="append">false</Set>
+ <Set name="LogLatency">true</Set>
+ </New>
+ </Set>
+
<Get name="ThreadPool">
<Set name="minThreads" type="int">10</Set>
<Set name="maxThreads" type="int">100</Set>
<Set name="idleTimeout" type="int">60000</Set>
<Set name="detailedDump">true</Set>
- </Get>
+ </Get>
</Configure>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/720e7ff6/juneau-microservice/juneau-microservice-template/my-microservice.cfg
----------------------------------------------------------------------
diff --git a/juneau-microservice/juneau-microservice-template/my-microservice.cfg b/juneau-microservice/juneau-microservice-template/my-microservice.cfg
index 2f461a3..41c7ed9 100755
--- a/juneau-microservice/juneau-microservice-template/my-microservice.cfg
+++ b/juneau-microservice/juneau-microservice-template/my-microservice.cfg
@@ -11,18 +11,40 @@
# * specific language governing permissions and limitations under the License. *
# ***************************************************************************************************************************
-#================================================================================
+#=======================================================================================================================
# Basic configuration file for SaaS microservices
# Subprojects can use this as a starting point.
-#================================================================================
+#=======================================================================================================================
-#================================================================================
+# What to do when the config file is saved.
+# Possible values:
+# NOTHING - Don't do anything. (default)
+# RESTART_SERVER - Restart the Jetty server.
+# RESTART_SERVICE - Shutdown and exit with code '3'.
+saveConfigAction = RESTART_SERVER
+
+#=======================================================================================================================
+# Jetty settings
+#=======================================================================================================================
+[Jetty]
+
+# Path of the jetty.xml file used to configure the Jetty server.
+config = jetty.xml
+
+# Resolve Juneau variables in the jetty.xml file.
+resolveVars = true
+
+# Port to use for the jetty server.
+# You can specify multiple ports. The first available will be used. '0' indicates to try a random port.
+# The resulting available port gets set as the system property "availablePort" which can be referenced in the
+# jetty.xml file as "$S{availablePort}" (assuming resolveVars is enabled).
+port = 10000,0,0,0
+
+#=======================================================================================================================
# REST settings
-#================================================================================
+#=======================================================================================================================
[REST]
-jettyXml = jetty.xml
-
# Stylesheet to use for HTML views.
# The default options are:
# - servlet:/styles/juneau.css
@@ -30,17 +52,11 @@ jettyXml = jetty.xml
# Other stylesheets can be referenced relative to the servlet package or working directory.
stylesheet = servlet:/styles/devops.css
-# What to do when the config file is saved.
-# Possible values:
-# NOTHING - Don't do anything. (default)
-# RESTART_SERVER - Restart the Jetty server.
-# RESTART_SERVICE - Shutdown and exit with code '3'.
-saveConfigAction = RESTART_SERVER
-
-#================================================================================
+#=======================================================================================================================
# Logger settings
+#-----------------------------------------------------------------------------------------------------------------------
# See FileHandler Java class for details.
-#================================================================================
+#=======================================================================================================================
[Logging]
# The directory where to create the log file.
@@ -85,9 +101,15 @@ limit = 10M
count = 5
# Default log levels.
+# Format is lax-JSON.
# Keys are logger names.
-# Values are serialized Level POJOs.
-levels = { org.apache.juneau:'INFO' }
+# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
+levels =
+ {
+ '': 'WARNING',
+ org.apache.juneau: 'WARNING',
+ org.eclipse.jetty: 'WARNING'
+ }
# Only print unique stack traces once and then refer to them by a simple 8 character hash identifier.
# Useful for preventing log files from filling up with duplicate stack traces.
@@ -95,18 +117,30 @@ levels = { org.apache.juneau:'INFO' }
useStackTraceHashes = true
# The default level for the console logger.
+# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
# Default is WARNING.
-consoleLevel =
+consoleLevel = WARNING
+
+# The default level for the file logger.
+# Values are serialized Level POJOs (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST)
+# Default is INFO.
+fileLevel = INFO
-#================================================================================
+#=======================================================================================================================
# System properties
-#--------------------------------------------------------------------------------
+#-----------------------------------------------------------------------------------------------------------------------
# These are arbitrary system properties that are set during startup.
-#================================================================================
+#=======================================================================================================================
[SystemProperties]
# Configure Jetty for StdErrLog Logging
-org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
+# org.eclipse.jetty.util.log.class = org.eclipse.jetty.util.log.StrErrLog
+
+# Configure Jetty to log using java-util logging
+org.eclipse.jetty.util.log.class = org.apache.juneau.microservice.JettyLogger
# Jetty logging level
+# Possible values: ALL, DEBUG, INFO, WARN, OFF
org.eclipse.jetty.LEVEL = WARN
+
+derby.stream.error.file = $C{Logging/logDir}/derby-errors.log