JUNEAU-106 Improved REST debugging.
diff --git a/eclipse-preferences/org.eclipse.jdt.core.prefs b/eclipse-preferences/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..880e185
--- /dev/null
+++ b/eclipse-preferences/org.eclipse.jdt.core.prefs
@@ -0,0 +1,476 @@
+# ***************************************************************************************************************************
+# * 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. *
+# ***************************************************************************************************************************
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled
+org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
+org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
+org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
+org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
+org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
+org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
+org.eclipse.jdt.core.compiler.codegen.methodParameters=generate
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.APILeak=warning
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
+org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
+org.eclipse.jdt.core.compiler.problem.deadCode=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
+org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
+org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
+org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=warning
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
+org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
+org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=all_standard_tags
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=warning
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=protected
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
+org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
+org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
+org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
+org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
+org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
+org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
+org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled
+org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
+org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
+org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
+org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
+org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedImport=warning
+org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
+org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
+org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
+org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
+org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
+org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false
+org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false
+org.eclipse.jdt.core.formatter.align_with_spaces=false
+org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16
+org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0
+org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
+org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=false
+org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.indent_tag_description=false
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
+org.eclipse.jdt.core.formatter.comment.line_length=200
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=1
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=true
+org.eclipse.jdt.core.formatter.indentation.size=3
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never
+org.eclipse.jdt.core.formatter.lineSplit=200
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
+org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=false
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/eclipse-preferences/org.eclipse.jdt.ui.prefs b/eclipse-preferences/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..f09a9ac
--- /dev/null
+++ b/eclipse-preferences/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,81 @@
+# ***************************************************************************************************************************
+# * 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. *
+# ***************************************************************************************************************************
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=false
+cleanup.always_use_parentheses_in_expressions=false
+cleanup.always_use_this_for_non_static_field_access=false
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=false
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=false
+cleanup.never_use_blocks=true
+cleanup.never_use_parentheses_in_expressions=true
+cleanup.organize_imports=false
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=false
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_modifiers=false
+cleanup.remove_redundant_semicolons=false
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=true
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=false
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=false
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=false
+cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+cleanup.use_this_for_non_static_method_access=false
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup_profile=_juneau-cleanup-rules
+cleanup_settings_version=2
+eclipse.preferences.version=1
+formatter_profile=_juneau-formatter-rules
+formatter_settings_version=16
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.javadoc=false
+org.eclipse.jdt.ui.ondemandthreshold=1
+org.eclipse.jdt.ui.staticondemandthreshold=1
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="false" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * Bean property getter\: <property>${bare_field_name}</property>.\n *\n * @return The value of the <property>${bare_field_name}</property> property on this bean, or <jk>null</jk> if it is not set.\n */</template><template autoinsert\="false" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * Bean property setter\: <property>${bare_field_name}</property>.\n *\n * @param ${param} The new value for the <property>${bare_field_name}</property> property on this bean.\n * @return This object (for method chaining).\n */</template><template autoinsert\="false" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * TODO\n * \n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">// ***************************************************************************************************************************\n// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file *\n// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file *\n// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance *\n// * with the License. You may obtain a copy of the License at * \n// * *\n// * http\://www.apache.org/licenses/LICENSE-2.0 *\n// * *\n// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an *\n// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the *\n// * specific language governing permissions and limitations under the License. *\n// ***************************************************************************************************************************</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * TODO\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="false" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * TODO\n * \n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="false" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * TODO\n * \n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="true" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="false" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">this.${field} \= ${param};</template></templates>
diff --git a/juneau-release-launch.launch b/juneau-release.launch
similarity index 79%
rename from juneau-release-launch.launch
rename to juneau-release.launch
index 36da94a..93ec99d 100644
--- a/juneau-release-launch.launch
+++ b/juneau-release.launch
@@ -3,6 +3,6 @@
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/juneau-root/juneau-release.sh}"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/juneau-root}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/juneau/juneau-release.sh}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/juneau}"/>
</launchConfiguration>
diff --git a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
index 4316e50..6d14568 100644
--- a/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
+++ b/juneau-rest/juneau-rest-server-utest/src/test/java/org/apache/juneau/rest/headers/AcceptCharsetTest.java
@@ -65,7 +65,7 @@
// Validate various Accept-Charset variations.
//=================================================================================================================
- @RestResource(defaultCharset="utf-8", debug="true")
+ @RestResource(defaultCharset="utf-8")
public static class B {
@RestMethod(name=PUT, parsers=TestParser.class, serializers=TestSerializer.class)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
index f7174fa..d7d555d 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestCallHandler.java
@@ -107,6 +107,7 @@
logger.log(FINE, "HTTP: {0} {1}", r1.getMethod(), r1.getRequestURI());
long startTime = System.currentTimeMillis();
RestRequest req = null;
+ RestResponse res = null;
try {
context.checkForInitException();
@@ -130,6 +131,8 @@
pathInfo = RestUtils.getPathInfoUndecoded(r1); // Can't use r1.getPathInfo() because we don't want '%2F' resolved.
upi = new UrlPathInfo(pathInfo);
} else {
+ if (isDebug(req))
+ r1 = CachingHttpServletRequest.wrap(req);
r2.setStatus(SC_NOT_FOUND);
return;
}
@@ -148,6 +151,8 @@
.servletPath(r1.getServletPath() + uppm.getPrefix());
rc.getCallHandler().service(childRequest, r2);
} else {
+ if (isDebug(req))
+ r1 = CachingHttpServletRequest.wrap(req);
r2.setStatus(SC_NOT_FOUND);
}
return;
@@ -155,10 +160,16 @@
}
}
+ if (isDebug(req)) {
+ r1 = CachingHttpServletRequest.wrap(r1);
+ r2 = CachingHttpServletResponse.wrap(r2);
+ r1.setAttribute("Debug", true);
+ }
+
context.startCall(r1, r2);
req = createRequest(r1);
- RestResponse res = createResponse(req, r2);
+ res = createResponse(req, r2);
req.setResponse(res);
context.setRequest(req);
context.setResponse(res);
@@ -218,12 +229,18 @@
res.flushBuffer();
req.close();
+ r1 = req.getInner();
+ r2 = res.getInner();
r1.setAttribute("ExecTime", System.currentTimeMillis() - startTime);
+ logger.log(r1, r2);
} catch (Throwable e) {
e = convertThrowable(e);
+ r1 = req.getInner();
+ r2 = res.getInner();
r1.setAttribute("Exception", e);
r1.setAttribute("ExecTime", System.currentTimeMillis() - startTime);
+ logger.log(r1, r2);
handleError(r1, r2, e);
} finally {
context.clearState();
@@ -234,6 +251,19 @@
logger.log(FINE, "HTTP: [{0} {1}] finished in {2}ms", r1.getMethod(), r1.getRequestURI(), System.currentTimeMillis()-startTime);
}
+ private boolean isDebug(HttpServletRequest req) {
+ if (! context.isDebug())
+ return false;
+ String debugHeader = context.getDebugHeader(), debugParam = context.getDebugParam();
+ if (debugHeader == null && debugParam == null)
+ return true;
+ if (debugHeader != null && "true".equalsIgnoreCase(req.getHeader(debugHeader)))
+ return true;
+ if (debugParam != null && "true".equalsIgnoreCase(req.getParameter(debugParam)))
+ return true;
+ return false;
+ }
+
/**
* The main method for serializing POJOs passed in through the {@link RestResponse#setOutput(Object)} method or
* returned by the Java method.
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestLogger.java
index 3a84ba7..e7e9f07 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestLogger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/BasicRestLogger.java
@@ -16,12 +16,14 @@
import static org.apache.juneau.internal.StringUtils.*;
import java.text.*;
+import java.util.*;
import java.util.logging.*;
import javax.servlet.http.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
+import org.apache.juneau.rest.util.*;
/**
* Logging utility class.
@@ -250,7 +252,77 @@
return contains(req.getHeader("No-Trace"), "true") || contains(req.getQueryString(), "noTrace=true");
}
- private static boolean isDebug(HttpServletRequest req) {
- return contains(req.getHeader("Debug"), "true");
+ @Override /* RestLogger */
+ public void log(HttpServletRequest req, HttpServletResponse res) {
+ if (isDebug(req)) {
+
+ String qs = req.getQueryString();
+ String method = req.getMethod();
+ byte[] reqBody = req instanceof CachingHttpServletRequest ? ((CachingHttpServletRequest)req).getBody() : null;
+ byte[] resBody = res instanceof CachingHttpServletResponse ? ((CachingHttpServletResponse)res).getBody() : null;
+ Throwable e = (Throwable)req.getAttribute("Exception");
+ Long execTime = (Long)req.getAttribute("ExecTime");
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("\n=== HTTP Request (incoming) ====================================================");
+ sb.append("\n").append(method).append(" ").append(req.getRequestURI()).append((qs == null ? "" : "?" + qs));
+ sb.append("\n\tResponse code: ").append(res.getStatus());
+ if (execTime != null)
+ sb.append("\n\tExec time: ").append(res.getStatus()).append("ms");
+ if (reqBody != null)
+ sb.append("\n\tReq body: ").append(reqBody.length).append(" bytes");
+ if (resBody != null)
+ sb.append("\n\tRes body: ").append(resBody.length).append(" bytes");
+ sb.append("\n---Request Headers---");
+ for (Enumeration<String> hh = req.getHeaderNames(); hh.hasMoreElements();) {
+ String h = hh.nextElement();
+ sb.append("\n\t").append(h).append(": ").append(req.getHeader(h));
+ }
+ if (context != null && ! context.getDefaultRequestHeaders().isEmpty()) {
+ sb.append("\n---Default Servlet Headers---");
+ for (Map.Entry<String,Object> h : context.getDefaultRequestHeaders().entrySet()) {
+ sb.append("\n\t").append(h.getKey()).append(": ").append(h.getValue());
+ }
+ }
+ if (reqBody != null && reqBody.length > 0) {
+ try {
+ sb.append("\n---Request Body UTF-8---");
+ sb.append("\n").append(new String(reqBody, IOUtils.UTF8));
+ sb.append("\n---Request Body Hex---");
+ sb.append("\n").append(toSpacedHex(reqBody));
+ } catch (Exception e1) {
+ sb.append("\n").append(e1.getLocalizedMessage());
+ }
+ }
+ sb.append("\n---Response Headers---");
+ for (String h : res.getHeaderNames()) {
+ sb.append("\n\t").append(h).append(": ").append(res.getHeader(h));
+ }
+ if (resBody != null && resBody.length > 0) {
+ try {
+ sb.append("\n---Response Body UTF-8---");
+ sb.append("\n").append(new String(resBody, IOUtils.UTF8));
+ sb.append("\n---Response Body Hex---");
+ sb.append("\n").append(toSpacedHex(resBody));
+ } catch (Exception e1) {
+ sb.append(e1.getLocalizedMessage());
+ }
+ }
+ if (e != null) {
+ sb.append("\n---Exception---");
+ sb.append("\n").append(getStackTrace(e));
+ }
+ sb.append("\n=== END ========================================================================");
+
+ logger.log(Level.WARNING, sb.toString());
+ }
+ }
+
+ private boolean isDebug(HttpServletRequest req) {
+ Object debug = req.getAttribute("Debug");
+ if (debug == null || ! "true".equals(debug.toString()))
+ return false;
+ return true;
}
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
index a2d80ef..6c28622 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestContext.java
@@ -3431,7 +3431,9 @@
private final String
clientVersionHeader,
uriAuthority,
- uriContext;
+ uriContext,
+ debugHeader,
+ debugParam;
final String fullPath;
final UrlPathPattern pathPattern;
@@ -3583,6 +3585,8 @@
renderResponseStackTraces = getBooleanProperty(REST_renderResponseStackTraces, false);
useStackTraceHashes = getBooleanProperty(REST_useStackTraceHashes, true);
debug = getBooleanProperty(REST_debug, super.isDebug());
+ debugHeader = getStringProperty(REST_debugHeader, null);
+ debugParam = getStringProperty(REST_debugParam, null);
clientVersionHeader = getStringProperty(REST_clientVersionHeader, "X-Client-Version");
responseHandlers = getInstanceArrayProperty(REST_responseHandlers, resource, ResponseHandler.class, new ResponseHandler[0], resourceResolver, this);
@@ -4647,6 +4651,34 @@
}
/**
+ * Returns the debug mode HTTP header name.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link RestContext#REST_debugHeader}
+ * </ul>
+ *
+ * @return The header name if specified or <jk>null</jk> if not.
+ */
+ public String getDebugHeader() {
+ return debugHeader;
+ }
+
+ /**
+ * Returns the debug mode URL parameter name.
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link RestContext#REST_debugParam}
+ * </ul>
+ *
+ * @return The parameter name if specified or <jk>null</jk> if not.
+ */
+ public String getDebugParam() {
+ return debugParam;
+ }
+
+ /**
* Returns the name of the client version header name used by this resource.
*
* <h5 class='section'>See Also:</h5>
@@ -4662,22 +4694,6 @@
return clientVersionHeader;
}
-// /**
-// * Returns <jk>true</jk> if the specified <c>Method</c> GET parameter value can be used to override
-// * the method name in the HTTP header.
-// *
-// * <h5 class='section'>See Also:</h5>
-// * <ul>
-// * <li class='jf'>{@link RestContext#REST_allowedMethodParams}
-// * </ul>
-// *
-// * @param m The method name, upper-cased.
-// * @return <jk>true</jk> if this resource allows the specified method to be overridden.
-// */
-// public boolean allowMethodParam(String m) {
-// return (isNotEmpty(m) && (allowedMethodParams.contains(m) || allowedMethodParams.contains("*")));
-// }
-//
/**
* Returns the HTTP-part parser associated with this resource.
*
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestLogger.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestLogger.java
index 639ea46..d62c159 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestLogger.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestLogger.java
@@ -121,4 +121,12 @@
* @param e Exception indicating what error occurred.
*/
public void onError(HttpServletRequest req, HttpServletResponse res, RestException e);
+
+ /**
+ * Called at the end of a servlet request to log the request.
+ *
+ * @param req The servlet request.
+ * @param res The servlet response.
+ */
+ public void log(HttpServletRequest req, HttpServletResponse res);
}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
index 7166631..07c6047 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestMethodContext.java
@@ -185,6 +185,84 @@
public static final String RESTMETHOD_clientVersion = PREFIX + ".clientVersion.s";
/**
+ * Configuration property: Debug mode.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"RestMethodContext.debug.b"</js>
+ * <li><b>Data type:</b> <c>Boolean</c>
+ * <li><b>Default:</b> <jk>false</jk>
+ * <li><b>Session property:</b> <jk>false</jk>
+ * <li><b>Annotations:</b>
+ * <ul>
+ * <li class='ja'>{@link RestMethod#debug()}
+ * </ul>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * Enables the following:
+ * <ul class='spaced-list'>
+ * <li>
+ * HTTP request/response bodies are cached in memory for logging purposes.
+ * <li>
+ * Request/response messages are automatically logged.
+ * </ul>
+ */
+ public static final String RESTMETHOD_debug = PREFIX + ".debug.b";
+
+ /**
+ * Configuration property: Debug mode HTTP header name.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"RestMethodContext.debugHeader.s"</js>
+ * <li><b>Data type:</b> <c>String</c>
+ * <li><b>Default:</b> empty string
+ * <li><b>Session property:</b> <jk>false</jk>
+ * <li><b>Annotations:</b>
+ * <ul>
+ * <li class='ja'>{@link RestMethod#debugHeader()}
+ * </ul>
+ * </ul>
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * Conditionally enables debug mode on requests when the specified HTTP header is present with a value of <js>"true"</js>.
+ * <br>If not specified, debug mode is enabled on all requests.
+ * <p>
+ * The purpose of this property is to allow debug mode on a per-request basis since debug mode can be somewhat
+ * expensive (since the request/response bodies have to be cached in memory).
+ */
+ public static final String RESTMETHOD_debugHeader = PREFIX + ".debugHeader.s";
+
+ /**
+ * Configuration property: Debug mode URL parameter name.
+ *
+ * <h5 class='section'>Property:</h5>
+ * <ul>
+ * <li><b>Name:</b> <js>"RestMethodContext.debugParam.s"</js>
+ * <li><b>Data type:</b> <c>String</c>
+ * <li><b>Default:</b> empty string
+ * <li><b>Session property:</b> <jk>false</jk>
+ * <li><b>Annotations:</b>
+ * <ul>
+ * <li class='ja'>{@link RestMethod#debugParam()}
+ * </ul>
+ * </ul>
+ *
+ *
+ * <h5 class='section'>Description:</h5>
+ * <p>
+ * Conditionally enables debug mode on requests when the specified URL parameter is present with a value of <js>"true"</js>.
+ * <br>If not specified, debug mode is enabled on all requests.
+ * <p>
+ * The purpose of this property is to allow debug mode on a per-request basis since debug mode can be somewhat
+ * expensive (since the request/response bodies have to be cached in memory).
+ */
+ public static final String RESTMETHOD_debugParam = PREFIX + ".debugParam.s";
+
+ /**
* Configuration property: Default form data.
*
* <h5 class='section'>Property:</h5>
@@ -488,6 +566,11 @@
final Map<Class<?>,ResponsePartMeta> bodyPartMetas = new ConcurrentHashMap<>();
final ResponseBeanMeta responseMeta;
+ final boolean debug;
+ final String
+ debugHeader,
+ debugParam;
+
@SuppressWarnings("deprecation")
RestMethodContext(RestMethodContextBuilder b) throws ServletException {
super(b.getPropertyStore());
@@ -639,6 +722,10 @@
this.supportedAcceptTypes = getListProperty(REST_produces, MediaType.class, serializers.getSupportedMediaTypes());
this.supportedContentTypes = getListProperty(REST_consumes, MediaType.class, parsers.getSupportedMediaTypes());
+
+ this.debug = getBooleanProperty(RESTMETHOD_debug, false);
+ this.debugHeader = getStringProperty(RESTMETHOD_debugHeader, null);
+ this.debugParam = getStringProperty(RESTMETHOD_debugParam, null);
}
ResponseBeanMeta getResponseBeanMeta(Object o) {
@@ -916,6 +1003,30 @@
return jsonSchemaGenerator;
}
+ /**
+ * Returns whether debug is enabled on this method.
+ *
+ * @return <jk>true</jk> if debug is enabled on this method.
+ */
+ @Override
+ protected boolean isDebug() {
+ return debug;
+ }
+
+ /**
+ * @return The debug HTTP header name.
+ */
+ protected String getDebugHeader() {
+ return debugHeader;
+ }
+
+ /**
+ * @return The debug URL parameter name.
+ */
+ protected String getDebugParam() {
+ return debugParam;
+ }
+
@Override /* Object */
public boolean equals(Object o) {
if (! (o instanceof RestMethodContext))
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
index ce459a1..263b530 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestRequest.java
@@ -56,7 +56,6 @@
import org.apache.juneau.rest.exception.*;
import org.apache.juneau.rest.helper.*;
import org.apache.juneau.rest.util.*;
-import org.apache.juneau.rest.util.RestUtils;
import org.apache.juneau.rest.widget.*;
import org.apache.juneau.serializer.*;
import org.apache.juneau.svl.*;
@@ -91,6 +90,7 @@
@SuppressWarnings({ "unchecked", "unused" })
public final class RestRequest extends HttpServletRequestWrapper {
+ private HttpServletRequest inner;
private final RestContext context;
private RestMethodContext restJavaMethod;
@@ -99,7 +99,6 @@
private Method javaMethod;
@SuppressWarnings("deprecation")
private RequestProperties properties;
- private final boolean debug;
private BeanSession beanSession;
private VarResolverSession varSession;
private final RequestQuery queryParams;
@@ -115,12 +114,14 @@
private SerializerSessionArgs serializerSessionArgs;
private ParserSessionArgs parserSessionArgs;
private RestResponse res;
+ private boolean debug;
/**
* Constructor.
*/
RestRequest(RestContext context, HttpServletRequest req) throws ServletException {
super(req);
+ this.inner = req;
this.context = context;
try {
@@ -174,8 +175,6 @@
if (! s.isEmpty())
headers.queryParams(queryParams, s);
- debug = "true".equals(getQuery().getString("debug", "false")) || "true".equals(getHeaders().getString("Debug", "false"));
-
this.pathParams = new RequestPath(this);
} catch (RestException e) {
@@ -188,7 +187,7 @@
/*
* Called from RestServlet after a match has been made but before the guard or method invocation.
*/
- final void init(RestMethodContext rjm, @SuppressWarnings("deprecation") RequestProperties properties) {
+ final void init(RestMethodContext rjm, @SuppressWarnings("deprecation") RequestProperties properties) throws IOException {
this.restJavaMethod = rjm;
this.javaMethod = rjm.method;
this.properties = properties;
@@ -209,6 +208,13 @@
.headers(headers)
.maxInput(rjm.maxInput);
+ if (isDebug(rjm)) {
+ inner = CachingHttpServletRequest.wrap(inner);
+ setAttribute("Debug", true);
+ }
+
+ debug = "true".equalsIgnoreCase((String)getAttribute("Debug"));
+
String stylesheet = getQuery().getString("stylesheet");
if (stylesheet != null)
getSession().setAttribute("stylesheet", stylesheet.replace(' ', '$')); // Prevent SVL insertion.
@@ -216,13 +222,19 @@
if (stylesheet != null)
properties.put(HTMLDOC_stylesheet, new String[]{stylesheet});
- if (debug) {
- String msg = ""
- + "\n=== HTTP Request (incoming) ===================================================="
- + toString()
- + "\n=== END ========================================================================";
- context.getLogger().log(Level.WARNING, msg);
- }
+ }
+
+ private boolean isDebug(RestMethodContext context) {
+ if (! context.isDebug())
+ return false;
+ String debugHeader = context.getDebugHeader(), debugParam = context.getDebugParam();
+ if (debugHeader == null && debugParam == null)
+ return true;
+ if (debugHeader != null && "true".equalsIgnoreCase(getHeader(debugHeader)))
+ return true;
+ if (debugParam != null && "true".equalsIgnoreCase(getParameter(debugParam)))
+ return true;
+ return false;
}
RestRequest setResponse(RestResponse res) {
@@ -838,7 +850,7 @@
}
ServletInputStream getRawInputStream() throws IOException {
- return super.getInputStream();
+ return inner.getInputStream();
}
@@ -1805,6 +1817,14 @@
return restJavaMethod == null ? context.getJsonSchemaGenerator() : restJavaMethod.getJsonSchemaGenerator();
}
+ /**
+ * Returns the wrapped servlet request.
+ *
+ * @return The wrapped servlet request.
+ */
+ protected HttpServletRequest getInner() {
+ return inner;
+ }
//-----------------------------------------------------------------------------------------------------------------
// Utility methods
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index 5b41be7..e943f8d 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -14,9 +14,6 @@
import static org.apache.juneau.internal.StringUtils.*;
-import org.apache.juneau.rest.util.FinishablePrintWriter;
-import org.apache.juneau.rest.util.FinishableServletOutputStream;
-
import java.io.*;
import java.nio.charset.*;
import java.util.*;
@@ -32,6 +29,7 @@
import org.apache.juneau.httppart.bean.*;
import org.apache.juneau.rest.annotation.*;
import org.apache.juneau.rest.exception.*;
+import org.apache.juneau.rest.util.*;
import org.apache.juneau.serializer.*;
/**
@@ -60,6 +58,7 @@
*/
public final class RestResponse extends HttpServletResponseWrapper {
+ private HttpServletResponse inner;
private final RestRequest request;
private RestMethodContext restJavaMethod;
private Object output; // The POJO being sent to the output.
@@ -79,6 +78,7 @@
*/
RestResponse(RestContext context, RestRequest req, HttpServletResponse res) throws BadRequest {
super(res);
+ this.inner = res;
this.request = req;
for (Map.Entry<String,Object> e : context.getDefaultResponseHeaders().entrySet())
@@ -100,10 +100,13 @@
/*
* Called from RestServlet after a match has been made but before the guard or method invocation.
*/
- final void init(RestMethodContext rjm, @SuppressWarnings("deprecation") RequestProperties properties) throws NotAcceptable {
+ final void init(RestMethodContext rjm, @SuppressWarnings("deprecation") RequestProperties properties) throws NotAcceptable, IOException {
this.restJavaMethod = rjm;
this.properties = properties;
+ if (request.isDebug())
+ inner = CachingHttpServletResponse.wrap(inner);
+
// Find acceptable charset
String h = request.getHeader("accept-charset");
String charset = null;
@@ -424,7 +427,7 @@
@Override /* ServletResponse */
public ServletOutputStream getOutputStream() throws IOException {
if (sos == null)
- sos = super.getOutputStream();
+ sos = inner.getOutputStream();
return sos;
}
@@ -601,6 +604,15 @@
return (T)output;
}
+ /**
+ * Returns the wrapped servlet request.
+ *
+ * @return The wrapped servlet request.
+ */
+ protected HttpServletResponse getInner() {
+ return inner;
+ }
+
@Override /* ServletResponse */
public void flushBuffer() throws IOException {
if (w != null)
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
index d1aecb1..e3dee38 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethod.java
@@ -284,6 +284,80 @@
Class<? extends RestConverter>[] converters() default {};
/**
+ * Enable debug mode.
+ *
+ * <p>
+ * Enables the following:
+ * <ul class='spaced-list'>
+ * <li>
+ * HTTP request/response bodies are cached in memory for logging purposes.
+ * <li>
+ * Request/response messages are automatically logged.
+ * </ul>
+ *
+ * <h5 class='section'>Notes:</h5>
+ * <ul class='spaced-list'>
+ * <li>
+ * Supports {@doc DefaultRestSvlVariables}
+ * (e.g. <js>"$L{my.localized.variable}"</js>).
+ * </ul>
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link RestMethodContext#RESTMETHOD_debug}
+ * </ul>
+ */
+ String debug() default "";
+
+ /**
+ * Debug mode HTTP header name.
+ *
+ * <p>
+ * Conditionally enables debug mode on requests when the specified HTTP header is present with a value of <js>"true"</js>.
+ * <br>If not specified, debug mode is enabled on all requests.
+ * <p>
+ * The purpose of this property is to allow debug mode on a per-request basis since debug mode can be somewhat
+ * expensive (since the request/response bodies have to be cached in memory).
+ *
+ * <h5 class='section'>Notes:</h5>
+ * <ul class='spaced-list'>
+ * <li>
+ * Supports {@doc DefaultRestSvlVariables}
+ * (e.g. <js>"$L{my.localized.variable}"</js>).
+ * </ul>
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link RestMethodContext#RESTMETHOD_debugHeader}
+ * </ul>
+ */
+ String debugHeader() default "";
+
+ /**
+ * Debug mode URL parameter name.
+ *
+ * <p>
+ * Conditionally enables debug mode on requests when the specified URL parameter is present with a value of <js>"true"</js>.
+ * <br>If not specified, debug mode is enabled on all requests.
+ * <p>
+ * The purpose of this property is to allow debug mode on a per-request basis since debug mode can be somewhat
+ * expensive (since the request/response bodies have to be cached in memory).
+ *
+ * <h5 class='section'>Notes:</h5>
+ * <ul class='spaced-list'>
+ * <li>
+ * Supports {@doc DefaultRestSvlVariables}
+ * (e.g. <js>"$L{my.localized.variable}"</js>).
+ * </ul>
+ *
+ * <h5 class='section'>See Also:</h5>
+ * <ul>
+ * <li class='jf'>{@link RestMethodContext#RESTMETHOD_debugParam}
+ * </ul>
+ */
+ String debugParam() default "";
+
+ /**
* Default <c>Accept</c> header.
*
* <p>
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodConfigApply.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodConfigApply.java
index bf8d38b..7cc50a1 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodConfigApply.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestMethodConfigApply.java
@@ -204,6 +204,15 @@
if (a.priority() != 0)
psb.set(RESTMETHOD_priority, a.priority());
+ if (! a.debug().isEmpty())
+ psb.set(RESTMETHOD_debug, a.debug());
+
+ if (! a.debugHeader().isEmpty())
+ psb.set(RESTMETHOD_debugHeader, a.debugHeader());
+
+ if (! a.debugParam().isEmpty())
+ psb.set(RESTMETHOD_debugParam, a.debugParam());
+
HtmlDoc hd = a.htmldoc();
new HtmlDocBuilder(psb).process(hd);
for (Class<? extends Widget> wc : hd.widgets()) {
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java
index 07cb118..8c6a9a0 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/annotation/RestResourceConfigApply.java
@@ -228,6 +228,12 @@
psb.set(BEAN_debug, bool(a.debug()));
}
+ if (! a.debugHeader().isEmpty())
+ psb.set(REST_debugHeader, a.debugHeader());
+
+ if (! a.debugParam().isEmpty())
+ psb.set(REST_debugParam, a.debugParam());
+
psb.addTo(REST_mimeTypes, strings(a.mimeTypes()));
if (! a.rolesDeclared().isEmpty())
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletRequest.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletRequest.java
new file mode 100644
index 0000000..2bf49fd
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletRequest.java
@@ -0,0 +1,67 @@
+// ***************************************************************************************************************************
+// * 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.rest.util;
+
+import java.io.IOException;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import org.apache.juneau.internal.IOUtils;
+
+/**
+ * Wraps an {@link HttpServletRequest} and preloads the body into memory for debugging purposes.
+ */
+public class CachingHttpServletRequest extends HttpServletRequestWrapper {
+
+ private final byte[] body;
+
+ /**
+ * Wraps the specified request inside a {@link CachingHttpServletRequest} if it isn't already.
+ *
+ * @param req The request to wrap.
+ * @return The wrapped request.
+ * @throws IOException Thrown by underlying body stream.
+ */
+ public static CachingHttpServletRequest wrap(HttpServletRequest req) throws IOException {
+ if (req instanceof CachingHttpServletRequest)
+ return (CachingHttpServletRequest)req;
+ return new CachingHttpServletRequest(req);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param req The request being wrapped.
+ * @throws IOException If body could not be loaded into memory.
+ */
+ protected CachingHttpServletRequest(HttpServletRequest req) throws IOException {
+ super(req);
+ this.body = IOUtils.readBytes(req.getInputStream());
+ }
+
+ @Override
+ public ServletInputStream getInputStream() {
+ return new BoundedServletInputStream(body);
+ }
+
+ /**
+ * Returns the body of the servlet request without consuming the stream.
+ *
+ * @return The body of the request.
+ */
+ public byte[] getBody() {
+ return body;
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletResponse.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletResponse.java
new file mode 100644
index 0000000..d618050
--- /dev/null
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/CachingHttpServletResponse.java
@@ -0,0 +1,94 @@
+// ***************************************************************************************************************************
+// * 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.rest.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.*;
+
+/**
+ * Wraps an {@link HttpServletResponse} and caches the output stream in a separate buffer for debugging purposes.
+ */
+public class CachingHttpServletResponse extends HttpServletResponseWrapper {
+
+ private final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ private final ServletOutputStream os;
+
+ /**
+ * Wraps the specified response inside a {@link CachingHttpServletResponse} if it isn't already.
+ *
+ * @param res The response to wrap.
+ * @return The wrapped request.
+ * @throws IOException Thrown by underlying body stream.
+ */
+ public static CachingHttpServletResponse wrap(HttpServletResponse res) throws IOException {
+ if (res instanceof CachingHttpServletResponse)
+ return (CachingHttpServletResponse)res;
+ return new CachingHttpServletResponse(res);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param res The wrapped servlet response.
+ * @throws IOException Thrown by underlying stream.
+ */
+ protected CachingHttpServletResponse(HttpServletResponse res) throws IOException {
+ super(res);
+ os = res.getOutputStream();
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ return new ServletOutputStream() {
+
+ @Override
+ public boolean isReady() {
+ return os.isReady();
+ }
+
+ @Override
+ public void setWriteListener(WriteListener writeListener) {
+ os.setWriteListener(writeListener);
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ baos.write(b);
+ os.write(b);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ os.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ os.close();
+ }
+ };
+ }
+
+ /**
+ * Returns the body of the servlet response without consuming the stream.
+ *
+ * @return The body of the response.
+ */
+ public byte[] getBody() {
+ return baos.toByteArray();
+ }
+}
diff --git a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
index b5326a4..78cf327 100644
--- a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
+++ b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/util/RestUtils.java
@@ -15,7 +15,7 @@
import static org.apache.juneau.internal.ArrayUtils.*;
import static org.apache.juneau.internal.StringUtils.*;
-import java.io.IOException;
+import java.io.*;
import java.util.*;
import java.util.regex.*;
diff --git a/juneau-release-launch.launch b/launches/juneau-apply-prefs.launch
similarity index 78%
copy from juneau-release-launch.launch
copy to launches/juneau-apply-prefs.launch
index 36da94a..e008f02 100644
--- a/juneau-release-launch.launch
+++ b/launches/juneau-apply-prefs.launch
@@ -3,6 +3,6 @@
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.ui.externaltools.launchGroup"/>
</listAttribute>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/juneau-root/juneau-release.sh}"/>
-<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/juneau-root}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:/juneau/launches/juneau-apply-prefs.sh}"/>
+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/juneau}"/>
</launchConfiguration>
diff --git a/launches/juneau-apply-prefs.sh b/launches/juneau-apply-prefs.sh
new file mode 100755
index 0000000..419e367
--- /dev/null
+++ b/launches/juneau-apply-prefs.sh
@@ -0,0 +1,53 @@
+#!/bin/bash
+# ***************************************************************************************************************************
+# * 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. *
+# ***************************************************************************************************************************
+
+projects=(
+"juneau-core/juneau-config"
+"juneau-core/juneau-core-utest"
+"juneau-core/juneau-dto"
+"juneau-core/juneau-marshall"
+"juneau-core/juneau-marshall-rdf"
+"juneau-core/juneau-svl"
+"juneau-doc"
+"juneau-examples/juneau-examples-core"
+"juneau-examples/juneau-examples-rest"
+"juneau-examples/juneau-examples-rest-jetty"
+"juneau-examples/juneau-examples-rest-jetty-ftest"
+"juneau-examples/juneau-examples-rest-springboot"
+"juneau-microservice/juneau-microservice-core"
+"juneau-microservice/juneau-microservice-ftest"
+"juneau-microservice/juneau-microservice-jetty"
+"juneau-microservice/juneau-my-jetty-microservice"
+"juneau-microservice/juneau-my-springboot-microservice"
+"juneau-rest/juneau-rest-client"
+"juneau-rest/juneau-rest-client-utest"
+"juneau-rest/juneau-rest-mock"
+"juneau-rest/juneau-rest-mock-utest"
+"juneau-rest/juneau-rest-server"
+"juneau-rest/juneau-rest-server-jaxrs"
+"juneau-rest/juneau-rest-server-rdf"
+"juneau-rest/juneau-rest-server-springboot"
+"juneau-rest/juneau-rest-server-utest"
+"juneau-sc/juneau-sc-client"
+"juneau-sc/juneau-sc-server"
+)
+
+for i in "${projects[@]}"
+do
+ echo Preferences applied to $i
+ cp eclipse-preferences/org.eclipse.jdt.core.prefs $i/.settings
+ cp eclipse-preferences/org.eclipse.jdt.ui.prefs $i/.settings
+done
+
+