From ca82d012cdb0a5449350e7335e3f5ef61b3b6f2c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 15:50:59 +0000 Subject: [PATCH 1/4] Initial plan From 3225673199f910a1411357996fe9a8d72dd1e905 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 15:57:06 +0000 Subject: [PATCH 2/4] Create org.eclipse.equinox.p2.transport.native bundle skeleton Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .../.classpath | 7 + .../.project | 39 ++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 494 +++++++++++++ .../.settings/org.eclipse.jdt.ui.prefs | 155 ++++ .../.settings/org.eclipse.pde.core.prefs | 4 + .../org.eclipse.pde.ds.annotations.prefs | 7 + .../META-INF/MANIFEST.MF | 20 + .../OSGI-INF/.gitignore | 1 + .../about.html | 36 + .../build.properties | 23 + .../forceQualifierUpdate.txt | 4 + .../plugin.properties | 15 + .../internal/p2/transport/ecf/Activator.java | 191 +++++ .../transport/ecf/ECFTransportComponent.java | 26 + .../p2/transport/ecf/FileInfoReader.java | 154 ++++ .../internal/p2/transport/ecf/FileReader.java | 663 ++++++++++++++++++ .../internal/p2/transport/ecf/Messages.java | 78 +++ .../p2/transport/ecf/P2SSLContextFactory.java | 52 ++ .../p2/transport/ecf/RepositoryStatus.java | 163 +++++ .../transport/ecf/RepositoryStatusHelper.java | 342 +++++++++ .../p2/transport/ecf/RepositoryTransport.java | 393 +++++++++++ .../p2/transport/ecf/messages.properties | 61 ++ 23 files changed, 2930 insertions(+) create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/.classpath create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/.project create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.core.resources.prefs create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.core.prefs create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.ui.prefs create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.core.prefs create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.ds.annotations.prefs create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/OSGI-INF/.gitignore create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/about.html create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/build.properties create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/forceQualifierUpdate.txt create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/plugin.properties create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Activator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/ECFTransportComponent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileInfoReader.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Messages.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatus.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatusHelper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/messages.properties diff --git a/bundles/org.eclipse.equinox.p2.transport.native/.classpath b/bundles/org.eclipse.equinox.p2.transport.native/.classpath new file mode 100644 index 0000000000..81fe078c20 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.eclipse.equinox.p2.transport.native/.project b/bundles/org.eclipse.equinox.p2.transport.native/.project new file mode 100644 index 0000000000..cc09bd6f83 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/.project @@ -0,0 +1,39 @@ + + + org.eclipse.equinox.p2.transport.ecf + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.core.resources.prefs b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..99f26c0203 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000000..6eebc10810 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,494 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +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.nonnullisdefault=disabled +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.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=1000 +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +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=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +org.eclipse.jdt.core.compiler.problem.finalParameterBound=ignore +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeFieldsInNullAnalysis=disabled +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private +org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=enabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +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=warning +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.nullSpecInsufficientInfo=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=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error +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=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +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=warning +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=ignore +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning +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=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=error +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=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error +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=enabled +org.eclipse.jdt.core.compiler.source=17 +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=16 +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=true +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=true +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=false +org.eclipse.jdt.core.formatter.comment.indent_root_tags=false +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=80 +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=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +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=false +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=false +org.eclipse.jdt.core.formatter.indentation.size=4 +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_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=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_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=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=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=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_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=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_switch_case_expressions=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=120 +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.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter diff --git a/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000000..c49cfff588 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,155 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=org.eclipse.jdt.ui.default.eclipse_profile +formatter_settings_version=16 +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=; +org.eclipse.jdt.ui.ondemandthreshold=3 +org.eclipse.jdt.ui.staticondemandthreshold=3 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_all=false +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=false +sp_cleanup.add_serial_version_id=false +sp_cleanup.also_simplify_lambda=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.array_with_curly=false +sp_cleanup.arrays_fill=false +sp_cleanup.bitwise_conditional_expression=false +sp_cleanup.boolean_literal=false +sp_cleanup.boolean_value_rather_than_comparison=false +sp_cleanup.break_loop=false +sp_cleanup.collection_cloning=false +sp_cleanup.comparing_on_criteria=false +sp_cleanup.comparison_statement=false +sp_cleanup.controlflow_merge=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.convert_to_enhanced_for_loop_if_loop_var_used=false +sp_cleanup.convert_to_switch_expressions=false +sp_cleanup.correct_indentation=false +sp_cleanup.do_while_rather_than_while=false +sp_cleanup.double_negation=false +sp_cleanup.else_if=false +sp_cleanup.embedded_if=false +sp_cleanup.evaluate_nullable=false +sp_cleanup.extract_increment=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=true +sp_cleanup.hash=false +sp_cleanup.if_condition=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.instanceof=false +sp_cleanup.instanceof_keyword=false +sp_cleanup.invert_equals=false +sp_cleanup.join=false +sp_cleanup.lazy_logical_operator=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=true +sp_cleanup.map_cloning=false +sp_cleanup.merge_conditional_blocks=false +sp_cleanup.multi_catch=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.no_string_creation=false +sp_cleanup.no_super=false +sp_cleanup.number_suffix=false +sp_cleanup.objects_equals=false +sp_cleanup.on_save_use_additional_actions=false +sp_cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false +sp_cleanup.operand_factorization=false +sp_cleanup.organize_imports=true +sp_cleanup.overridden_assignment=false +sp_cleanup.overridden_assignment_move_decl=false +sp_cleanup.plain_replacement=false +sp_cleanup.precompile_regex=false +sp_cleanup.primitive_comparison=false +sp_cleanup.primitive_parsing=false +sp_cleanup.primitive_rather_than_wrapper=false +sp_cleanup.primitive_serialization=false +sp_cleanup.pull_out_if_from_if_else=false +sp_cleanup.pull_up_assignment=false +sp_cleanup.push_down_negation=false +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.reduce_indentation=false +sp_cleanup.redundant_comparator=false +sp_cleanup.redundant_falling_through_block_end=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_modifiers=false +sp_cleanup.remove_redundant_semicolons=false +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=false +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_array_creation=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=false +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_method_parameters=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.replace_deprecated_calls=false +sp_cleanup.return_expression=false +sp_cleanup.simplify_boolean_if_else=false +sp_cleanup.simplify_lambda_expression_and_method_ref=false +sp_cleanup.single_used_field=false +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.standard_comparison=false +sp_cleanup.static_inner_class=false +sp_cleanup.strictly_equal_or_different=false +sp_cleanup.stringbuffer_to_stringbuilder=false +sp_cleanup.stringbuilder=false +sp_cleanup.stringbuilder_for_local_vars=false +sp_cleanup.stringconcat_stringbuffer_stringbuilder=false +sp_cleanup.stringconcat_to_textblock=false +sp_cleanup.substring=false +sp_cleanup.switch=false +sp_cleanup.system_property=false +sp_cleanup.system_property_boolean=false +sp_cleanup.system_property_file_encoding=false +sp_cleanup.system_property_file_separator=false +sp_cleanup.system_property_javaspecversion=false +sp_cleanup.system_property_javaversion=false +sp_cleanup.system_property_line_separator=false +sp_cleanup.system_property_path_separator=false +sp_cleanup.ternary_operator=false +sp_cleanup.try_with_resource=false +sp_cleanup.unlooped_while=false +sp_cleanup.unreachable_block=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_autoboxing=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_directly_map_method=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_string_is_blank=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_unboxing=false +sp_cleanup.use_var=false +sp_cleanup.useless_continue=false +sp_cleanup.useless_return=false +sp_cleanup.valueof_rather_than_instantiation=false diff --git a/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 0000000000..7913d20dbc --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ + +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.ds.annotations.prefs b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.ds.annotations.prefs new file mode 100644 index 0000000000..5faf08b7d5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/.settings/org.eclipse.pde.ds.annotations.prefs @@ -0,0 +1,7 @@ +dsVersion=V1_4 +eclipse.preferences.version=1 +enabled=true +generateBundleActivationPolicyLazy=true +path=OSGI-INF +validationErrorLevel=error +validationErrorLevel.missingImplicitUnbindMethod=error diff --git a/bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..dc35b20534 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF @@ -0,0 +1,20 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.equinox.p2.transport.native +Bundle-Version: 1.4.600.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-17 +Require-Bundle: org.eclipse.equinox.p2.core;bundle-version="2.0.100", + org.eclipse.equinox.p2.repository;bundle-version="2.1.0", + org.eclipse.equinox.common;bundle-version="3.6.0", + org.eclipse.core.jobs;bundle-version="3.5.100" +Service-Component: OSGI-INF/nativeTransport.xml +Bundle-Activator: org.eclipse.equinox.internal.p2.transport.ecf.Activator +Bundle-ActivationPolicy: lazy +Export-Package: org.eclipse.equinox.internal.p2.transport.ecf;x-friends:="org.eclipse.equinox.p2.discovery.compatibility,org.eclipse.equinox.p2.installer" +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Import-Package: org.eclipse.osgi.util;version="1.1.0", + org.osgi.framework;version="1.6.0", + org.osgi.util.tracker;version="1.5.0" +Automatic-Module-Name: org.eclipse.equinox.p2.transport.native diff --git a/bundles/org.eclipse.equinox.p2.transport.native/OSGI-INF/.gitignore b/bundles/org.eclipse.equinox.p2.transport.native/OSGI-INF/.gitignore new file mode 100644 index 0000000000..b878e882ac --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/OSGI-INF/.gitignore @@ -0,0 +1 @@ +/*.xml diff --git a/bundles/org.eclipse.equinox.p2.transport.native/about.html b/bundles/org.eclipse.equinox.p2.transport.native/about.html new file mode 100644 index 0000000000..164f781a8f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/about.html @@ -0,0 +1,36 @@ + + + + +About + + +

About This Content

+ +

November 30, 2017

+

License

+ +

+ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +

+ + + \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/build.properties b/bundles/org.eclipse.equinox.p2.transport.native/build.properties new file mode 100644 index 0000000000..02493d4636 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/build.properties @@ -0,0 +1,23 @@ +############################################################################### +# Copyright (c) 2011 Sonatype Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Sonatype Corporation - initial API and implementation +# IBM Corporation - ongoing development +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + OSGI-INF/,\ + about.html,\ + plugin.properties +src.includes = about.html + diff --git a/bundles/org.eclipse.equinox.p2.transport.native/forceQualifierUpdate.txt b/bundles/org.eclipse.equinox.p2.transport.native/forceQualifierUpdate.txt new file mode 100644 index 0000000000..d5e8883295 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/forceQualifierUpdate.txt @@ -0,0 +1,4 @@ +# To force a version qualifier update add the bug here +Bug 403352 - Update all parent versions to match our build stream +Bug 527899 [9] Implement JEP 280: Indify String Concatenation +https://github.com/eclipse-platform/eclipse.platform.releng.aggregator/issues/1659 \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/plugin.properties b/bundles/org.eclipse.equinox.p2.transport.native/plugin.properties new file mode 100644 index 0000000000..9dde14708e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/plugin.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2010 - 2011 Sonatype, Inc. and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Sonatype, Inc. - initial API and implementation +############################################################################### +pluginName = Equinox Provisioning ECF based Transport +providerName = Eclipse.org - Equinox diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Activator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Activator.java new file mode 100644 index 0000000000..859bd500c0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Activator.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2009, 2017 Cloudsmith Inc and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Cloudsmith Inc - initial API and implementation + * IBM Corporation - ongoing development + * Genuitec - Bug 291926 + * Red Hat Inc. - Bug 460967 + ******************************************************************************/ +package org.eclipse.equinox.internal.p2.transport.ecf; + +import java.util.*; +import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransferFactory; +import org.eclipse.ecf.provider.filetransfer.IFileTransferProtocolToFactoryMapper; +import org.osgi.framework.*; +import org.osgi.util.tracker.ServiceTracker; + +/** + * The activator class controls the plug-in life cycle. This activator has + * helper methods to get file transfer service tracker, and for making sure + * required ECF bundles are started. + */ +@SuppressWarnings("restriction") +public class Activator implements BundleActivator { + + public static final String ID = "org.eclipse.equinox.p2.transport.ecf"; //$NON-NLS-1$ + private static final String HTTP = "http"; //$NON-NLS-1$ + private static final String HTTPS = "https"; //$NON-NLS-1$ + + private static BundleContext context; + // tracker for ECF service + private ServiceTracker retrievalFactoryTracker; + + // tracker for protocolToFactoryMapperTracker + private ServiceTracker protocolToFactoryMapperTracker = null; + + // The shared instance + private static Activator plugin; + + @Override + public void start(BundleContext aContext) throws Exception { + Activator.context = aContext; + Activator.plugin = this; + } + + @Override + public void stop(BundleContext aContext) throws Exception { + Activator.context = null; + Activator.plugin = null; + if (retrievalFactoryTracker != null) { + retrievalFactoryTracker.close(); + retrievalFactoryTracker = null; + } + if (protocolToFactoryMapperTracker != null) { + protocolToFactoryMapperTracker.close(); + protocolToFactoryMapperTracker = null; + } + + } + + /** + * Get singleton instance. + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Returns a {@link IRetrieveFileTransferFactory} using a {@link ServiceTracker} + * after having attempted to start the bundle + * "org.eclipse.ecf.provider.filetransfer". If something is wrong with the + * configuration this method returns null. + * + * @return a factory, or null, if configuration is incorrect + */ + public IRetrieveFileTransferFactory getRetrieveFileTransferFactory() { + return getFileTransferServiceTracker().getService(); + } + + public synchronized void useJREHttpClient() { + IFileTransferProtocolToFactoryMapper mapper = getProtocolToFactoryMapper(); + if (mapper != null) { + // remove http + // Remove browse provider + String providerId = mapper.getBrowseFileTransferFactoryId(HTTP); + if (providerId != null) { + mapper.removeBrowseFileTransferFactory(providerId); + } + // Remove retrieve provider + providerId = mapper.getRetrieveFileTransferFactoryId(HTTP); + if (providerId != null) { + mapper.removeRetrieveFileTransferFactory(providerId); + } + // Remove send provider + providerId = mapper.getSendFileTransferFactoryId(HTTP); + if (providerId != null) { + mapper.removeSendFileTransferFactory(providerId); + } + // remove https + // Remove browse provider + providerId = mapper.getBrowseFileTransferFactoryId(HTTPS); + if (providerId != null) { + mapper.removeBrowseFileTransferFactory(providerId); + } + // Remove retrieve provider + providerId = mapper.getRetrieveFileTransferFactoryId(HTTPS); + if (providerId != null) { + mapper.removeRetrieveFileTransferFactory(providerId); + } + // Remove send provider + providerId = mapper.getSendFileTransferFactoryId(HTTPS); + if (providerId != null) { + mapper.removeSendFileTransferFactory(providerId); + } + } + } + + /** + * Gets the singleton ServiceTracker for the IRetrieveFileTransferFactory and + * starts the bundles "org.eclipse.ecf" and + * "org.eclipse.ecf.provider.filetransfer" on first call. + * + * @return ServiceTracker + */ + private synchronized ServiceTracker getFileTransferServiceTracker() { + if (retrievalFactoryTracker == null) { + BundleContext bundleContext = Activator.context; + retrievalFactoryTracker = new ServiceTracker<>(bundleContext, IRetrieveFileTransferFactory.class, null); + retrievalFactoryTracker.open(); + HashSet toStart = new HashSet<>(); + toStart.add("org.eclipse.ecf"); //$NON-NLS-1$ + toStart.add("org.eclipse.ecf.provider.filetransfer"); //$NON-NLS-1$ + startBundle(toStart, bundleContext); + } + return retrievalFactoryTracker; + } + + private IFileTransferProtocolToFactoryMapper getProtocolToFactoryMapper() { + if (protocolToFactoryMapperTracker == null) { + protocolToFactoryMapperTracker = new ServiceTracker<>(context, IFileTransferProtocolToFactoryMapper.class, + null); + protocolToFactoryMapperTracker.open(); + } + return protocolToFactoryMapperTracker.getService(); + } + + private static void startBundle(Set bundles, BundleContext bundleContext) { + for (Bundle bundle : bundleContext.getBundles()) { + String symbolicName = bundle.getSymbolicName(); + if (bundles.contains(symbolicName)) { + try { + if ((bundle.getState() & Bundle.INSTALLED) == 0) { + bundle.start(Bundle.START_ACTIVATION_POLICY); + bundle.start(Bundle.START_TRANSIENT); + bundles.remove(symbolicName); + if (bundles.isEmpty()) { + // nothing more to do + return; + } + } + } catch (BundleException e) { + // failed, try next bundle + } + } + } + } + + public static String getProperty(String key) { + if (context != null) { + return context.getProperty(key); + } + return System.getProperty(key); + } + + public static Optional getVersion() { + return Optional.ofNullable(context) // + .map(BundleContext::getBundle) // + .or(() -> Optional.ofNullable(FrameworkUtil.getBundle(FileReader.class)))// + .map(Bundle::getVersion); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/ECFTransportComponent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/ECFTransportComponent.java new file mode 100644 index 0000000000..e195f21096 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/ECFTransportComponent.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2011, 2017 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.transport.ecf; + +import org.eclipse.equinox.p2.core.IProvisioningAgent; +import org.eclipse.equinox.p2.core.spi.IAgentServiceFactory; + +public class ECFTransportComponent implements IAgentServiceFactory { + + @Override + public Object createService(IProvisioningAgent agent) { + return new RepositoryTransport(agent); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileInfoReader.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileInfoReader.java new file mode 100644 index 0000000000..f2bf4a7395 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileInfoReader.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2009, 2017 IBM Corporation, and others. + * The code, documentation and other materials contained herein have been + * licensed under the Eclipse Public License - v 1.0 by the copyright holder + * listed above, as the Initial Contributor under such license. The text of + * such license is available at www.eclipse.org. + * Contributors: + * IBM Corporation - initial implementation + * Cloudsmith Inc - modified API, and implementation + * Red Hat Inc. - Bug 460967 + ******************************************************************************/ +package org.eclipse.equinox.internal.p2.transport.ecf; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.core.*; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.filetransfer.*; +import org.eclipse.ecf.filetransfer.events.IRemoteFileSystemBrowseEvent; +import org.eclipse.ecf.filetransfer.identity.*; +import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; +import org.eclipse.equinox.internal.p2.repository.*; +import org.eclipse.equinox.internal.p2.repository.Activator; +import org.eclipse.equinox.internal.p2.repository.Messages; +import org.eclipse.osgi.util.NLS; + +class FileInfoReader { + private final int connectionRetryCount; + private final long connectionRetryDelay; + private final IConnectContext connectContext; + + /** + * Create a new FileInfoReader that will retry failed connection attempts and + * sleep some amount of time between each attempt. + */ + FileInfoReader(IConnectContext aConnectContext) { + connectionRetryCount = RepositoryPreferences.getConnectionRetryCount(); + connectionRetryDelay = RepositoryPreferences.getConnectionMsRetryDelay(); + connectContext = aConnectContext; + } + + long getLastModified(URI uri, IProgressMonitor monitor) + throws AuthenticationFailedException, FileNotFoundException, CoreException, JREHttpClientRequiredException { + SubMonitor convert = SubMonitor.convert(monitor, uri.toString(), connectionRetryCount); + IContainer container; + try { + container = ContainerFactory.getDefault().createContainer(); + } catch (ContainerCreateException e) { + throw RepositoryStatusHelper.fromExceptionMessage(e, Messages.ecf_configuration_error); + } + IRemoteFileSystemBrowserContainerAdapter adapter = container + .getAdapter(IRemoteFileSystemBrowserContainerAdapter.class); + if (adapter == null) { + throw RepositoryStatusHelper.fromMessage(Messages.ecf_configuration_error); + } + adapter.setConnectContextForAuthentication(connectContext); + CoreException summary = new CoreException(Status.error("All download attempts failed")); //$NON-NLS-1$ + for (int retryCount = 0; retryCount < connectionRetryCount; retryCount++) { + if (convert.isCanceled()) { + throw new OperationCanceledException(); + } + AtomicReference remote = new AtomicReference<>(); + AtomicReference exception = new AtomicReference<>(); + try { + IFileID fileID = FileIDFactory.getDefault().createFileID(adapter.getBrowseNamespace(), uri.toString()); + CountDownLatch latch = new CountDownLatch(1); + IRemoteFileSystemRequest browseRequest = adapter.sendBrowseRequest(fileID, event -> { + Exception e = event.getException(); + if (e != null) { + exception.set(e); + } else if (event instanceof IRemoteFileSystemBrowseEvent fsbe) { + IRemoteFile[] remoteFiles = fsbe.getRemoteFiles(); + if (remoteFiles != null && remoteFiles.length > 0) { + remote.set(remoteFiles[0]); + } + convert.worked(1); + } + latch.countDown(); + }); + while (!latch.await(1, TimeUnit.SECONDS)) { + if (convert.isCanceled()) { + browseRequest.cancel(); + throw new OperationCanceledException(); + } + } + } catch (RemoteFileSystemException | FileCreateException e) { + exception.set(e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LogHelper.log(new Status(IStatus.WARNING, Activator.ID, + "Unexpected interrupt while waiting on ECF browse request", e)); //$NON-NLS-1$ + throw new OperationCanceledException(); + } + Exception e = exception.get(); + if (e == null) { + IRemoteFile remoteFile = remote.get(); + if (remoteFile == null) { + throw new FileNotFoundException(uri.toString()); + } + return remoteFile.getInfo().getLastModified(); + } + checkException(uri, retryCount, e); + summary.addSuppressed(e); + } + throw summary; + } + + /** + * Utility method to check exception condition and determine if retry should be + * done. If there was an exception it is translated into one of the specified + * exceptions and thrown. + * + * @param uri the URI being read - used for logging purposes + * @param attemptCounter - the current attempt number (start with 0) + * @return true if the exception is an IOException and attemptCounter < + * connectionRetryCount, false otherwise + * @throws JREHttpClientRequiredException + */ + private boolean checkException(URI uri, int attemptCounter, Exception exception) + throws CoreException, FileNotFoundException, AuthenticationFailedException, JREHttpClientRequiredException { + // check if HTTP client needs to be changed + RepositoryStatusHelper.checkJREHttpClientRequired(exception); + + // if this is a authentication failure - it is not meaningful to continue + RepositoryStatusHelper.checkPermissionDenied(exception); + + // if this is a file not found - it is not meaningful to continue + RepositoryStatusHelper.checkFileNotFound(exception, uri); + + Throwable t = RepositoryStatusHelper.unwind(exception); + if (t instanceof CoreException) { + throw RepositoryStatusHelper.unwindCoreException((CoreException) t); + } + if (t instanceof IOException && attemptCounter < connectionRetryCount - 1) { + LogHelper + .log(new Status(IStatus.WARNING, Activator.ID, + NLS.bind(Messages.connection_to_0_failed_on_1_retry_attempt_2, + uri.toString(), t.getMessage(), String.valueOf(attemptCounter)), + t)); + try { + Thread.sleep(connectionRetryDelay); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new OperationCanceledException(); + } + } + throw RepositoryStatusHelper.wrap(exception); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java new file mode 100644 index 0000000000..a47a1be03a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/FileReader.java @@ -0,0 +1,663 @@ +/******************************************************************************* + * Copyright (c) 2006, 2017 Cloudsmith Inc. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Cloudsmith Inc - initial API and implementation + * IBM Corporation - ongoing development + * Sonatype Inc - ongoing development + * Ericsson AB. - Bug 407940 - [transport] Initial connection happens in current thread + * Red Hat Inc. - Bug 460967 + * Rapicorp Inc - Bug 467286 - Set the ECF user agent property + ******************************************************************************/ +package org.eclipse.equinox.internal.p2.transport.ecf; + +import java.io.*; +import java.net.SocketTimeoutException; +import java.net.URI; +import java.util.*; +import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.filetransfer.*; +import org.eclipse.ecf.filetransfer.events.*; +import org.eclipse.ecf.filetransfer.identity.*; +import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransferFactory; +import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; +import org.eclipse.equinox.internal.p2.repository.*; +import org.eclipse.equinox.internal.p2.repository.Messages; +import org.eclipse.equinox.p2.core.IProvisioningAgent; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.Version; + +/** + * FileReader is an ECF FileTransferJob implementation. + */ +public final class FileReader extends FileTransferJob implements IFileTransferListener { + /** + * Class used to suppress warnings about a job being blocked by another job. + * Since we are running a job that will always be blocked by another job that is + * actually performing the transfer, these messages are unnecessary and ugly. + */ + static class SuppressBlockedMonitor extends ProgressMonitorWrapper { + public SuppressBlockedMonitor(IProgressMonitor monitor, int ticks) { + super(monitor.slice(ticks)); + } + + @Override + public void setBlocked(IStatus reason) { + // do nothing + } + + @Override + public void clearBlocked() { + // do nothing + } + } + + static Map> options; + + static private String getProperty(String key, String defaultValue) { + String value = Activator.getProperty(key); + if (value != null) { + return value; + } + return defaultValue; + } + + static { + Map extraRequestHeaders = new HashMap<>(1); + String userAgent = null; + String javaSpec = getProperty("java.runtime.version", "unknownJava"); //$NON-NLS-1$//$NON-NLS-2$ + String javaVendor = getProperty("java.vendor", "unknownJavaVendor");//$NON-NLS-1$//$NON-NLS-2$ + String osName = getProperty("org.osgi.framework.os.name", "unknownOS"); //$NON-NLS-1$ //$NON-NLS-2$ + String osgiArch = getProperty("org.osgi.framework.processor", "unknownArch");//$NON-NLS-1$//$NON-NLS-2$ + String language = getProperty("osgi.nl", "unknownLanguage");//$NON-NLS-1$//$NON-NLS-2$ + String osVersion = getProperty("org.osgi.framework.os.version", "unknownOSVersion"); //$NON-NLS-1$ //$NON-NLS-2$ + String p2Version = Activator.getVersion().map(Version::toString).orElse("unknownVersion"); //$NON-NLS-1$ + userAgent = "p2/" + p2Version + " (Java " + javaSpec + ' ' + javaVendor + "; " + osName + ' ' + osVersion + ' ' //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + osgiArch + "; " + language + ") "; //$NON-NLS-1$ //$NON-NLS-2$ + String userAgentProvided = getProperty("p2.userAgent", null); //$NON-NLS-1$ + if (userAgentProvided == null) { + String productId = getProperty("eclipse.product", "unknownProduct"); //$NON-NLS-1$ //$NON-NLS-2$ + String appId = getProperty("eclipse.application", "unknownApp"); //$NON-NLS-1$ //$NON-NLS-2$ + String buildId = getProperty("eclipse.buildId", "unknownBuildId"); //$NON-NLS-1$ //$NON-NLS-2$ + userAgent += productId + '/' + buildId + " (" + appId + ')'; //$NON-NLS-1$ + } else { + userAgent += userAgentProvided; + } + extraRequestHeaders.put("User-Agent", userAgent); //$NON-NLS-1$ + options = new HashMap<>(1); + options.put(org.eclipse.ecf.filetransfer.IRetrieveFileTransferOptions.REQUEST_HEADERS, extraRequestHeaders); + } + + private static IFileReaderProbe testProbe; + private boolean closeStreamWhenFinished = false; + private Exception exception; + private FileInfo fileInfo; + private long lastProgressCount; + private long lastStatsCount; + protected IProgressMonitor theMonitor; + private OutputStream theOutputStream; + private ProgressStatistics statistics; + private final int connectionRetryCount; + private final long connectionRetryDelay; + /** See bug 574173: allow to retry download if specified */ + private final boolean retryOnSocketTimeout; + private final IConnectContext connectContext; + private URI requestUri; + protected IFileTransferConnectStartEvent connectEvent; + private Job cancelJob; + private boolean monitorStarted; + private final IProvisioningAgent agent; + private boolean isPause = false; + private boolean hasPaused = false; + private IFileTransferPausable pasuable = null; + + /** + * Create a new FileReader that will retry failed connection attempts and sleep + * some amount of time between each attempt. + */ + public FileReader(IProvisioningAgent aAgent, IConnectContext aConnectContext) { + super(Messages.FileTransport_reader); // job label + + // Hide this job. + setSystem(true); + setUser(false); + connectionRetryCount = RepositoryPreferences.getConnectionRetryCount(); + connectionRetryDelay = RepositoryPreferences.getConnectionMsRetryDelay(); + retryOnSocketTimeout = RepositoryPreferences.getRetryOnSocketTimeout(); + connectContext = aConnectContext; + this.agent = aAgent; + } + + public FileInfo getLastFileInfo() { + return fileInfo; + } + + /** + * A job to handle cancelation when trying to establish a socket connection. At + * this point we don't have a transfer job running yet, so we need a separate + * job to monitor for cancelation. + */ + protected class CancelHandler extends Job { + + protected CancelHandler() { + super(Messages.FileTransport_cancelCheck); + setSystem(true); + } + + @Override + public IStatus run(IProgressMonitor jobMonitor) { + while (FileReader.this.cancelJob == this && !jobMonitor.isCanceled()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return Status.CANCEL_STATUS; + } + if (theMonitor != null && theMonitor.isCanceled()) { + if (connectEvent != null) { + connectEvent.cancel(); + } + } + } + return Status.OK_STATUS; + } + + @Override + protected void canceling() { + // wake up from sleep in run method + Thread t = getThread(); + if (t != null) { + t.interrupt(); + } + } + + } + + @Override + public synchronized void handleTransferEvent(IFileTransferEvent event) { + if (event instanceof IFileTransferConnectStartEvent) { + // keep the connect event to be able to cancel the transfer + connectEvent = (IFileTransferConnectStartEvent) event; + connectEvent.connectUsingJob(((IFileTransferConnectStartEvent) event).prepareConnectJob(null)); + cancelJob = new CancelHandler(); + // schedule with a delay to avoid the overhead of an extra job on a fast + // connection + cancelJob.schedule(500); + } else if (event instanceof IIncomingFileTransferReceiveStartEvent) { + // we no longer need the cancel handler because we are about to fork the + // transfer job + if (cancelJob != null) { + cancelJob.cancel(); + } + IIncomingFileTransfer source = ((IIncomingFileTransferEvent) event).getSource(); + try { + FileInfo fi = new FileInfo(); + Date lastModified = source.getRemoteLastModified(); + if (lastModified != null) { + fi.setLastModified(lastModified.getTime()); + } + fi.setName(source.getRemoteFileName()); + fi.setSize(source.getFileLength()); + fileInfo = fi; + + ((IIncomingFileTransferReceiveStartEvent) event).receive(theOutputStream, this); + } catch (IOException e) { + exception = e; + return; + } + long fileLength = source.getFileLength(); + ProgressStatistics stats = new ProgressStatistics(agent, requestUri, source.getRemoteFileName(), + fileLength); + setStatistics(stats); + + if (theMonitor != null) { + theMonitor.beginTask(null, 1000); + monitorStarted = true; + theMonitor.subTask(stats.report()); + lastStatsCount = 0; + lastProgressCount = 0; + } + onStart(source); + } else if (event instanceof IIncomingFileTransferReceiveDataEvent) { + IIncomingFileTransfer source = ((IIncomingFileTransferEvent) event).getSource(); + if (theMonitor != null) { + if (theMonitor.isCanceled()) { + source.cancel(); + return; + } + + long br = source.getBytesReceived(); + long count = br - lastStatsCount; + lastStatsCount = br; + ProgressStatistics stats = getStatistics(); + if (stats != null) { + stats.increase(count); + fileInfo.setAverageSpeed(stats.getAverageSpeed()); + if (stats.shouldReport()) { + count = br - lastProgressCount; + lastProgressCount = br; + theMonitor.subTask(stats.report()); + theMonitor.worked((int) (1000 * count / stats.getTotal())); + } + } + } + pauseIfPossible(source); + onData(source); + } else if (event instanceof IIncomingFileTransferReceiveDoneEvent) { + // stop paused Reader if resuming failed + this.hasPaused = false; + if (closeStreamWhenFinished) { + hardClose(theOutputStream); + } + + if (exception == null) { + exception = ((IIncomingFileTransferReceiveDoneEvent) event).getException(); + } + onDone(((IIncomingFileTransferReceiveDoneEvent) event).getSource()); + } else if (event instanceof IIncomingFileTransferReceivePausedEvent) { + this.hasPaused = true; + } else if (event instanceof IIncomingFileTransferReceiveResumedEvent) { + // we no longer need the cancel handler because we are about to resume the + // transfer job + if (cancelJob != null) { + cancelJob.cancel(); + } + try { + ((IIncomingFileTransferReceiveResumedEvent) event).receive(theOutputStream, this); + } catch (IOException e) { + exception = e; + } finally { + this.hasPaused = false; + } + } + } + + private synchronized void pauseIfPossible(IIncomingFileTransfer source) { + if (isPaused() && !hasPaused) { + pasuable = source.getAdapter(IFileTransferPausable.class); + if (pasuable != null) { + pasuable.pause(); + } + } + } + + public InputStream read(URI url, final IProgressMonitor monitor) + throws CoreException, FileNotFoundException, AuthenticationFailedException, JREHttpClientRequiredException { + final PipedInputStream input = new PipedInputStream(); + PipedOutputStream output; + try { + output = new PipedOutputStream(input); + } catch (IOException e) { + throw RepositoryStatusHelper.wrap(e); + } + RepositoryTracing.debug("Downloading {0}", url); //$NON-NLS-1$ + + sendRetrieveRequest(url, output, null, true, monitor); + + return new InputStream() { + @Override + public int available() throws IOException { + checkException(); + return input.available(); + } + + @Override + public void close() throws IOException { + hardClose(input); + checkException(); + } + + @Override + public void mark(int readlimit) { + input.mark(readlimit); + } + + @Override + public boolean markSupported() { + return input.markSupported(); + } + + @Override + public int read() throws IOException { + checkException(); + return input.read(); + } + + @Override + public int read(byte b[]) throws IOException { + checkException(); + return input.read(b); + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + checkException(); + return input.read(b, off, len); + } + + @Override + public void reset() throws IOException { + checkException(); + input.reset(); + } + + @Override + public long skip(long n) throws IOException { + checkException(); + return input.skip(n); + } + + private void checkException() throws IOException { + if (getException() == null) { + return; + } + + IOException e; + Throwable t = RepositoryStatusHelper.unwind(getException()); + if (t instanceof IOException) { + e = (IOException) t; + } else { + if (t instanceof UserCancelledException) { + Throwable cause = t; + t = new OperationCanceledException(t.getMessage()); + t.initCause(cause); + } + e = new IOException(t.getMessage()); + e.initCause(t); + } + throw e; + } + }; + } + + public void readInto(URI uri, OutputStream anOutputStream, IProgressMonitor monitor) // + throws CoreException, FileNotFoundException, AuthenticationFailedException, JREHttpClientRequiredException { + readInto(uri, anOutputStream, -1, monitor); + } + + @Override + public boolean belongsTo(Object family) { + return family == this; + } + + public void readInto(URI uri, OutputStream anOutputStream, long startPos, IProgressMonitor monitor) // + throws CoreException, FileNotFoundException, AuthenticationFailedException, JREHttpClientRequiredException { + if (monitor == null) { + monitor = new NullProgressMonitor(); + } + try { + sendRetrieveRequest(uri, anOutputStream, (startPos != -1 ? new DownloadRange(startPos) : null), false, + monitor); + Job.getJobManager().join(this, new SuppressBlockedMonitor(monitor, 0)); + waitPaused(uri, anOutputStream, startPos, monitor); + if (monitor.isCanceled() && connectEvent != null) { + connectEvent.cancel(); + } + // check and throw exception if received in callback + checkException(uri, connectionRetryCount); + } catch (InterruptedException e) { + monitor.setCanceled(true); + throw new OperationCanceledException(); + } finally { + // kill the cancelJob, if there is one + if (cancelJob != null) { + cancelJob.cancel(); + cancelJob = null; + } + // If monitor was never started, make sure it is balanced + if (!monitorStarted) { + monitor.beginTask(null, 1); + } + monitorStarted = false; + monitor.done(); + } + } + + protected void waitPaused(URI uri, OutputStream anOutputStream, long startPos, IProgressMonitor monitor) + throws AuthenticationFailedException, JREHttpClientRequiredException, FileNotFoundException, CoreException, + OperationCanceledException, InterruptedException { + if (hasPaused) { + while (hasPaused) { + Thread.sleep(1000); + if (monitor.isCanceled()) { + throw new OperationCanceledException(); + } + } + Job.getJobManager().join(this, new SuppressBlockedMonitor(monitor, 0)); + waitPaused(uri, anOutputStream, startPos, monitor); + } + } + + protected void sendRetrieveRequest(URI uri, OutputStream outputStream, DownloadRange range, + boolean closeStreamOnFinish, // + IProgressMonitor monitor) + throws CoreException, FileNotFoundException, AuthenticationFailedException, JREHttpClientRequiredException { + + IRetrieveFileTransferFactory factory = Activator.getDefault().getRetrieveFileTransferFactory(); + if (factory == null) { + throw RepositoryStatusHelper.fromMessage(Messages.ecf_configuration_error); + } + + IRetrieveFileTransferContainerAdapter adapter = factory.newInstance(); + adapter.setConnectContextForAuthentication(connectContext); + + this.exception = null; + this.closeStreamWhenFinished = closeStreamOnFinish; + this.fileInfo = null; + this.statistics = null; + this.lastProgressCount = 0L; + this.lastStatsCount = 0L; + this.theMonitor = monitor; + this.monitorStarted = false; + this.theOutputStream = outputStream; + this.requestUri = uri; + + for (int retryCount = 0;; retryCount++) { + if (monitor != null && monitor.isCanceled()) { + throw new OperationCanceledException(); + } + + try { + IFileID fileID = FileIDFactory.getDefault().createFileID(adapter.getRetrieveNamespace(), + uri.toString()); + adapter.sendRetrieveRequest(fileID, range, this, options); + } catch (IncomingFileTransferException e) { + exception = e; + } catch (FileCreateException e) { + exception = e; + } catch (Throwable t) { + if (exception != null) { + exception.printStackTrace(); + } + } + if (checkException(uri, retryCount)) { + break; + } + } + } + + public synchronized boolean pause() { + this.isPause = true; + return true; + } + + public boolean isPaused() { + return this.isPause; + } + + public synchronized boolean resume() { + this.isPause = false; + if (this.pasuable != null) { + return this.pasuable.resume(); + } + return false; + } + + /** + * Utility method to check exception condition and determine if retry should be + * done. If there was an exception it is translated into one of the specified + * exceptions and thrown. + * + * @param uri the URI being read - used for logging purposes + * @param attemptCounter - the current attempt number (start with 0) + * @return true if the exception is an IOException and attemptCounter < + * connectionRetryCount, false otherwise + */ + private boolean checkException(URI uri, int attemptCounter) + throws CoreException, FileNotFoundException, AuthenticationFailedException, JREHttpClientRequiredException { + // note that 'exception' could have been captured in a callback + if (exception != null) { + // check if HTTP client needs to be changed + RepositoryStatusHelper.checkJREHttpClientRequired(exception); + + // if this is an 'authentication failure' - it is not meaningful to continue + RepositoryStatusHelper.checkPermissionDenied(exception); + + // if this is a 'file not found' - it is not meaningful to continue + RepositoryStatusHelper.checkFileNotFound(exception, uri); + + Throwable t = RepositoryStatusHelper.unwind(exception); + if (t instanceof CoreException) { + throw RepositoryStatusHelper.unwindCoreException((CoreException) t); + } + + if (!retryOnSocketTimeout) { + // not meaningful to try 'timeout again' - if a server is that busy, we + // need to wait for quite some time before retrying- it is not likely it is + // just a temporary network thing. + if (t instanceof SocketTimeoutException) { + throw RepositoryStatusHelper.wrap(t); + } + } + + if (t instanceof IOException && attemptCounter < connectionRetryCount) { + // TODO: Retry only certain exceptions or filter out + // some exceptions not worth retrying + // + exception = null; + try { + LogHelper.log(new Status(IStatus.WARNING, Activator.ID, + NLS.bind(Messages.connection_to_0_failed_on_1_retry_attempt_2, + uri.toString(), t.getMessage(), String.valueOf(attemptCounter)), + t)); + + Thread.sleep(connectionRetryDelay); + return false; + } catch (InterruptedException e) { + /* ignore */ + } + } + throw RepositoryStatusHelper.wrap(exception); + } + return true; + } + + protected Exception getException() { + return exception; + } + + /** + * Closes input and output streams + */ + public static void hardClose(Object aStream) { + if (aStream != null) { + try { + if (aStream instanceof OutputStream) { + ((OutputStream) aStream).close(); + } else if (aStream instanceof InputStream) { + ((InputStream) aStream).close(); + } + } catch (IOException e) { /* ignore */ + } + } + } + + private static class DownloadRange implements IFileRangeSpecification { + + private final long startPosition; + + public DownloadRange(long startPos) { + startPosition = startPos; + } + + @Override + public long getEndPosition() { + return -1; + } + + @Override + public long getStartPosition() { + return startPosition; + } + + } + + private void onDone(IIncomingFileTransfer source) { + if (testProbe != null) { + testProbe.onDone(this, source, theMonitor); + } + } + + private void onStart(IIncomingFileTransfer source) { + if (testProbe != null) { + testProbe.onStart(this, source, theMonitor); + } + } + + private void onData(IIncomingFileTransfer source) { + if (testProbe != null) { + testProbe.onData(this, source, theMonitor); + } + } + + /** + * Sets a testing probe that can intercept events on the file reader for testing + * purposes. This method should only ever be called from automated test suites. + */ + public static void setTestProbe(IFileReaderProbe probe) { + testProbe = probe; + } + + /** + * Sets the progress statistics. This method is synchronized because the field + * is accessed from both the transfer thread and the thread initiating the + * transfer and we need to ensure field values are consistent across threads. + * + * @param statistics the statistics to set, or null + */ + private synchronized void setStatistics(ProgressStatistics statistics) { + this.statistics = statistics; + } + + /** + * Returns the progress statistics. This method is synchronized because the + * field is accessed from both the transfer thread and the thread initiating the + * transfer and we need to ensure field values are consistent across threads. + * + * @return the statistics, or null + */ + private synchronized ProgressStatistics getStatistics() { + return statistics; + } + + /** + * An interface to allow automated tests to hook into file reader events + * + * @see #setTestProbe + */ + public interface IFileReaderProbe { + public void onStart(FileReader reader, IIncomingFileTransfer source, IProgressMonitor monitor); + + public void onData(FileReader reader, IIncomingFileTransfer source, IProgressMonitor monitor); + + public void onDone(FileReader reader, IIncomingFileTransfer source, IProgressMonitor monitor); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Messages.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Messages.java new file mode 100644 index 0000000000..e582743625 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/Messages.java @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (c) 2007, 2012 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Cloudsmith Inc - additional messages + * Sonatype Inc - ongoing development + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.transport.ecf; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.equinox.internal.p2.transport.ecf.messages"; //$NON-NLS-1$ + + public static String artifact_not_found; + public static String io_failedRead; + + public static String exception_malformedRepoURI; + public static String TransportErrorTranslator_400; + public static String TransportErrorTranslator_401; + public static String TransportErrorTranslator_402; + public static String TransportErrorTranslator_403; + public static String TransportErrorTranslator_404; + public static String TransportErrorTranslator_405; + public static String TransportErrorTranslator_406; + public static String TransportErrorTranslator_407; + public static String TransportErrorTranslator_408; + public static String TransportErrorTranslator_409; + public static String TransportErrorTranslator_410; + public static String TransportErrorTranslator_411; + public static String TransportErrorTranslator_412; + public static String TransportErrorTranslator_413; + public static String TransportErrorTranslator_414; + public static String TransportErrorTranslator_415; + public static String TransportErrorTranslator_416; + public static String TransportErrorTranslator_417; + public static String TransportErrorTranslator_418; + public static String TransportErrorTranslator_422; + public static String TransportErrorTranslator_423; + public static String TransportErrorTranslator_424; + public static String TransportErrorTranslator_425; + public static String TransportErrorTranslator_426; + public static String TransportErrorTranslator_449; + public static String TransportErrorTranslator_450; + public static String TransportErrorTranslator_500; + public static String TransportErrorTranslator_501; + public static String TransportErrorTranslator_502; + public static String TransportErrorTranslator_503; + public static String TransportErrorTranslator_504; + public static String TransportErrorTranslator_505; + public static String TransportErrorTranslator_506; + public static String TransportErrorTranslator_507; + public static String TransportErrorTranslator_508; + public static String TransportErrorTranslator_510; + public static String TransportErrorTranslator_MalformedRemoteFileReference; + public static String TransportErrorTranslator_UnableToConnectToRepository_0; + + public static String TransportErrorTranslator_UnknownErrorCode; + public static String TransportErrorTranslator_UnknownHost; + + static { + // initialize resource bundles + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + // Do not instantiate + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java new file mode 100644 index 0000000000..4cfd64597c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2025 Christoph Läubrich and others. + * The code, documentation and other materials contained herein have been + * licensed under the Eclipse Public License - v 1.0 by the copyright holder + * listed above, as the Initial Contributor under such license. The text of + * such license is available at www.eclipse.org. + * Contributors: + * Christoph Läubrich - initial implementation + ******************************************************************************/ +package org.eclipse.equinox.internal.p2.transport.ecf; + +import java.security.*; +import javax.net.ssl.SSLContext; +import org.eclipse.ecf.core.security.SSLContextFactory; +import org.osgi.framework.Constants; +import org.osgi.service.component.annotations.Component; + +@Component(property = Constants.SERVICE_RANKING + ":Integer=100") +public class P2SSLContextFactory implements SSLContextFactory { + + @Override + public SSLContext getDefault() throws NoSuchAlgorithmException { + // the default is guaranteed to be initialized always + return SSLContext.getDefault(); + } + + @Override + public SSLContext getInstance(String protocol) throws NoSuchAlgorithmException, NoSuchProviderException { + SSLContext context = SSLContext.getInstance(protocol); + try { + // init it as we have a new context here + context.init(null, null, null); + } catch (KeyManagementException e) { + throw new NoSuchProviderException(); + } + return context; + } + + @Override + public SSLContext getInstance(String protocol, String providerName) + throws NoSuchAlgorithmException, NoSuchProviderException { + SSLContext context = SSLContext.getInstance(protocol, providerName); + try { + // init it as we have a new context here + context.init(null, null, null); + } catch (KeyManagementException e) { + throw new NoSuchProviderException(); + } + return context; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatus.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatus.java new file mode 100644 index 0000000000..78440042dd --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatus.java @@ -0,0 +1,163 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Cloudsmith Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Cloudsmith Inc. - initial API and implementation + *******************************************************************************/ + +package org.eclipse.equinox.internal.p2.transport.ecf; + +import org.eclipse.equinox.internal.p2.repository.DownloadStatus; +import org.eclipse.equinox.p2.core.ProvisionException; + +import java.io.FileNotFoundException; +import java.net.*; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.identity.IDCreateException; +import org.eclipse.ecf.filetransfer.BrowseFileTransferException; +import org.eclipse.ecf.filetransfer.IncomingFileTransferException; +import org.eclipse.osgi.util.NLS; + +/** + * Utility class to transform transport errors into error messages. + */ +public class RepositoryStatus { + + public static String codeToMessage(int code, String toDownload) { + switch (code) { + case 400 : + return NLS.bind(Messages.TransportErrorTranslator_400, toDownload); + case 401 : + return NLS.bind(Messages.TransportErrorTranslator_401, toDownload); + case 402 : + return NLS.bind(Messages.TransportErrorTranslator_402, toDownload); + case 403 : + return NLS.bind(Messages.TransportErrorTranslator_403, toDownload); + case 404 : + return NLS.bind(Messages.TransportErrorTranslator_404, toDownload); + case 405 : + return NLS.bind(Messages.TransportErrorTranslator_405, toDownload); + case 406 : + return NLS.bind(Messages.TransportErrorTranslator_406, toDownload); + case 407 : + return NLS.bind(Messages.TransportErrorTranslator_407, toDownload); + case 408 : + return NLS.bind(Messages.TransportErrorTranslator_408, toDownload); + case 409 : + return NLS.bind(Messages.TransportErrorTranslator_409, toDownload); + case 410 : + return NLS.bind(Messages.TransportErrorTranslator_410, toDownload); + case 411 : + return NLS.bind(Messages.TransportErrorTranslator_411, toDownload); + case 412 : + return NLS.bind(Messages.TransportErrorTranslator_412, toDownload); + case 413 : + return NLS.bind(Messages.TransportErrorTranslator_413, toDownload); + case 414 : + return NLS.bind(Messages.TransportErrorTranslator_414, toDownload); + case 415 : + return NLS.bind(Messages.TransportErrorTranslator_415, toDownload); + case 416 : + return NLS.bind(Messages.TransportErrorTranslator_416, toDownload); + case 417 : + return NLS.bind(Messages.TransportErrorTranslator_417, toDownload); + case 418 : + return NLS.bind(Messages.TransportErrorTranslator_418, toDownload); + case 422 : + return NLS.bind(Messages.TransportErrorTranslator_422, toDownload); + case 423 : + return NLS.bind(Messages.TransportErrorTranslator_423, toDownload); + case 424 : + return NLS.bind(Messages.TransportErrorTranslator_424, toDownload); + case 425 : + return NLS.bind(Messages.TransportErrorTranslator_425, toDownload); + case 426 : + return NLS.bind(Messages.TransportErrorTranslator_426, toDownload); + case 449 : + return NLS.bind(Messages.TransportErrorTranslator_449, toDownload); + case 450 : + return NLS.bind(Messages.TransportErrorTranslator_450, toDownload); + + case 500 : + return NLS.bind(Messages.TransportErrorTranslator_500, toDownload); + case 501 : + return NLS.bind(Messages.TransportErrorTranslator_501, toDownload); + case 502 : + return NLS.bind(Messages.TransportErrorTranslator_502, toDownload); + case 503 : + return NLS.bind(Messages.TransportErrorTranslator_503, toDownload); + case 504 : + return NLS.bind(Messages.TransportErrorTranslator_504, toDownload); + case 505 : + return NLS.bind(Messages.TransportErrorTranslator_505, toDownload); + case 506 : + return NLS.bind(Messages.TransportErrorTranslator_506, toDownload); + case 507 : + return NLS.bind(Messages.TransportErrorTranslator_507, toDownload); + case 508 : + return NLS.bind(Messages.TransportErrorTranslator_508, toDownload); + case 510 : + return NLS.bind(Messages.TransportErrorTranslator_510, toDownload); + + default : + return NLS.bind(Messages.TransportErrorTranslator_UnknownErrorCode, Integer.toString(code), toDownload); + } + } + + public static DownloadStatus forStatus(IStatus original, URI toDownload) { + Throwable t = original.getException(); + return forException(t, toDownload); + } + + public static DownloadStatus forException(Throwable t, URI toDownload) { + if (t instanceof FileNotFoundException || (t instanceof IncomingFileTransferException && ((IncomingFileTransferException) t).getErrorCode() == 404)) { + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.ARTIFACT_NOT_FOUND, NLS.bind(Messages.artifact_not_found, toDownload), t); + } + if (t instanceof ConnectException) { + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_FAILED_READ, NLS.bind(Messages.TransportErrorTranslator_UnableToConnectToRepository_0, toDownload), t); + } + if (t instanceof UnknownHostException) { + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_INVALID_LOCATION, NLS.bind(Messages.TransportErrorTranslator_UnknownHost, toDownload), t); + } + if (t instanceof IDCreateException) { + IStatus status = ((IDCreateException) t).getStatus(); + if (status != null && status.getException() != null) { + t = status.getException(); + } + + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_INVALID_LOCATION, NLS.bind(Messages.TransportErrorTranslator_MalformedRemoteFileReference, toDownload), t); + } + int code = 0; + + // default to report as read repository error + int provisionCode = ProvisionException.REPOSITORY_FAILED_READ; + + if (t instanceof IncomingFileTransferException) { + code = ((IncomingFileTransferException) t).getErrorCode(); + } else if (t instanceof BrowseFileTransferException) { + code = ((BrowseFileTransferException) t).getErrorCode(); + } + + // Switch on error codes in the HTTP error code range. + // Note that 404 uses ARTIFACT_NOT_FOUND (as opposed to REPOSITORY_NOT_FOUND, which + // is determined higher up in the calling chain). + if (code == 401) { + provisionCode = ProvisionException.REPOSITORY_FAILED_AUTHENTICATION; + } else if (code == 404) { + provisionCode = ProvisionException.ARTIFACT_NOT_FOUND; + } + + // Add more specific translation here + + return new DownloadStatus(IStatus.ERROR, Activator.ID, provisionCode, // + code == 0 ? NLS.bind(Messages.io_failedRead, toDownload) // + : codeToMessage(code, toDownload.toString()), t); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatusHelper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatusHelper.java new file mode 100644 index 0000000000..99b216d4c7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryStatusHelper.java @@ -0,0 +1,342 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Cloudsmith Inc, and other. + * The code, documentation and other materials contained herein have been + * licensed under the Eclipse Public License - v 1.0 by the individual + * copyright holders listed above, as Initial Contributors under such license. + * The text of such license is available at www.eclipse.org. + * Contributors: + * Cloudsmith Inc. - Initial API and implementation + * IBM Corporation - Original Implementation of checkPermissionDenied + * IBM Corportaion - Ongoing development + *******************************************************************************/ +package org.eclipse.equinox.internal.p2.transport.ecf; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintStream; +import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.concurrent.ExecutionException; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.ecf.filetransfer.BrowseFileTransferException; +import org.eclipse.ecf.filetransfer.IncomingFileTransferException; +import org.eclipse.equinox.internal.p2.repository.AuthenticationFailedException; +import org.eclipse.equinox.internal.p2.repository.JREHttpClientRequiredException; +import org.eclipse.equinox.p2.core.ProvisionException; +import org.eclipse.osgi.util.NLS; + +/** + * RepositoryStatusHelper is a utility class for processing of exceptions and status. + */ +public abstract class RepositoryStatusHelper { + + protected static final String SERVER_REDIRECT = "Server redirected too many times"; //$NON-NLS-1$ + + public static IStatus createStatus(String nlsMessage, Object arg) { + return createExceptionStatus(null, nlsMessage, new Object[] {arg}); + } + + public static IStatus createStatus(String nlsMessage, Object arg1, Object arg2) { + return createExceptionStatus(null, nlsMessage, new Object[] {arg1, arg2}); + } + + public static IStatus createStatus(String nlsMessage, Object arg1, Object arg2, Object arg3) { + return createExceptionStatus(null, nlsMessage, new Object[] {arg1, arg2, arg3}); + } + + public static IStatus createStatus(String nlsMessage, Object[] args) { + return createExceptionStatus(null, nlsMessage, args); + } + + public static IStatus createStatus(String nlsMessage) { + return createExceptionStatus(null, nlsMessage, new Object[] {}); + } + + public static IStatus createExceptionStatus(Throwable cause) { + return (cause instanceof CoreException c) ? c.getStatus() : new Status(IStatus.ERROR, Activator.ID, IStatus.OK, cause.getMessage(), cause); + } + + public static IStatus createExceptionStatus(Throwable cause, String nlsMessage, Object[] args) { + if (args != null && args.length > 0) { + nlsMessage = NLS.bind(nlsMessage, args); + } + return new Status(IStatus.ERROR, Activator.ID, IStatus.OK, nlsMessage, cause); + } + + public static IStatus createExceptionStatus(Throwable cause, String nlsMessage, Object arg1, Object arg2, Object arg3) { + return createExceptionStatus(cause, nlsMessage, new Object[] {arg1, arg2, arg3}); + } + + public static IStatus createExceptionStatus(Throwable cause, String nlsMessage, Object arg1, Object arg2) { + return createExceptionStatus(cause, nlsMessage, new Object[] {arg1, arg2}); + } + + public static IStatus createExceptionStatus(Throwable cause, String nlsMessage, Object arg1) { + return createExceptionStatus(cause, nlsMessage, new Object[] {arg1}); + } + + public static IStatus createExceptionStatus(Throwable cause, String nlsMessage) { + return createExceptionStatus(cause, nlsMessage, new Object[] {}); + } + + public static void deeplyPrint(Throwable e, PrintStream strm, boolean stackTrace) { + deeplyPrint(e, strm, stackTrace, 0); + } + + public static CoreException fromMessage(String nlsMessage, Object[] args) { + return fromExceptionMessage(null, nlsMessage, args); + } + + public static CoreException fromMessage(String nlsMessage, Object arg1) { + return fromExceptionMessage(null, nlsMessage, new Object[] {arg1}); + } + + public static CoreException fromMessage(String nlsMessage, Object arg1, Object arg2) { + return fromExceptionMessage(null, nlsMessage, new Object[] {arg1, arg2}); + } + + public static CoreException fromMessage(String nlsMessage, Object arg1, Object arg2, Object arg3) { + return fromExceptionMessage(null, nlsMessage, new Object[] {arg1, arg2, arg3}); + } + + public static CoreException fromMessage(String nlsMessage) { + return fromExceptionMessage(null, nlsMessage, new Object[] {}); + } + + public static CoreException fromExceptionMessage(Throwable cause, String nlsMessage, Object[] args) { + CoreException ce = new CoreException(createExceptionStatus(cause, nlsMessage, args)); + if (cause != null) { + ce.initCause(cause); + } + return ce; + } + + public static CoreException fromExceptionMessage(Throwable cause, String nlsMessage, Object arg1, Object arg2, Object arg3) { + return fromExceptionMessage(cause, nlsMessage, new Object[] {arg1, arg2, arg3}); + } + + public static CoreException fromExceptionMessage(Throwable cause, String nlsMessage, Object arg1, Object arg2) { + return fromExceptionMessage(cause, nlsMessage, new Object[] {arg1, arg2}); + } + + public static CoreException fromExceptionMessage(Throwable cause, String nlsMessage, Object arg1) { + return fromExceptionMessage(cause, nlsMessage, new Object[] {arg1}); + } + + public static CoreException fromExceptionMessage(Throwable cause, String nlsMessage) { + return fromExceptionMessage(cause, nlsMessage, new Object[] {}); + } + + public static Throwable unwind(Throwable t) { + for (;;) { + Class tc = t.getClass(); + + // We don't use instanceof operator since we want + // the explicit class, not subclasses. + // + if (tc != RuntimeException.class && tc != InvocationTargetException.class && tc != IOException.class + && tc != ExecutionException.class) { + break; + } + + Throwable cause = t.getCause(); + if (cause == null) { + break; + } + + String msg = t.getMessage(); + if (msg != null && !msg.equals(cause.toString())) { + break; + } + + t = cause; + } + return t; + } + + public static CoreException unwindCoreException(CoreException exception) { + IStatus status = exception.getStatus(); + while (status != null && status.getException() instanceof CoreException) { + exception = (CoreException) status.getException(); + status = exception.getStatus(); + } + return exception; + } + + public static CoreException wrap(IStatus status) { + CoreException e = new CoreException(status); + Throwable t = status.getException(); + if (t != null) { + e.initCause(t); + } + return e; + } + + public static CoreException wrap(Throwable t) { + t = unwind(t); + if (t instanceof CoreException) { + return unwindCoreException((CoreException) t); + } + + if (t instanceof OperationCanceledException || t instanceof InterruptedException) { + return new CoreException(Status.CANCEL_STATUS); + } + + String msg = t.toString(); + return fromExceptionMessage(t, msg); + } + + private static void appendLevelString(PrintStream strm, int level) { + if (level > 0) { + strm.print("[0"); //$NON-NLS-1$ + for (int idx = 1; idx < level; ++idx) { + strm.print('.'); + strm.print(level); + } + strm.print(']'); + } + } + + private static void deeplyPrint(CoreException ce, PrintStream strm, boolean stackTrace, int level) { + appendLevelString(strm, level); + if (stackTrace) { + ce.printStackTrace(strm); + } + deeplyPrint(ce.getStatus(), strm, stackTrace, level); + } + + private static void deeplyPrint(IStatus status, PrintStream strm, boolean stackTrace, int level) { + appendLevelString(strm, level); + String msg = status.getMessage(); + strm.println(msg); + Throwable cause = status.getException(); + if (cause != null) { + strm.print("Caused by: "); //$NON-NLS-1$ + if (stackTrace || !(msg.equals(cause.getMessage()) || msg.equals(cause.toString()))) { + deeplyPrint(cause, strm, stackTrace, level); + } + } + + if (status.isMultiStatus()) { + IStatus[] children = status.getChildren(); + for (IStatus child : children) { + deeplyPrint(child, strm, stackTrace, level + 1); + } + } + } + + private static void deeplyPrint(Throwable t, PrintStream strm, boolean stackTrace, int level) { + if (t instanceof CoreException) { + deeplyPrint((CoreException) t, strm, stackTrace, level); + } else { + appendLevelString(strm, level); + if (stackTrace) { + t.printStackTrace(strm); + } else { + strm.println(t.toString()); + Throwable cause = t.getCause(); + if (cause != null) { + strm.print("Caused by: "); //$NON-NLS-1$ + deeplyPrint(cause, strm, stackTrace, level); + } + } + } + } + + /** + * Check if the given exception represents that a switch to the JRE HTTP Client + * is required. ECF sets the HTTP status code 477 to indicate this. + * If the JRE HTTP client is required a JREHttpClientRequiredException is thrown. + */ + public static void checkJREHttpClientRequired(Throwable t) throws JREHttpClientRequiredException { + if (t instanceof IncomingFileTransferException) { + if (((IncomingFileTransferException) t).getErrorCode() == 477) { + throw new JREHttpClientRequiredException(); + } + } else if (t instanceof BrowseFileTransferException) { + if (((BrowseFileTransferException) t).getErrorCode() == 477) { + throw new JREHttpClientRequiredException(); + } + } + + } + + /** + * Check if the given exception represents a permission failure (401 for HTTP), + * and throw a AuthenticationFailedException if a permission failure was encountered. + */ + public static void checkPermissionDenied(Throwable t) throws AuthenticationFailedException { + // From Use of File Transfer + if (t instanceof IncomingFileTransferException) { + if (((IncomingFileTransferException) t).getErrorCode() == 401) { + throw new AuthenticationFailedException(); + } + IStatus status = ((IncomingFileTransferException) t).getStatus(); + t = status == null ? t : status.getException(); + // From Use of Browse + } else if (t instanceof BrowseFileTransferException) { + if (((BrowseFileTransferException) t).getErrorCode() == 401) { + throw new AuthenticationFailedException(); + } + IStatus status = ((BrowseFileTransferException) t).getStatus(); + t = status == null ? t : status.getException(); + } + + if (t == null || !(t instanceof IOException)) { + return; + } + + // TODO: is this needed (for 401) now that ECF throws exceptions with codes? + // try to figure out if we have a 401 by parsing the exception message + // There is unfortunately no specific (general) exception for "redirected too many times" - which is commonly + // caused by a failed login. The message and exception are different in different implementations + // of http client. + String m = t.getMessage(); + if (m != null && (m.contains(" 401 ") || m.contains(SERVER_REDIRECT))) { //$NON-NLS-1$ + throw new AuthenticationFailedException(); + } + if ("org.apache.commons.httpclient.RedirectException".equals(t.getClass().getName())) { //$NON-NLS-1$ + throw new AuthenticationFailedException(); + } + } + + /** + * Translates exceptions representing "FileNotFound" into FileNotFoundException. + * @param t the throwable to check + * @param toDownload the URI the exception was thrown for + * @throws FileNotFoundException if 't' represents a file not found + */ + public static void checkFileNotFound(Throwable t, URI toDownload) throws FileNotFoundException { + if (t instanceof IncomingFileTransferException e) { + if (e.getErrorCode() == 404 || e.getErrorCode() == 403 || e.getErrorCode() == 300) { + throw new FileNotFoundException(toDownload.toString()); + } + } + if (t instanceof BrowseFileTransferException e) { + if (e.getErrorCode() == 404 || e.getErrorCode() == 403 || e.getErrorCode() == 300) { + throw new FileNotFoundException(toDownload.toString()); + } + } + + if (t instanceof FileNotFoundException) { + throw (FileNotFoundException) t; + } + if (t instanceof CoreException) { + IStatus status = ((CoreException) t).getStatus(); + Throwable e = status == null ? null : status.getException(); + if (e instanceof FileNotFoundException) { + throw (FileNotFoundException) e; + } + } + } + + public static IStatus malformedAddressStatus(String address, Throwable t) { + return new Status(IStatus.ERROR, Activator.ID, // + ProvisionException.REPOSITORY_INVALID_LOCATION, NLS.bind(Messages.exception_malformedRepoURI, address), t); + + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java new file mode 100644 index 0000000000..8e123abc98 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/RepositoryTransport.java @@ -0,0 +1,393 @@ +/******************************************************************************* + * Copyright (c) 2006, 2022 IBM Corporation and others. + * The code, documentation and other materials contained herein have been + * licensed under the Eclipse Public License - v 1.0 by the copyright holder + * listed above, as the Initial Contributor under such license. The text of + * such license is available at www.eclipse.org. + * + * Contributors + * IBM Corporation - Initial API and implementation. + * Cloudsmith Inc - Implementation + * Christoph Läubrich - Issue #6 - Deprecate Transport.download(URI, OutputStream, long, IProgressMonitor) + ******************************************************************************/ + +package org.eclipse.equinox.internal.p2.transport.ecf; + +import java.io.*; +import java.net.*; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.core.identity.IDCreateException; +import org.eclipse.ecf.core.security.ConnectContextFactory; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.filetransfer.*; +import org.eclipse.equinox.internal.p2.repository.*; +import org.eclipse.equinox.internal.p2.repository.Credentials.LoginCanceledException; +import org.eclipse.equinox.internal.p2.repository.Messages; +import org.eclipse.equinox.internal.provisional.p2.core.eventbus.IProvisioningEventBus; +import org.eclipse.equinox.internal.provisional.p2.core.eventbus.ProvisioningListener; +import org.eclipse.equinox.internal.provisional.p2.repository.IStateful; +import org.eclipse.equinox.p2.core.IProvisioningAgent; +import org.eclipse.equinox.p2.core.ProvisionException; +import org.eclipse.equinox.p2.core.UIServices.AuthenticationInfo; +import org.eclipse.equinox.p2.repository.artifact.IArtifactRepository; +import org.eclipse.osgi.util.NLS; + +/** + * RepositoryTransport adapts p2 to ECF file download and file browsing. + * Download is performed by {@link FileReader}, and file browsing is performed + * by {@link FileInfoReader}. + */ +public class RepositoryTransport extends Transport { + + public static final String TIMEOUT_RETRY = "org.eclipse.equinox.p2.transport.ecf.retry"; //$NON-NLS-1$ + + private static class Retry { + long LIFETIME = TimeUnit.MINUTES.toMillis(10); + long expiration; + int count; + + public Retry() { + expiration = System.currentTimeMillis() + LIFETIME; + } + + public synchronized int increment() { + long now = System.currentTimeMillis(); + if (now > expiration) { + expiration = now + LIFETIME; + count = 1; + return 1; + } + return ++count; + } + } + + private static final Map SOCKET_EXCEPTION_RETRY = new ConcurrentHashMap<>(); + + private IProvisioningAgent agent = null; + + /** + * Returns an shared instance of Generic Transport + */ + // public static synchronized RepositoryTransport getInstance() { + // if (instance == null) { + // instance = new RepositoryTransport(); + // } + // return instance; + // } + + public RepositoryTransport() { + this(null); + } + + /** + * + * @param agent If agent is null, it means client would like to use + * RepositoryTransport as a download utility, don't want to publish + * download progress. + */ + public RepositoryTransport(IProvisioningAgent agent) { + this.agent = agent; + } + + @Override + public IStatus download(URI toDownload, OutputStream target, IProgressMonitor monitor) { + boolean promptUser = false; + boolean useJREHttp = false; + AuthenticationInfo loginDetails = null; + URI secureToDownload; + try { + secureToDownload = getSecureLocation(toDownload); + } catch (CoreException e) { + return e.getStatus(); + } + for (int i = RepositoryPreferences.getLoginRetryCount(); i > 0; i--) { + FileReader reader = null; + try { + loginDetails = Credentials.forLocation(secureToDownload, promptUser, loginDetails); + IConnectContext context = (loginDetails == null) ? null + : ConnectContextFactory.createUsernamePasswordConnectContext(loginDetails.getUserName(), + loginDetails.getPassword()); + + // perform the download + reader = new FileReader(agent, context); + ProvisioningListener listener = null; + IProvisioningEventBus eventBus = null; + try { + if (agent != null) { + eventBus = agent.getService(IProvisioningEventBus.class); + if (eventBus != null) { + final FileReader fileReader = reader; + listener = event -> { + if (event instanceof DownloadPauseResumeEvent) { + if (((DownloadPauseResumeEvent) event) + .getType() == DownloadPauseResumeEvent.TYPE_PAUSE) { + fileReader.pause(); + } else if (((DownloadPauseResumeEvent) event) + .getType() == DownloadPauseResumeEvent.TYPE_RESUME) { + fileReader.resume(); + } + } + }; + eventBus.addListener(listener); + } + } + reader.readInto(secureToDownload, target, -1, monitor); + } finally { + if (eventBus != null) { + eventBus.removeListener(listener); + } + } + + // check that job ended ok - throw exceptions otherwise + IStatus result = reader.getResult(); + if (result == null) { + String msg = NLS.bind(Messages.RepositoryTransport_failedReadRepo, secureToDownload); + DownloadStatus ds = new DownloadStatus(IStatus.ERROR, Activator.ID, + ProvisionException.REPOSITORY_FAILED_READ, msg, null); + return statusOn(target, ds, reader); + } + if (result.getSeverity() == IStatus.CANCEL) { + throw new OperationCanceledException(); + } + if (!result.isOK()) { + throw new CoreException(result); + } + + // Download status is expected on success + DownloadStatus status = new DownloadStatus(IStatus.OK, Activator.ID, Status.OK_STATUS.getMessage()); + return statusOn(target, status, reader); + } catch (UserCancelledException e) { + statusOn(target, new DownloadStatus(IStatus.CANCEL, Activator.ID, 1, "", null), reader); //$NON-NLS-1$ + throw new OperationCanceledException(); + } catch (OperationCanceledException e) { + statusOn(target, new DownloadStatus(IStatus.CANCEL, Activator.ID, 1, "", null), reader); //$NON-NLS-1$ + throw e; + } catch (CoreException e) { + if (e.getStatus().getException() == null) { + return statusOn(target, forException(e, secureToDownload), reader); + } + return statusOn(target, forStatus(e.getStatus(), secureToDownload), reader); + } catch (FileNotFoundException e) { + return statusOn(target, forException(e, secureToDownload), reader); + } catch (AuthenticationFailedException e) { + promptUser = true; + } catch (Credentials.LoginCanceledException e) { + DownloadStatus status = new DownloadStatus(IStatus.ERROR, Activator.ID, + ProvisionException.REPOSITORY_FAILED_AUTHENTICATION, // + NLS.bind(Messages.UnableToRead_0_UserCanceled, secureToDownload), null); + return statusOn(target, status, null); + } catch (JREHttpClientRequiredException e) { + if (!useJREHttp) { + useJREHttp = true; // only do this once + i++; // need an extra retry + Activator.getDefault().useJREHttpClient(); + } + } + } + // reached maximum number of retries without success + DownloadStatus status = new DownloadStatus(IStatus.ERROR, Activator.ID, + ProvisionException.REPOSITORY_FAILED_AUTHENTICATION, // + NLS.bind(Messages.UnableToRead_0_TooManyAttempts, secureToDownload), null); + return statusOn(target, status, null); + } + + @Override + public InputStream stream(URI toDownload, IProgressMonitor monitor) + throws FileNotFoundException, CoreException, AuthenticationFailedException { + + boolean promptUser = false; + boolean useJREHttp = false; + AuthenticationInfo loginDetails = null; + URI secureToDownload = getSecureLocation(toDownload); + for (int i = RepositoryPreferences.getLoginRetryCount(); i > 0; i--) { + FileReader reader = null; + try { + loginDetails = Credentials.forLocation(secureToDownload, promptUser, loginDetails); + IConnectContext context = (loginDetails == null) ? null + : ConnectContextFactory.createUsernamePasswordConnectContext(loginDetails.getUserName(), + loginDetails.getPassword()); + + // perform the streamed download + reader = new FileReader(agent, context); + return reader.read(secureToDownload, monitor); + } catch (UserCancelledException e) { + throw new OperationCanceledException(); + } catch (AuthenticationFailedException e) { + promptUser = true; + } catch (CoreException e) { + // must translate this core exception as it is most likely not informative to a + // user + if (e.getStatus().getException() == null) { + throw new CoreException(forException(e, secureToDownload)); + } + throw new CoreException(forStatus(e.getStatus(), secureToDownload)); + } catch (LoginCanceledException e) { + // i.e. same behavior when user cancels as when failing n attempts. + throw new AuthenticationFailedException(); + } catch (JREHttpClientRequiredException e) { + if (!useJREHttp) { + useJREHttp = true; // only do this once + i++; // need an extra retry + Activator.getDefault().useJREHttpClient(); + } + } + } + throw new AuthenticationFailedException(); + } + + /** + * Set the status on the output stream if it implements IStateful. Update the + * DownloadStatus with information from FileReader. + * + * @param target an OutputStream possibly implementing IStateful + * @param status a DownloadStatus configured with status message, code, etc + * @param reader a FileReade that was used to download (or null if not known). + * @throws OperationCanceledException if the operation was canceled by the user. + * @return the configured DownloadStatus status. + */ + private static DownloadStatus statusOn(OutputStream target, DownloadStatus status, FileReader reader) { + if (reader != null) { + FileInfo fi = reader.getLastFileInfo(); + if (fi != null) { + status.setFileSize(fi.getSize()); + status.setLastModified(fi.getLastModified()); + status.setTransferRate(fi.getAverageSpeed()); + } + } + if (target instanceof IStateful) { + ((IStateful) target).setStatus(status); + } + return status; + } + + @Override + public long getLastModified(URI toDownload, IProgressMonitor monitor) + throws CoreException, FileNotFoundException, AuthenticationFailedException { + boolean promptUser = false; + boolean useJREHttp = false; + AuthenticationInfo loginDetails = null; + URI secureToDownload = getSecureLocation(toDownload); + for (int i = RepositoryPreferences.getLoginRetryCount(); i > 0; i--) { + try { + loginDetails = Credentials.forLocation(secureToDownload, promptUser, loginDetails); + IConnectContext context = (loginDetails == null) ? null + : ConnectContextFactory.createUsernamePasswordConnectContext(loginDetails.getUserName(), + loginDetails.getPassword()); + // get the remote info + FileInfoReader reader = new FileInfoReader(context); + return reader.getLastModified(secureToDownload, monitor); + } catch (UserCancelledException e) { + throw new OperationCanceledException(); + } catch (CoreException e) { + // must translate this core exception as it is most likely not informative to a + // user + if (e.getStatus().getException() == null) { + throw new CoreException(forException(e, secureToDownload)); + } + throw new CoreException(forStatus(e.getStatus(), secureToDownload)); + } catch (AuthenticationFailedException e) { + promptUser = true; + } catch (LoginCanceledException e) { + // same behavior as if user failed n attempts. + throw new AuthenticationFailedException(); + } catch (JREHttpClientRequiredException e) { + if (!useJREHttp) { + useJREHttp = true; // only do this once + i++; // need an extra retry + Activator.getDefault().useJREHttpClient(); + } + } + + } + // reached maximum number of authentication retries without success + throw new AuthenticationFailedException(); + } + + private static boolean isForgiveableException(Throwable t) { + if (t instanceof SocketTimeoutException) { + return true; + } else if (t instanceof SocketException) { + return true; + } else if (t instanceof IncomingFileTransferException + && ((IncomingFileTransferException) t).getErrorCode() == 503) { + return true; + } + return false; + } + + public static DownloadStatus forStatus(IStatus original, URI toDownload) { + Throwable t = original.getException(); + if (isForgiveableException(t) && original.getCode() == IArtifactRepository.CODE_RETRY) { + return new DownloadStatus(original.getSeverity(), Activator.ID, original.getCode(), original.getMessage(), + t); + } + return forException(t, toDownload); + } + + public static DownloadStatus forException(Throwable t, URI toDownload) { + if (isForgiveableException(t)) { + int retry = Integer.getInteger(TIMEOUT_RETRY, 0); + if (retry > 0) { + int retryCount = SOCKET_EXCEPTION_RETRY.computeIfAbsent(toDownload, uri -> new Retry()).increment(); + if (retryCount <= retry) { + return new DownloadStatus(IStatus.ERROR, Activator.ID, IArtifactRepository.CODE_RETRY, NLS.bind( + Messages.connection_to_0_failed_on_1_retry_attempt_2, + toDownload.toString(), t.getMessage(), Integer.toString(retryCount)), t); + } + } + } + if (t instanceof FileNotFoundException || (t instanceof IncomingFileTransferException + && ((IncomingFileTransferException) t).getErrorCode() == 404)) { + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.ARTIFACT_NOT_FOUND, + NLS.bind(Messages.artifact_not_found, toDownload), t); + } + if (t instanceof ConnectException) { + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_FAILED_READ, + NLS.bind(Messages.TransportErrorTranslator_UnableToConnectToRepository_0, toDownload), t); + } + if (t instanceof UnknownHostException) { + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_INVALID_LOCATION, + NLS.bind(Messages.TransportErrorTranslator_UnknownHost, toDownload), t); + } + if (t instanceof IDCreateException) { + IStatus status = ((IDCreateException) t).getStatus(); + if (status != null && status.getException() != null) { + t = status.getException(); + } + + return new DownloadStatus(IStatus.ERROR, Activator.ID, ProvisionException.REPOSITORY_INVALID_LOCATION, + NLS.bind(Messages.TransportErrorTranslator_MalformedRemoteFileReference, toDownload), t); + } + int code = 0; + + // default to report as read repository error + int provisionCode = ProvisionException.REPOSITORY_FAILED_READ; + + if (t instanceof IncomingFileTransferException) { + code = ((IncomingFileTransferException) t).getErrorCode(); + } else if (t instanceof BrowseFileTransferException) { + code = ((BrowseFileTransferException) t).getErrorCode(); + } + + // Switch on error codes in the HTTP error code range. + // Note that 404 uses ARTIFACT_NOT_FOUND (as opposed to REPOSITORY_NOT_FOUND, + // which + // is determined higher up in the calling chain). + if (code == 401) { + provisionCode = ProvisionException.REPOSITORY_FAILED_AUTHENTICATION; + } else if (code == 404) { + provisionCode = ProvisionException.ARTIFACT_NOT_FOUND; + } + + // Add more specific translation here + + return new DownloadStatus(IStatus.ERROR, Activator.ID, provisionCode, // + code == 0 ? NLS.bind(Messages.io_failedRead, toDownload) // + : RepositoryStatus.codeToMessage(code, toDownload.toString()), + t); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/messages.properties b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/messages.properties new file mode 100644 index 0000000000..2ee026d0ae --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/messages.properties @@ -0,0 +1,61 @@ +############################################################################### +# Copyright (c) 2007, 2012 IBM Corporation and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +# Cloudsmith Inc - additional messages +# Sonatype Inc - ongoing implementation +############################################################################### +artifact_not_found=Artifact not found: {0}. + +io_failedRead=Unable to read repository at {0}. + +exception_malformedRepoURI = The repository location ({0}) must be a URI. + +TransportErrorTranslator_400=Bad HTTP Request: {0} +TransportErrorTranslator_401=Authentication Failed - Unauthorized: {0} +TransportErrorTranslator_402=HTTP Payment Required: {0} +TransportErrorTranslator_403=HTTP Access Forbidden: {0} +TransportErrorTranslator_404=HTTP Remote File Not Found: {0} +TransportErrorTranslator_405=HTTP Method Not Allowed: {0} +TransportErrorTranslator_406=HTTP Request Not Acceptable: {0} +TransportErrorTranslator_407=HTTP Proxy Authentication Required: {0} +TransportErrorTranslator_408=HTTP Request Timeout: {0} +TransportErrorTranslator_409=HTTP Conflict In Request: {0} +TransportErrorTranslator_410=HTTP Remote File Permanently Removed: {0} +TransportErrorTranslator_411=HTTP Length Required: {0} +TransportErrorTranslator_412=HTTP Precondition Failed: {0} +TransportErrorTranslator_413=HTTP Requested Entity Too Large: {0} +TransportErrorTranslator_414=HTTP Request URI Too Long: {0} +TransportErrorTranslator_415=HTTP Unsupported Media Type: {0} +TransportErrorTranslator_416=HTTP Requested Range Not Satisfiable: {0} +TransportErrorTranslator_417=HTTP Expectation Failed: {0} +TransportErrorTranslator_418=HTTP Cannot provision coffee from a tea pot: {0} +TransportErrorTranslator_422=HTTP (WebDav) Unprocessable Entity: {0} +TransportErrorTranslator_423=HTTP (WebDAV) Locked: {0} +TransportErrorTranslator_424=HTTP (WebDAV) Failed Dependency: {0} +TransportErrorTranslator_425=HTTP Unordered Collection: {0} +TransportErrorTranslator_426=HTTP Upgrade Required: {0} +TransportErrorTranslator_449=HTTP Retry With Response: {0} +TransportErrorTranslator_450=HTTP Blocked By Parental Control: {0} +TransportErrorTranslator_500=HTTP Server ''Internal Error'': {0} +TransportErrorTranslator_501=HTTP Server ''Not Implemented'': {0} +TransportErrorTranslator_502=HTTP Server ''Bad Gateway'' : {0} +TransportErrorTranslator_503=HTTP Server ''Service Unavailable'': {0} +TransportErrorTranslator_504=HTTP Server ''Gateway Timeout'': {0} +TransportErrorTranslator_505=HTTP Server ''HTTP Version Not Supported'': {0} +TransportErrorTranslator_506=HTTP Server ''Variant Also Negotiates'': {0} +TransportErrorTranslator_507=HTTP (WebDAV) ''Insufficient Storage'': {0} +TransportErrorTranslator_508=HTTP Server ''Bandwidth Limit Exceeded'': {0} +TransportErrorTranslator_510=HTTP Server ''Not Extended'': {0} +TransportErrorTranslator_MalformedRemoteFileReference=Malformed reference to remote file: {0} +TransportErrorTranslator_UnableToConnectToRepository_0=Unable to connect to repository {0} +TransportErrorTranslator_UnknownErrorCode=HTTP Server Unknown HTTP Response Code ({0}):{1} +TransportErrorTranslator_UnknownHost=Unknown Host: {0} From 618846776f74f4393fdde0fdd45471b75969a81a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 16:00:27 +0000 Subject: [PATCH 3/4] Copy ECF source code into native transport bundle Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .../META-INF/MANIFEST.MF | 34 +- .../eclipse/ecf/core/AbstractContainer.java | 100 ++ .../core/AbstractContainerAdapterFactory.java | 56 + .../org/eclipse/ecf/core/BaseContainer.java | 136 +++ .../ContainerAuthenticationException.java | 39 + .../ecf/core/ContainerConnectException.java | 46 + .../ecf/core/ContainerCreateException.java | 44 + .../eclipse/ecf/core/ContainerFactory.java | 606 +++++++++++ .../ecf/core/ContainerTypeDescription.java | 289 +++++ .../src/org/eclipse/ecf/core/IContainer.java | 214 ++++ .../eclipse/ecf/core/IContainerFactory.java | 336 ++++++ .../eclipse/ecf/core/IContainerListener.java | 49 + .../eclipse/ecf/core/IContainerManager.java | 131 +++ .../ecf/core/IContainerManagerListener.java | 42 + .../eclipse/ecf/core/IReliableContainer.java | 35 + .../core/events/ContainerConnectedEvent.java | 55 + .../core/events/ContainerConnectingEvent.java | 62 ++ .../events/ContainerDisconnectedEvent.java | 68 ++ .../events/ContainerDisconnectingEvent.java | 55 + .../core/events/ContainerDisposeEvent.java | 43 + .../core/events/ContainerEjectedEvent.java | 55 + .../core/events/IContainerConnectedEvent.java | 27 + .../events/IContainerConnectingEvent.java | 34 + .../events/IContainerDisconnectedEvent.java | 28 + .../events/IContainerDisconnectingEvent.java | 28 + .../core/events/IContainerDisposeEvent.java | 20 + .../core/events/IContainerEjectedEvent.java | 37 + .../ecf/core/events/IContainerEvent.java | 28 + .../org/eclipse/ecf/core/identity/BaseID.java | 164 +++ .../org/eclipse/ecf/core/identity/GUID.java | 164 +++ .../src/org/eclipse/ecf/core/identity/ID.java | 66 ++ .../ecf/core/identity/IDCreateException.java | 39 + .../eclipse/ecf/core/identity/IDFactory.java | 306 ++++++ .../eclipse/ecf/core/identity/IIDFactory.java | 288 +++++ .../ecf/core/identity/IIdentifiable.java | 26 + .../ecf/core/identity/IResourceID.java | 34 + .../org/eclipse/ecf/core/identity/LongID.java | 108 ++ .../eclipse/ecf/core/identity/Namespace.java | 328 ++++++ .../core/identity/NamespacePermission.java | 55 + .../eclipse/ecf/core/identity/StringID.java | 144 +++ .../org/eclipse/ecf/core/identity/URIID.java | 131 +++ .../org/eclipse/ecf/core/identity/UuID.java | 114 ++ .../eclipse/ecf/core/jobs/JobsExecutor.java | 99 ++ .../provider/BaseContainerInstantiator.java | 244 +++++ ...aseRemoteServiceContainerInstantiator.java | 38 + .../provider/ContainerInstantiatorUtils.java | 136 +++ .../provider/ContainerIntentException.java | 46 + .../core/provider/IContainerInstantiator.java | 114 ++ .../IRemoteServiceContainerInstantiator.java | 85 ++ .../ecf/core/security/BooleanCallback.java | 112 ++ .../eclipse/ecf/core/security/Callback.java | 16 + .../ecf/core/security/CallbackHandler.java | 18 + .../core/security/ConnectContextFactory.java | 106 ++ .../core/security/ECFSSLContextFactory.java | 111 ++ .../ecf/core/security/IConnectContext.java | 33 + .../core/security/IConnectHandlerPolicy.java | 40 + .../security/IConnectInitiatorPolicy.java | 38 + .../ecf/core/security/IContainerPolicy.java | 20 + .../ecf/core/security/NameCallback.java | 116 ++ .../ecf/core/security/ObjectCallback.java | 36 + .../ecf/core/security/PassphraseCallback.java | 116 ++ .../ecf/core/security/PasswordCallback.java | 116 ++ .../ecf/core/security/SSLContextFactory.java | 44 + .../UnsupportedCallbackException.java | 64 ++ .../eclipse/ecf/core/start/ECFStartJob.java | 35 + .../org/eclipse/ecf/core/start/IECFStart.java | 30 + .../core/status/SerializableMultiStatus.java | 165 +++ .../ecf/core/status/SerializableStatus.java | 289 +++++ .../src/org/eclipse/ecf/core/user/IUser.java | 46 + .../src/org/eclipse/ecf/core/user/User.java | 111 ++ .../ecf/core/util/AbstractFactory.java | 37 + .../ecf/core/util/AdapterContainerFilter.java | 43 + .../ecf/core/util/AdapterManagerTracker.java | 43 + .../src/org/eclipse/ecf/core/util/Base64.java | 219 ++++ .../ecf/core/util/BundleClassResolver.java | 48 + .../eclipse/ecf/core/util/BundleStarter.java | 30 + .../util/ClassResolverObjectInputStream.java | 109 ++ .../core/util/ConnectedContainerFilter.java | 41 + .../core/util/ContainerFactoryTracker.java | 33 + .../core/util/ContainerManagerTracker.java | 33 + .../eclipse/ecf/core/util/ECFException.java | 57 + .../ecf/core/util/ECFRuntimeException.java | 87 ++ .../src/org/eclipse/ecf/core/util/Event.java | 21 + .../core/util/ExtensionRegistryRunnable.java | 74 ++ .../eclipse/ecf/core/util/IClassResolver.java | 24 + .../ecf/core/util/IContainerFilter.java | 33 + .../ecf/core/util/IDFactoryTracker.java | 38 + .../ecf/core/util/IEventProcessor.java | 32 + .../ecf/core/util/IExceptionHandler.java | 27 + .../org/eclipse/ecf/core/util/LogHelper.java | 58 + .../ecf/core/util/OSGIObjectInputStream.java | 446 ++++++++ .../ecf/core/util/OSGIObjectOutputStream.java | 446 ++++++++ .../core/util/OSGIObjectStreamConstants.java | 55 + .../eclipse/ecf/core/util/PlatformHelper.java | 109 ++ .../src/org/eclipse/ecf/core/util/Proxy.java | 149 +++ .../eclipse/ecf/core/util/ProxyAddress.java | 71 ++ .../src/org/eclipse/ecf/core/util/SerDTO.java | 79 ++ .../org/eclipse/ecf/core/util/SerVersion.java | 31 + .../eclipse/ecf/core/util/StringUtils.java | 310 ++++++ .../ecf/core/util/SystemLogService.java | 125 +++ .../src/org/eclipse/ecf/core/util/Trace.java | 538 ++++++++++ .../ecf/core/util/reflection/ClassUtil.java | 130 +++ .../BrowseFileTransferException.java | 70 ++ .../ecf/filetransfer/FileTransferInfo.java | 115 ++ .../ecf/filetransfer/FileTransferJob.java | 85 ++ .../filetransfer/IFileRangeSpecification.java | 74 ++ .../ecf/filetransfer/IFileTransfer.java | 97 ++ .../ecf/filetransfer/IFileTransferInfo.java | 64 ++ .../filetransfer/IFileTransferListener.java | 51 + .../filetransfer/IFileTransferPausable.java | 57 + .../IFileTransferRateControl.java | 51 + .../filetransfer/IFileTransferRunnable.java | 33 + .../filetransfer/IIncomingFileTransfer.java | 68 ++ .../IIncomingFileTransferRequestListener.java | 32 + .../filetransfer/IOutgoingFileTransfer.java | 29 + .../eclipse/ecf/filetransfer/IRemoteFile.java | 37 + .../filetransfer/IRemoteFileAttributes.java | 52 + .../ecf/filetransfer/IRemoteFileInfo.java | 95 ++ ...moteFileSystemBrowserContainerAdapter.java | 75 ++ .../IRemoteFileSystemListener.java | 49 + .../IRemoteFileSystemRequest.java | 40 + ...IRetrieveFileTransferContainerAdapter.java | 218 ++++ .../IRetrieveFileTransferOptions.java | 47 + .../ISendFileTransferContainerAdapter.java | 188 ++++ .../ISendFileTransferOptions.java | 22 + .../IncomingFileTransferException.java | 117 +++ ...nvalidFileRangeSpecificationException.java | 76 ++ .../RemoteFileSystemException.java | 62 ++ .../SendFileTransferException.java | 70 ++ .../filetransfer/UserCancelledException.java | 45 + .../IFileTransferConnectStartEvent.java | 95 ++ .../events/IFileTransferEvent.java | 22 + .../events/IFileTransferRequestEvent.java | 102 ++ .../events/IIncomingFileTransferEvent.java | 28 + ...IIncomingFileTransferReceiveDataEvent.java | 24 + ...IIncomingFileTransferReceiveDoneEvent.java | 39 + ...ncomingFileTransferReceivePausedEvent.java | 21 + ...comingFileTransferReceiveResumedEvent.java | 155 +++ ...IncomingFileTransferReceiveStartEvent.java | 143 +++ .../events/IOutgoingFileTransferEvent.java | 28 + .../IOutgoingFileTransferResponseEvent.java | 40 + .../IOutgoingFileTransferSendDataEvent.java | 24 + .../IOutgoingFileTransferSendDoneEvent.java | 25 + .../IOutgoingFileTransferSendPausedEvent.java | 21 + ...IOutgoingFileTransferSendResumedEvent.java | 22 + .../events/IRemoteFileSystemBrowseEvent.java | 41 + .../events/IRemoteFileSystemEvent.java | 27 + .../events/socket/ISocketClosedEvent.java | 37 + .../events/socket/ISocketConnectedEvent.java | 42 + .../events/socket/ISocketCreatedEvent.java | 30 + .../events/socket/ISocketEvent.java | 58 + .../events/socket/ISocketEventSource.java | 25 + .../events/socket/ISocketListener.java | 18 + .../INonconnectedSocketFactory.java | 22 + .../identity/FileCreateException.java | 46 + .../filetransfer/identity/FileIDFactory.java | 129 +++ .../ecf/filetransfer/identity/IFileID.java | 49 + .../filetransfer/identity/IFileIDFactory.java | 92 ++ .../service/IRemoteFileSystemBrowser.java | 23 + .../IRemoteFileSystemBrowserFactory.java | 29 + .../service/IRetrieveFileTransfer.java | 21 + .../service/IRetrieveFileTransferFactory.java | 29 + .../service/ISendFileTransfer.java | 21 + .../service/ISendFileTransferFactory.java | 30 + .../ecf/internal/core/ECFDebugOptions.java | 27 + .../eclipse/ecf/internal/core/ECFPlugin.java | 583 +++++++++++ .../ecf/internal/core/IDisposable.java | 16 + .../ecf/internal/core/identity/Activator.java | 315 ++++++ .../ecf/internal/filetransfer/Activator.java | 133 +++ .../FileTransferDebugOptions.java | 26 + .../ProxyURLStreamHandlerService.java | 89 ++ .../provider/filetransfer/Activator.java | 923 ++++++++++++++++ .../provider/filetransfer/DebugOptions.java | 26 + .../filetransfer/IURLConnectionModifier.java | 29 + .../provider/filetransfer/Messages.java | 81 ++ .../provider/filetransfer/messages.properties | 59 ++ .../IFileTransferProtocolToFactoryMapper.java | 230 ++++ .../browse/AbstractFileSystemBrowser.java | 267 +++++ .../browse/LocalFileSystemBrowser.java | 65 ++ .../filetransfer/browse/LocalRemoteFile.java | 120 +++ .../browse/LocalRemoteFileAttributes.java | 86 ++ ...MultiProtocolFileSystemBrowserAdapter.java | 112 ++ ...otocolFileSystemBrowserAdapterFactory.java | 47 + .../browse/URLFileSystemBrowser.java | 209 ++++ .../filetransfer/browse/URLRemoteFile.java | 135 +++ .../browse/URLRemoteFileAttributes.java | 77 ++ .../events/socket/AbstractSocketEvent.java | 68 ++ .../events/socket/AbstractSocketWrapper.java | 217 ++++ .../events/socket/SocketClosedEvent.java | 29 + .../events/socket/SocketConnectedEvent.java | 33 + .../events/socket/SocketCreatedEvent.java | 29 + .../events/socket/SocketEventCreateUtil.java | 75 ++ .../events/socket/SocketEventSource.java | 53 + .../filetransfer/identity/FileTransferID.java | 101 ++ .../identity/FileTransferNamespace.java | 102 ++ .../AbstractOutgoingFileTransfer.java | 468 +++++++++ ...ractUrlConnectionOutgoingFileTransfer.java | 146 +++ .../LocalFileOutgoingFileTransfer.java | 71 ++ .../MultiProtocolOutgoingAdapter.java | 165 +++ .../MultiProtocolOutgoingAdapterFactory.java | 47 + .../AbstractRetrieveFileTransfer.java | 991 ++++++++++++++++++ .../filetransfer/retrieve/HttpHelper.java | 41 + .../MultiProtocolRetrieveAdapter.java | 164 +++ .../MultiProtocolRetrieveAdapterFactory.java | 47 + .../UrlConnectionRetrieveFileTransfer.java | 574 ++++++++++ .../filetransfer/util/JREProxyHelper.java | 92 ++ .../filetransfer/util/PollingInputStream.java | 276 +++++ .../filetransfer/util/ProxySetupHelper.java | 105 ++ .../filetransfer/util/TimeoutInputStream.java | 378 +++++++ 209 files changed, 22165 insertions(+), 3 deletions(-) create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainerAdapterFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/BaseContainer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerAuthenticationException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerConnectException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerCreateException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerTypeDescription.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerListener.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManager.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManagerListener.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IReliableContainer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectingEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectingEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisposeEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerEjectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectingEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectingEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisposeEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEjectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/BaseID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/GUID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/ID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDCreateException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIDFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIdentifiable.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IResourceID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/LongID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/Namespace.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/NamespacePermission.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/StringID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/URIID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/UuID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/jobs/JobsExecutor.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseContainerInstantiator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseRemoteServiceContainerInstantiator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerInstantiatorUtils.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerIntentException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IContainerInstantiator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IRemoteServiceContainerInstantiator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/BooleanCallback.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/Callback.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/CallbackHandler.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ConnectContextFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ECFSSLContextFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectContext.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectHandlerPolicy.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectInitiatorPolicy.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IContainerPolicy.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/NameCallback.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ObjectCallback.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PassphraseCallback.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PasswordCallback.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/SSLContextFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/UnsupportedCallbackException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/ECFStartJob.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/IECFStart.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableMultiStatus.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableStatus.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/IUser.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/User.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AbstractFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterContainerFilter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterManagerTracker.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Base64.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleClassResolver.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleStarter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ClassResolverObjectInputStream.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ConnectedContainerFilter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerFactoryTracker.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerManagerTracker.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFRuntimeException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Event.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ExtensionRegistryRunnable.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IClassResolver.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IContainerFilter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IDFactoryTracker.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IEventProcessor.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IExceptionHandler.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/LogHelper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectInputStream.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectOutputStream.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectStreamConstants.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/PlatformHelper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Proxy.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ProxyAddress.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerDTO.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerVersion.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/StringUtils.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SystemLogService.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Trace.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/BrowseFileTransferException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferInfo.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferJob.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileRangeSpecification.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferInfo.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferListener.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferPausable.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRateControl.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRunnable.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransferRequestListener.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IOutgoingFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFile.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileAttributes.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileInfo.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemBrowserContainerAdapter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemListener.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemRequest.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferContainerAdapter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferOptions.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferContainerAdapter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferOptions.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IncomingFileTransferException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/InvalidFileRangeSpecificationException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/RemoteFileSystemException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/SendFileTransferException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/UserCancelledException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferConnectStartEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferRequestEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDataEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDoneEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceivePausedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveResumedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveStartEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferResponseEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDataEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDoneEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendPausedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendResumedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemBrowseEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketClosedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketConnectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketCreatedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEventSource.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketListener.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socketfactory/INonconnectedSocketFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileCreateException.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileIDFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileIDFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowser.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowserFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransferFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransferFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFDebugOptions.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFPlugin.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/IDisposable.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/identity/Activator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/Activator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/FileTransferDebugOptions.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/ProxyURLStreamHandlerService.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Activator.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/DebugOptions.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/IURLConnectionModifier.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Messages.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/messages.properties create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/IFileTransferProtocolToFactoryMapper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/AbstractFileSystemBrowser.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalFileSystemBrowser.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFile.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFileAttributes.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapterFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLFileSystemBrowser.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFile.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFileAttributes.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketWrapper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketClosedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketConnectedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketCreatedEvent.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventCreateUtil.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventSource.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferID.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferNamespace.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractOutgoingFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractUrlConnectionOutgoingFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/LocalFileOutgoingFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapterFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/AbstractRetrieveFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/HttpHelper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapter.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapterFactory.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/UrlConnectionRetrieveFileTransfer.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/JREProxyHelper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/PollingInputStream.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/ProxySetupHelper.java create mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/TimeoutInputStream.java diff --git a/bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF index dc35b20534..caf3b4ec3f 100644 --- a/bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.p2.transport.native/META-INF/MANIFEST.MF @@ -7,14 +7,42 @@ Bundle-RequiredExecutionEnvironment: JavaSE-17 Require-Bundle: org.eclipse.equinox.p2.core;bundle-version="2.0.100", org.eclipse.equinox.p2.repository;bundle-version="2.1.0", org.eclipse.equinox.common;bundle-version="3.6.0", - org.eclipse.core.jobs;bundle-version="3.5.100" + org.eclipse.core.jobs;bundle-version="3.5.100", + org.eclipse.equinox.registry;bundle-version="3.0.0";resolution:=optional Service-Component: OSGI-INF/nativeTransport.xml Bundle-Activator: org.eclipse.equinox.internal.p2.transport.ecf.Activator Bundle-ActivationPolicy: lazy -Export-Package: org.eclipse.equinox.internal.p2.transport.ecf;x-friends:="org.eclipse.equinox.p2.discovery.compatibility,org.eclipse.equinox.p2.installer" +Export-Package: org.eclipse.ecf.core;version="3.0.0", + org.eclipse.ecf.core.events;version="3.1.0", + org.eclipse.ecf.core.jobs;version="1.1.0", + org.eclipse.ecf.core.provider;version="3.3.0", + org.eclipse.ecf.core.security;version="3.2.0", + org.eclipse.ecf.core.start;version="3.1.0", + org.eclipse.ecf.core.status;version="1.1.0", + org.eclipse.ecf.core.user;version="3.1.0", + org.eclipse.ecf.core.util;version="3.6.0", + org.eclipse.ecf.core.util.reflection;version="2.3.0", + org.eclipse.ecf.filetransfer;version="5.0.0", + org.eclipse.ecf.filetransfer.events;version="5.0.0", + org.eclipse.ecf.filetransfer.events.socketfactory;version="5.0.0", + org.eclipse.ecf.filetransfer.identity;version="5.0.0", + org.eclipse.ecf.filetransfer.service;version="5.0.0", + org.eclipse.ecf.provider.filetransfer;version="3.2.0", + org.eclipse.ecf.provider.filetransfer.browse;version="3.2.0", + org.eclipse.ecf.provider.filetransfer.identity;version="3.2.0", + org.eclipse.ecf.provider.filetransfer.outgoing;version="3.2.0", + org.eclipse.ecf.provider.filetransfer.retrieve;version="3.2.0", + org.eclipse.ecf.provider.filetransfer.util;version="3.2.0", + org.eclipse.equinox.internal.p2.transport.ecf;x-friends:="org.eclipse.equinox.p2.discovery.compatibility,org.eclipse.equinox.p2.installer" Bundle-Vendor: %providerName Bundle-Localization: plugin -Import-Package: org.eclipse.osgi.util;version="1.1.0", +Import-Package: org.eclipse.core.net.proxy;resolution:=optional, + org.eclipse.core.runtime.jobs, + org.eclipse.equinox.concurrent.future;version="[1.0.0,2.0.0)";resolution:=optional, + org.eclipse.osgi.util;version="1.1.0", org.osgi.framework;version="1.6.0", + org.osgi.service.log;version="[1.3.0,2.0.0)", + org.osgi.service.url;version="[1.0.0,2.0.0)", org.osgi.util.tracker;version="1.5.0" Automatic-Module-Name: org.eclipse.equinox.p2.transport.native +DynamicImport-Package: * diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainer.java new file mode 100644 index 0000000000..21e06d2bbd --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainer.java @@ -0,0 +1,100 @@ +/**************************************************************************** + * Copyright (c) 2006 IBM, Inc and Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Chris Aniszczyk - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import java.util.*; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.core.events.ContainerDisposeEvent; +import org.eclipse.ecf.core.events.IContainerEvent; +import org.eclipse.ecf.core.security.*; +import org.eclipse.ecf.internal.core.ECFPlugin; + +/** + * Abstract implementation of IContainer. Provides implementations of listener + * methods that subsclasses may use to avoid having to implement them + * themselves. This class may be subclassed as needed. + * + */ +public abstract class AbstractContainer implements IContainer { + + private final List containerListeners = new ArrayList(5); + + public void addListener(IContainerListener l) { + synchronized (containerListeners) { + containerListeners.add(l); + } + } + + public void removeListener(IContainerListener l) { + synchronized (containerListeners) { + containerListeners.remove(l); + } + } + + public void dispose() { + fireContainerEvent(new ContainerDisposeEvent(getID())); + synchronized (containerListeners) { + containerListeners.clear(); + } + } + + /** + * Fires a container event + * + * @param event event + */ + protected void fireContainerEvent(IContainerEvent event) { + List toNotify = null; + // Copy array + synchronized (containerListeners) { + toNotify = new ArrayList(containerListeners); + } + // Notify all in toNotify + for (Iterator i = toNotify.iterator(); i.hasNext();) { + IContainerListener l = (IContainerListener) i.next(); + l.handleEvent(event); + } + } + + public T getAdapter(Class serviceType) { + if (serviceType == null) + return null; + if (serviceType.isInstance(this)) { + return serviceType.cast(this); + } + ECFPlugin plugin = ECFPlugin.getDefault(); + if (plugin == null) + return null; + IAdapterManager adapterManager = plugin.getAdapterManager(); + return (T) ((adapterManager == null) ? null : adapterManager.loadAdapter(this, serviceType.getName())); + } + + protected String getPasswordFromConnectContext(IConnectContext connectContext) throws ContainerConnectException { + String pw = null; + try { + Callback[] callbacks = new Callback[1]; + callbacks[0] = new ObjectCallback(); + if (connectContext != null) { + CallbackHandler handler = connectContext.getCallbackHandler(); + if (handler != null) { + handler.handle(callbacks); + } + } + ObjectCallback cb = (ObjectCallback) callbacks[0]; + pw = (String) cb.getObject(); + } catch (Exception e) { + throw new ContainerConnectException("Exception in CallbackHandler.handle()", e); //$NON-NLS-1$ + } + return pw; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainerAdapterFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainerAdapterFactory.java new file mode 100644 index 0000000000..d5b0f86c6e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/AbstractContainerAdapterFactory.java @@ -0,0 +1,56 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core; + +import org.eclipse.core.runtime.IAdapterFactory; + +/** + * Abstract container adapter factory. This is an abstract implementation of the + * {@link IAdapterFactory} interface. Subclasses may be created as appropriate. + */ +public abstract class AbstractContainerAdapterFactory implements IAdapterFactory { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, + * java.lang.Class) + */ + public T getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject == null || adapterType == null) + return null; + if (IContainer.class.isInstance(adaptableObject)) + return adapterType.cast(getContainerAdapter((IContainer) adaptableObject, adapterType)); + return null; + } + + /** + * Method called by implementation of {@link #getAdapter(Object, Class)} if the + * adaptableObject is an instance of {@link IContainer}. Subclasses should implement to + * return the proper container adapter object based upon the given adapterType. + * + * @param container the IContainer adaptable object provided to the adapter. Will not be null. + * @param adapterType the type (interface) of the adapter on the given container. Will not be null + * @return Object the container adapter instance. May be null. + */ + protected abstract Object getContainerAdapter(IContainer container, Class adapterType); + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList() + */ + public abstract Class[] getAdapterList(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/BaseContainer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/BaseContainer.java new file mode 100644 index 0000000000..81215d4138 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/BaseContainer.java @@ -0,0 +1,136 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.ecf.core.identity.*; +import org.eclipse.ecf.core.provider.BaseContainerInstantiator; +import org.eclipse.ecf.core.security.IConnectContext; + +/** + * Base implementation of IContainer. Subclasses may be created to fill out the + * behavior of this base implementation. Also, adapter factories may be created + * via adapterFactory extension point to allow adapters to be added to this + * BaseContainer implementation without the need to create a separate IContainer + * implementation class. + */ +public class BaseContainer extends AbstractContainer { + + public static class Instantiator extends BaseContainerInstantiator { + + /** + * @since 3.4 + */ + public static final String NAME = "ecf.base"; //$NON-NLS-1$ + + private static long nextBaseContainerID = 0L; + + public IContainer createInstance(ContainerTypeDescription description, Object[] parameters) throws ContainerCreateException { + try { + if (parameters != null && parameters.length > 0) { + if (parameters[0] instanceof ID) + return new BaseContainer((ID) parameters[0]); + if (parameters[0] instanceof String) + return new BaseContainer(IDFactory.getDefault().createStringID((String) parameters[0])); + } + } catch (IDCreateException e) { + throw new ContainerCreateException("Could not create ID for basecontainer"); //$NON-NLS-1$ + } + return new BaseContainer(nextBaseContainerID++); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.provider.IContainerInstantiator#getSupportedAdapterTypes(org.eclipse.ecf.core.ContainerTypeDescription) + */ + public String[] getSupportedAdapterTypes(ContainerTypeDescription description) { + return getInterfacesAndAdaptersForClass(BaseContainer.class); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.provider.BaseContainerInstantiator#getSupportedParameterTypes(org.eclipse.ecf.core.ContainerTypeDescription) + */ + public Class[][] getSupportedParameterTypes(ContainerTypeDescription description) { + return new Class[][] { {}, {ID.class}, {String.class}}; + } + + } + + private ID id = null; + + protected BaseContainer(long idl) throws ContainerCreateException { + try { + this.id = IDFactory.getDefault().createLongID(idl); + } catch (IDCreateException e) { + throw new ContainerCreateException("Could not create ID for basecontainer", e); //$NON-NLS-1$ + } + } + + protected BaseContainer(ID id) { + Assert.isNotNull(id); + this.id = id; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainer#connect(org.eclipse.ecf.core.identity.ID, + * org.eclipse.ecf.core.security.IConnectContext) + */ + public void connect(ID targetID, IConnectContext connectContext) throws ContainerConnectException { + throw new ContainerConnectException("Connect not supported"); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainer#disconnect() + */ + public void disconnect() { + // Nothing to disconnect + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainer#getConnectNamespace() + */ + public Namespace getConnectNamespace() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainer#getConnectedID() + */ + public ID getConnectedID() { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.IIdentifiable#getID() + */ + public ID getID() { + return id; + } + + public String toString() { + StringBuffer sb = new StringBuffer("BaseContainer["); //$NON-NLS-1$ + sb.append("id=").append(getID()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + return sb.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerAuthenticationException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerAuthenticationException.java new file mode 100644 index 0000000000..8563a6a8d4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerAuthenticationException.java @@ -0,0 +1,39 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +/** + * Exception class to be thrown upon authentication failure during connect + * + * @see IContainer#connect(org.eclipse.ecf.core.identity.ID, + * org.eclipse.ecf.core.security.IConnectContext) + */ +public class ContainerAuthenticationException extends ContainerConnectException { + private static final long serialVersionUID = 7038962779623213444L; + + public ContainerAuthenticationException() { + super(); + } + + public ContainerAuthenticationException(String message) { + super(message); + } + + public ContainerAuthenticationException(Throwable cause) { + super(cause); + } + + public ContainerAuthenticationException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerConnectException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerConnectException.java new file mode 100644 index 0000000000..230bfe09be --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerConnectException.java @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * Exception class to be thrown upon connection failure. + * + * @see IContainer#connect(org.eclipse.ecf.core.identity.ID, + * org.eclipse.ecf.core.security.IConnectContext) + * + */ +public class ContainerConnectException extends ECFException { + private static final long serialVersionUID = 4078658849424746859L; + + public ContainerConnectException() { + super(); + } + + public ContainerConnectException(String message) { + super(message); + } + + public ContainerConnectException(Throwable cause) { + super(cause); + } + + public ContainerConnectException(String message, Throwable cause) { + super(message, cause); + } + + public ContainerConnectException(IStatus status) { + super(status); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerCreateException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerCreateException.java new file mode 100644 index 0000000000..13c1a6e5b9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerCreateException.java @@ -0,0 +1,44 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * Exception thrown during container creation + * + * @see ContainerFactory#createContainer(ContainerTypeDescription, Object[]) + */ +public class ContainerCreateException extends ECFException { + private static final long serialVersionUID = -6979687717421003065L; + + public ContainerCreateException(IStatus status) { + super(status); + } + + public ContainerCreateException() { + super(); + } + + public ContainerCreateException(String message) { + super(message); + } + + public ContainerCreateException(Throwable cause) { + super(cause); + } + + public ContainerCreateException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerFactory.java new file mode 100644 index 0000000000..68f18cc862 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerFactory.java @@ -0,0 +1,606 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import java.util.*; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.core.provider.IContainerInstantiator; +import org.eclipse.ecf.core.util.Trace; +import org.eclipse.ecf.internal.core.*; + +/** + * Factory for creating {@link IContainer} instances. This class provides ECF + * clients an entry point to constructing {@link IContainer} instances.
+ *
+ * Here is an example use of the ContainerFactory to construct an instance of + * the 'standalone' container (has no connection to other containers):
+ *
+ * + * IContainer container =
+ * ContainerFactory.getDefault().createContainer("ecf.generic.client"); + *

+ * ...further use of container here... + *
For more details on the creation + * and lifecycle of IContainer instances created via this factory see + * {@link IContainer}. + * + * @see IContainer + * @see IContainerFactory + * @since 3.1 + */ +public class ContainerFactory implements IContainerFactory, IContainerManager { + + public static final String BASE_CONTAINER_NAME = "ecf.base"; //$NON-NLS-1$ + + static final Map containerdescriptions = new HashMap(); + + static final Map containers = new HashMap(); + + static final List managerListeners = new ArrayList(); + + private static IContainerFactory instance = null; + + private volatile static boolean init = false; + + static { + instance = new ContainerFactory(); + } + + class ContainerEntry { + private final IContainer container; + private final ContainerTypeDescription typeDescription; + + public ContainerEntry(IContainer container, ContainerTypeDescription typeDescription) { + this.container = container; + this.typeDescription = typeDescription; + } + + public IContainer getContainer() { + return this.container; + } + + public ContainerTypeDescription getContainerTypeDescription() { + return this.typeDescription; + } + } + + public synchronized static IContainerFactory getDefault() { + if (init == false) { + // first mark the extension initalized because it initializeExtensions() + // eventually calls this method again + init = true; + ECFPlugin.getDefault().initializeExtensions(); + } + return instance; + } + + protected ContainerFactory() { + ECFPlugin.getDefault().addDisposable(new IDisposable() { + public void dispose() { + synchronized (containers) { + for (Iterator i = containers.keySet().iterator(); i.hasNext();) { + ContainerEntry entry = (ContainerEntry) containers.get(i.next()); + if (entry != null) { + IContainer c = entry.getContainer(); + try { + c.dispose(); + } catch (Throwable e) { + // Log exception + ECFPlugin.getDefault().log(new Status(IStatus.ERROR, ECFPlugin.getDefault().getBundle().getSymbolicName(), IStatus.ERROR, "container dispose error", e)); //$NON-NLS-1$ + Trace.catching(ECFPlugin.PLUGIN_ID, ECFDebugOptions.EXCEPTIONS_CATCHING, ContainerFactory.class, "doDispose", e); //$NON-NLS-1$ + } + } + } + containers.clear(); + } + containerdescriptions.clear(); + managerListeners.clear(); + } + }); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#addDescription(org.eclipse.ecf.core.ContainerTypeDescription) + */ + public ContainerTypeDescription addDescription(ContainerTypeDescription containerTypeDescription) { + return addDescription0(containerTypeDescription); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#getDescriptions() + */ + public List getDescriptions() { + return getDescriptions0(); + } + + protected List getDescriptions0() { + synchronized (containerdescriptions) { + return new ArrayList(containerdescriptions.values()); + } + } + + protected ContainerTypeDescription addDescription0(ContainerTypeDescription containerTypeDescription) { + if (containerTypeDescription == null) + return null; + synchronized (containerdescriptions) { + return (ContainerTypeDescription) containerdescriptions.put(containerTypeDescription.getName(), containerTypeDescription); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#containsDescription(org.eclipse.ecf.core.ContainerTypeDescription) + */ + public boolean containsDescription(ContainerTypeDescription containerTypeDescription) { + return containsDescription0(containerTypeDescription); + } + + protected boolean containsDescription0(ContainerTypeDescription containerTypeDescription) { + if (containerTypeDescription == null) + return false; + synchronized (containerdescriptions) { + return containerdescriptions.containsKey(containerTypeDescription.getName()); + } + } + + protected ContainerTypeDescription getDescription0(ContainerTypeDescription containerTypeDescription) { + if (containerTypeDescription == null) + return null; + synchronized (containerdescriptions) { + return (ContainerTypeDescription) containerdescriptions.get(containerTypeDescription.getName()); + } + } + + protected ContainerTypeDescription getDescription0(String containerTypeDescriptionName) { + if (containerTypeDescriptionName == null) + return null; + synchronized (containerdescriptions) { + return (ContainerTypeDescription) containerdescriptions.get(containerTypeDescriptionName); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#getDescriptionByName(java.lang.String) + */ + public ContainerTypeDescription getDescriptionByName(String containerTypeDescriptionName) { + return getDescription0(containerTypeDescriptionName); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#removeDescription(org.eclipse.ecf.core.ContainerTypeDescription) + */ + public ContainerTypeDescription removeDescription(ContainerTypeDescription containerTypeDescription) { + return removeDescription0(containerTypeDescription); + + } + + protected ContainerTypeDescription removeDescription0(ContainerTypeDescription containerTypeDescription) { + if (containerTypeDescription == null) + return null; + synchronized (containerdescriptions) { + return (ContainerTypeDescription) containerdescriptions.remove(containerTypeDescription.getName()); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#getDescriptionsForContainerAdapter(java.lang.Class) + */ + public ContainerTypeDescription[] getDescriptionsForContainerAdapter(Class containerAdapter) { + if (containerAdapter == null) + throw new NullPointerException("containerAdapter cannot be null"); //$NON-NLS-1$ + List result = new ArrayList(); + List descriptions = getDescriptions(); + for (Iterator i = descriptions.iterator(); i.hasNext();) { + ContainerTypeDescription description = (ContainerTypeDescription) i.next(); + String[] supportedAdapters = description.getSupportedAdapterTypes(); + if (supportedAdapters != null) { + for (int j = 0; j < supportedAdapters.length; j++) { + if (supportedAdapters[j].equals(containerAdapter.getName())) + result.add(description); + } + } + } + return (ContainerTypeDescription[]) result.toArray(new ContainerTypeDescription[] {}); + } + + protected void throwContainerCreateException(String message, Throwable cause, String method) throws ContainerCreateException { + ContainerCreateException except = (cause == null) ? new ContainerCreateException(message) : new ContainerCreateException(message, cause); + Trace.throwing(ECFPlugin.PLUGIN_ID, ECFDebugOptions.EXCEPTIONS_THROWING, ContainerFactory.class, method, except); + throw except; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#createContainer() + */ + public IContainer createContainer() throws ContainerCreateException { + return createContainer(BASE_CONTAINER_NAME); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(org.eclipse.ecf.core.identity.ID) + */ + public IContainer createContainer(ID containerID) throws ContainerCreateException { + if (containerID == null) + return createContainer(); + return createContainer(BASE_CONTAINER_NAME, new Object[] {containerID}); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(org.eclipse.ecf.core.ContainerTypeDescription) + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription) throws ContainerCreateException { + return createContainer(containerTypeDescription, (Object[]) null); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(java.lang.String) + */ + public IContainer createContainer(String containerTypeDescriptionName) throws ContainerCreateException { + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), (Object[]) null); + } + + private ContainerTypeDescription getDescriptionByNameWithException(String containerTypeDescriptionName) throws ContainerCreateException { + ContainerTypeDescription typeDescription = getDescriptionByName(containerTypeDescriptionName); + if (typeDescription == null) + throw new ContainerCreateException("Container type description with name=" + containerTypeDescriptionName + " not found. This may indicate that the desired provider is not available or not startable within runtime."); //$NON-NLS-1$ //$NON-NLS-2$ + return typeDescription; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(org.eclipse.ecf.core.ContainerTypeDescription, + * java.lang.Object[]) + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, Object[] parameters) throws ContainerCreateException { + String method = "createContainer"; //$NON-NLS-1$ + Trace.entering(ECFPlugin.PLUGIN_ID, ECFDebugOptions.METHODS_ENTERING, ContainerFactory.class, method, new Object[] {containerTypeDescription, Trace.getArgumentsString(parameters)}); + if (containerTypeDescription == null) + throwContainerCreateException("ContainerTypeDescription cannot be null", null, method); //$NON-NLS-1$ + ContainerTypeDescription cd = getDescription0(containerTypeDescription); + if (cd == null) + throwContainerCreateException("ContainerTypeDescription '" //$NON-NLS-1$ + + containerTypeDescription.getName() + "' not found", null, method); //$NON-NLS-1$ + IContainerInstantiator instantiator = null; + try { + instantiator = cd.getInstantiator(); + } catch (Exception e) { + throwContainerCreateException("createContainer cannot get IContainerInstantiator for description : " //$NON-NLS-1$ + + containerTypeDescription, e, method); + } + // Ask instantiator to actually create instance + IContainer container = instantiator.createInstance(containerTypeDescription, parameters); + if (container == null) + throwContainerCreateException("Instantiator returned null for '" //$NON-NLS-1$ + + cd.getName() + "'", null, method); //$NON-NLS-1$ + // Add to containers map if container.getID() provides a valid value. + ID containerID = container.getID(); + if (containerID != null) + addContainer(container, cd); + Trace.exiting(ECFPlugin.PLUGIN_ID, ECFDebugOptions.METHODS_EXITING, ContainerFactory.class, method, container); + return container; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(java.lang.String, + * java.lang.Object[]) + */ + public IContainer createContainer(String containerTypeDescriptionName, Object[] parameters) throws ContainerCreateException { + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), parameters); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(org.eclipse.ecf.core.ContainerTypeDescription, org.eclipse.ecf.core.identity.ID, java.lang.Object[]) + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, ID containerID, Object[] parameters) throws ContainerCreateException { + if (containerID == null) + return createContainer(containerTypeDescription, parameters); + Object[] params = (parameters == null || parameters.length == 0) ? new Object[1] : new Object[parameters.length + 1]; + params[0] = containerID; + if (parameters != null && parameters.length != 0) + System.arraycopy(parameters, 0, params, 1, parameters.length); + return createContainer(containerTypeDescription, params); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(java.lang.String, org.eclipse.ecf.core.identity.ID, java.lang.Object[]) + */ + public IContainer createContainer(String containerTypeDescriptionName, ID containerID, Object[] parameters) throws ContainerCreateException { + if (containerID == null) + return createContainer(containerTypeDescriptionName, parameters); + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), containerID, parameters); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(org.eclipse.ecf.core.ContainerTypeDescription, org.eclipse.ecf.core.identity.ID) + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, ID containerID) throws ContainerCreateException { + if (containerID == null) + return createContainer(containerTypeDescription); + return createContainer(containerTypeDescription, new Object[] {containerID}); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerFactory#createContainer(java.lang.String, org.eclipse.ecf.core.identity.ID) + */ + public IContainer createContainer(String containerTypeDescriptionName, ID containerID) throws ContainerCreateException { + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), new Object[] {containerID}); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, String containerId) throws ContainerCreateException { + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), containerId); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, String containerId, Object[] parameters) throws ContainerCreateException { + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), containerId, parameters); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, String containerId) throws ContainerCreateException { + return createContainer(containerTypeDescription, containerId, (Object[]) null); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, String containerId, Object[] parameters) throws ContainerCreateException { + if (containerId == null) + return createContainer(containerTypeDescription, parameters); + Object[] params = (parameters == null || parameters.length == 0) ? new Object[1] : new Object[parameters.length + 1]; + params[0] = containerId; + if (parameters != null && parameters.length != 0) + System.arraycopy(parameters, 0, params, 1, parameters.length); + return createContainer(containerTypeDescription, params); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerManager#getAllContainers() + */ + public IContainer[] getAllContainers() { + List containerValues = new ArrayList(); + synchronized (containers) { + Collection containerEntrys = containers.values(); + for (Iterator i = containerEntrys.iterator(); i.hasNext();) { + ContainerEntry entry = (ContainerEntry) i.next(); + containerValues.add(entry.getContainer()); + } + } + return (IContainer[]) containerValues.toArray(new IContainer[] {}); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerManager#getContainer(org.eclipse.ecf.core.identity.ID) + */ + public IContainer getContainer(ID containerID) { + if (containerID == null) + return null; + synchronized (containers) { + ContainerEntry entry = (ContainerEntry) containers.get(containerID); + if (entry == null) + return null; + return entry.getContainer(); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerManager#hasContainer(org.eclipse.ecf.core.identity.ID) + */ + public boolean hasContainer(ID containerID) { + Assert.isNotNull(containerID); + synchronized (containers) { + return containers.containsKey(containerID); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerManager#addListener(org.eclipse.ecf.core.IContainerManagerListener) + */ + public boolean addListener(IContainerManagerListener listener) { + Assert.isNotNull(listener); + synchronized (managerListeners) { + return managerListeners.add(listener); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.IContainerManager#removeListener(org.eclipse.ecf.core.IContainerManagerListener) + */ + public boolean removeListener(IContainerManagerListener listener) { + Assert.isNotNull(listener); + synchronized (managerListeners) { + return managerListeners.remove(listener); + } + } + + public IContainer addContainer(IContainer container, ContainerTypeDescription typeDescription) { + Assert.isNotNull(container); + Assert.isNotNull(typeDescription); + ID containerID = container.getID(); + Assert.isNotNull(containerID, "Container ID cannot be null"); //$NON-NLS-1$ + ContainerEntry result = null; + synchronized (containers) { + result = (ContainerEntry) containers.put(containerID, new ContainerEntry(container, typeDescription)); + } + if (result == null) + fireContainerAdded(container); + return container; + } + + /** + * @param result + */ + private void fireContainerAdded(IContainer result) { + List toNotify = null; + synchronized (managerListeners) { + toNotify = new ArrayList(managerListeners); + } + for (Iterator i = toNotify.iterator(); i.hasNext();) { + IContainerManagerListener cml = (IContainerManagerListener) i.next(); + cml.containerAdded(result); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IContainerManager#removeContainer(org.eclipse.ecf.core.IContainer) + */ + public IContainer removeContainer(IContainer container) { + Assert.isNotNull(container); + ID containerID = container.getID(); + if (containerID == null) + return null; + return removeContainer(containerID); + } + + public IContainer removeContainer(ID containerID) { + Assert.isNotNull(containerID); + ContainerEntry result = null; + synchronized (containers) { + result = (ContainerEntry) containers.remove(containerID); + } + IContainer resultContainer = null; + if (result != null) { + resultContainer = result.getContainer(); + fireContainerRemoved(resultContainer); + } + return resultContainer; + } + + /** + * @param result + */ + private void fireContainerRemoved(IContainer result) { + List toNotify = null; + synchronized (managerListeners) { + toNotify = new ArrayList(managerListeners); + } + for (Iterator i = toNotify.iterator(); i.hasNext();) { + IContainerManagerListener cml = (IContainerManagerListener) i.next(); + cml.containerRemoved(result); + } + } + + public ContainerTypeDescription getContainerTypeDescription(ID containerID) { + if (containerID == null) + return null; + synchronized (containers) { + ContainerEntry entry = (ContainerEntry) containers.get(containerID); + if (entry == null) + return null; + return entry.getContainerTypeDescription(); + } + } + + public IContainerFactory getContainerFactory() { + return this; + } + + public void removeAllContainers() { + synchronized (containers) { + for (Iterator i = containers.keySet().iterator(); i.hasNext();) { + ID key = (ID) i.next(); + ContainerEntry entry = (ContainerEntry) containers.get(key); + i.remove(); + fireContainerRemoved(entry.getContainer()); + } + } + } + + /** + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, ID containerID, Map parameters) throws ContainerCreateException { + if (containerID == null) + return createContainer(containerTypeDescription, parameters); + if (parameters == null) + return createContainer(containerTypeDescription, containerID); + return createContainer(containerTypeDescription, new Object[] {containerID, parameters}); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, String containerId, Map parameters) throws ContainerCreateException { + if (containerId == null) + return createContainer(containerTypeDescription, parameters); + if (parameters == null) + return createContainer(containerTypeDescription, containerId); + return createContainer(containerTypeDescription, new Object[] {containerId, parameters}); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, ID containerID, Map parameters) throws ContainerCreateException { + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), containerID, parameters); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, String containerId, Map parameters) throws ContainerCreateException { + return createContainer(getDescriptionByNameWithException(containerTypeDescriptionName), containerId, parameters); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, Map parameters) throws ContainerCreateException { + if (parameters == null) + return createContainer(containerTypeDescription); + return createContainer(containerTypeDescription, new Object[] {parameters}); + } + + /** + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, Map parameters) throws ContainerCreateException { + if (parameters == null) + return createContainer(containerTypeDescriptionName); + return createContainer(containerTypeDescriptionName, new Object[] {parameters}); + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerTypeDescription.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerTypeDescription.java new file mode 100644 index 0000000000..fb7d278dd8 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/ContainerTypeDescription.java @@ -0,0 +1,289 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.core.provider.IContainerInstantiator; +import org.eclipse.ecf.core.provider.IRemoteServiceContainerInstantiator; +import org.eclipse.ecf.core.util.Trace; +import org.eclipse.ecf.internal.core.ECFDebugOptions; +import org.eclipse.ecf.internal.core.ECFPlugin; + +/** + * Description of an {@link IContainer} type. Instances of this class are used to represent {@link IContainerInstantiator}s + * in the {@link ContainerFactory} + * + * @see ContainerFactory IContainerInstantiator + */ +public class ContainerTypeDescription { + + protected String name = null; + + protected String instantiatorClass = null; + + protected IContainerInstantiator instantiator = null; + + protected String description = null; + + protected int hashCode = 0; + + protected boolean server; + + protected boolean hidden; + + public ContainerTypeDescription(String name, String instantiatorClass, String description) { + this(name, instantiatorClass, description, false, false); + } + + public ContainerTypeDescription(String name, String instantiatorClass, String description, boolean server, boolean hidden) { + Assert.isNotNull(name, "ContainerTypeDescription name cannot be null"); //$NON-NLS-1$ + this.name = name; + this.hashCode = name.hashCode(); + Assert.isNotNull(instantiatorClass, "ContainerTypeDescription instantiatorClass cannot be null"); //$NON-NLS-1$ + this.instantiatorClass = instantiatorClass; + this.description = description; + this.server = server; + this.hidden = hidden; + } + + /** + * @param name name + * @param instantiator instantiator + * @since 3.4 + */ + public ContainerTypeDescription(String name, IContainerInstantiator instantiator) { + this(name, instantiator, null); + } + + public ContainerTypeDescription(String name, IContainerInstantiator instantiator, String description) { + this(name, instantiator, description, false, false); + } + + public ContainerTypeDescription(String name, IContainerInstantiator inst, String desc, boolean server, boolean hidden) { + Assert.isNotNull(name, "ContainerTypeDescription name cannot be null"); //$NON-NLS-1$ + this.name = name; + this.hashCode = name.hashCode(); + Assert.isNotNull(inst, "ContainerTypeDescription instantiator instance cannot be null"); //$NON-NLS-1$ + this.instantiator = inst; + this.description = desc; + this.server = server; + this.hidden = hidden; + } + + /** + * Get ContainerTypeDescription name + * + * @return String name for the ContainerTypeDescription. Will not be null. + */ + public String getName() { + return name; + } + + public boolean equals(Object other) { + if (!(other instanceof ContainerTypeDescription)) + return false; + ContainerTypeDescription scd = (ContainerTypeDescription) other; + return scd.name.equals(name); + } + + public int hashCode() { + return hashCode; + } + + public String toString() { + StringBuffer b = new StringBuffer("ContainerTypeDescription["); //$NON-NLS-1$ + b.append("name=").append(name).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + if (instantiator == null) + b.append("instantiatorClass=").append(instantiatorClass) //$NON-NLS-1$ + .append(";"); //$NON-NLS-1$ + else + b.append("instantiator=").append(instantiator).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + b.append("desc=").append(description).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + return b.toString(); + } + + protected IContainerInstantiator getInstantiator() throws ClassNotFoundException, InstantiationException, IllegalAccessException { + synchronized (this) { + if (instantiator == null) + initializeInstantiator(); + return instantiator; + } + } + + private void initializeInstantiator() throws ClassNotFoundException, InstantiationException, IllegalAccessException { + // Load instantiator class + Class clazz = Class.forName(instantiatorClass); + // Make new instance + try { + instantiator = (IContainerInstantiator) clazz.getDeclaredConstructor().newInstance(); + } catch (InvocationTargetException e) { + throw new ClassNotFoundException("Invocation target exception accessing null constructor for class=" + clazz, e); //$NON-NLS-1$ + } catch (NoSuchMethodException e) { + throw new ClassNotFoundException("No null constructor found on class=" + clazz, e); //$NON-NLS-1$ + } catch (SecurityException e) { + throw new ClassNotFoundException("Security exception accessing null constructor for class=" + clazz, e); //$NON-NLS-1$ + } + } + + /** + * Get the String description associated with this ContainerTypeDescription + * instance + * + * @return String description. May be null. + */ + public String getDescription() { + return description; + } + + public boolean isServer() { + return server; + } + + public boolean isHidden() { + return hidden; + } + + /** + * Get array of supported adapters for this container type description. The + * returned array entries will be the fully qualified names of the adapter + * classes. + * + * Note that the returned types do not guarantee that a subsequent call to + * {@link IContainer#getAdapter(Class)} with the same type name as a + * returned value will return a non-null result. In other words, even if the + * class name is in the returned array, subsequent calls to + * {@link IContainer#getAdapter(Class)} may still return null. + * + * @return String[] of supported adapters. The entries in the returned array + * will be the fully qualified class names of adapters supported by + * the given description. An empty string array (String[0]) will be + * returned if no adapters are supported. + */ + public String[] getSupportedAdapterTypes() { + String[] result = new String[0]; + try { + String[] r = getInstantiator().getSupportedAdapterTypes(this); + if (r != null) + result = r; + } catch (Exception e) { + traceAndLogException(IStatus.ERROR, "getSupportedAdapterTypes", e); //$NON-NLS-1$ + } + List resultList = new ArrayList(); + resultList.addAll(Arrays.asList(result)); + if (!resultList.contains(IContainer.class.getName())) + resultList.add(IContainer.class.getName()); + return (String[]) resultList.toArray(new String[] {}); + } + + protected void traceAndLogException(int code, String method, Throwable e) { + Trace.catching(ECFPlugin.PLUGIN_ID, ECFDebugOptions.EXCEPTIONS_CATCHING, this.getClass(), method, e); + ECFPlugin.getDefault().log(new Status(IStatus.ERROR, ECFPlugin.PLUGIN_ID, code, method, e)); + } + + /** + * Get array of parameter types for this ContainerTypeDescription. Each of + * the rows of the returned array specifies a Class[] of parameter types. + * These parameter types correspond to the types of Objects that can be + * passed into the second parameter of + * {@link IContainerInstantiator#createInstance(ContainerTypeDescription, Object[])}. + * For example, if this method returns a Class [] = {{ String.class, + * String.class }, { String.class }} this indicates that a call to + * createInstance(description,new String[] { "hello", "there" }) and a call + * to createInstance(description,new String[] { "hello" }) will be + * understood by the underlying provider implementation. + * + * @return Class[][] array of Class arrays. Each row corresponds to a + * Class[] that describes the types of Objects for second parameter + * to + * {@link IContainerInstantiator#createInstance(ContainerTypeDescription, Object[])}. + * If no parameter types are understood as arguments, a Class[0][0] + * array will be returned + */ + public Class[][] getSupportedParameterTypes() { + Class[][] result = {{}}; + try { + Class[][] r = getInstantiator().getSupportedParameterTypes(this); + if (r != null) + result = r; + } catch (Exception e) { + traceAndLogException(IStatus.ERROR, "getSupportedParameterTypes", e); //$NON-NLS-1$ + } + return result; + } + + /** + * @return String[] of container's intents. + * + * @since 3.0 + */ + public String[] getSupportedIntents() { + try { + IContainerInstantiator ci = getInstantiator(); + return (ci instanceof IRemoteServiceContainerInstantiator) ? ((IRemoteServiceContainerInstantiator) ci).getSupportedIntents(this) : null; + } catch (Exception e) { + traceAndLogException(IStatus.ERROR, "getSupportedIntents", e); //$NON-NLS-1$ + return null; + } + } + + /** + * @return String[] supported configs + * @since 3.1 + */ + public String[] getSupportedConfigs() { + try { + IContainerInstantiator ci = getInstantiator(); + return (ci instanceof IRemoteServiceContainerInstantiator) ? ((IRemoteServiceContainerInstantiator) ci).getSupportedConfigs(this) : null; + } catch (Exception e) { + traceAndLogException(IStatus.ERROR, "getSupportedConfigs", e); //$NON-NLS-1$ + return null; + } + } + + /** + * @param exporterSupportedConfigs exporter supported configs + * @return String[] imported configs + * @since 3.1 + */ + public String[] getImportedConfigs(String[] exporterSupportedConfigs) { + if (exporterSupportedConfigs == null) + return null; + try { + IContainerInstantiator ci = getInstantiator(); + return (ci instanceof IRemoteServiceContainerInstantiator) ? ((IRemoteServiceContainerInstantiator) ci).getImportedConfigs(this, exporterSupportedConfigs) : null; + } catch (Exception e) { + traceAndLogException(IStatus.ERROR, "getImportedConfigs", e); //$NON-NLS-1$ + return null; + } + } + + /** + * @param importedConfigs imported configs + * @param exportedProperties exported properties + * @return Dictionary dictionary of properties for imported configs + * @since 3.1 + */ + public Dictionary getPropertiesForImportedConfigs(String[] importedConfigs, Dictionary exportedProperties) { + if (importedConfigs == null) + return null; + try { + IContainerInstantiator ci = getInstantiator(); + return (ci instanceof IRemoteServiceContainerInstantiator) ? ((IRemoteServiceContainerInstantiator) ci).getPropertiesForImportedConfigs(this, importedConfigs, exportedProperties) : null; + } catch (Exception e) { + traceAndLogException(IStatus.ERROR, "getPropertiesForImportedConfigs", e); //$NON-NLS-1$ + return null; + } + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainer.java new file mode 100644 index 0000000000..5b5618a465 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainer.java @@ -0,0 +1,214 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.core.identity.*; +import org.eclipse.ecf.core.security.IConnectContext; + +/** + * Contract for ECF communications container
+ *
+ * IContainer instances are used by clients to define a context for + * communications.
+ *
+ * The typical life cycle of an ECF communications container is: + *
    + *
  1. Create an IContainer instance via a {@link ContainerFactory}
  2. + *
  3. Optional: Setup client-specific protocol adapters for + * communicating via specific protocols
  4. + *
  5. Connect the container to a remote process or group
  6. + *
  7. Engage in communication via protocol adapters
  8. + *
  9. Disconnect
  10. + *
+ * For example, to create and connect an ECF "generic client": + * + *
+ * // Create container instance via factory
+ * IContainer container = ContainerFactory.getDefault().createContainer(
+ * 		"ecf.generic.client");
+ * 
+ * // Get presence protocol adapter
+ * IPresenceContainerAdapter presence = (IPresenceContainerAdapter) container
+ * 		.getAdapter(IPresenceContainerAdapter.class);
+ * // ... setup presence listeners and local input here using presence
+ * 
+ * // Connect
+ * container.connect(target, targetConnectContext);
+ * 
+ * // Engage in appropriate communications here using protocol adapter(s)
+ * // Manage protocol adapters as needed when finished
+ * 
+ * // Disconnect
+ * container.disconnect();
+ * 
+ * + */ +public interface IContainer extends IAdaptable, IIdentifiable { + + /** + * Connect to a target remote process or process group. The target + * identified by the first parameter (targetID) is connected the + * implementation class. If authentication information is required, the + * required information is given via via the second parameter + * (connectContext). + * + * Callers note that depending upon the provider implementation this method + * may block. It is suggested that callers use a separate thread to call + * this method. + * + * This method provides an implementation independent way for container + * implementations to connect, authenticate, and communicate with a remote + * service or group of services. Providers are responsible for implementing + * this operation in a way appropriate to the given remote service (or + * group) via expected protocol. + * + * @param targetID + * the ID of the remote server or group to connect to. See + * {@link #getConnectNamespace()} for a explanation of the + * constraints upon this parameter. + * @param connectContext + * any required context to allow this container to authenticate. + * May be null if underlying provider does not + * have any authentication requirements for connection. + * @exception ContainerConnectException + * thrown if communication cannot be established with remote + * service. Causes can include network connection failure, + * authentication failure, server error, or if container is + * already connected. + */ + public void connect(ID targetID, IConnectContext connectContext) throws ContainerConnectException; + + /** + * Get the target ID that this container instance has connected to. Returns + * null if not connected. + * + * @return ID of the target we are connected to. Returns null + * if container not connected. + */ + public ID getConnectedID(); + + /** + * Get the Namespace for creating a targetID suitable for use as the first + * parameter in subsequent calls to {@link #connect(ID, IConnectContext)}. + * If this method returns null, then it means that + * null is expected as a valid parameter in subsequent calls + * to {@link #connect(ID, IConnectContext)}. If this method returns a non-null + * Namespace, then the targetID parameter in + * {@link #connect(ID, IConnectContext)} must be non-null + * instance created of the returned Namespace. + * + * @return Namespace the namespace associated with subsequent calls to + * {@link #connect(ID, IConnectContext)}. If null, + * then the targetID instances passed to + * {@link #connect(ID, IConnectContext)} may be null. + * If not null, then targetID + * instances passed to {@link #connect(ID, IConnectContext)} must be + * instances of the returned Namespace. + */ + public Namespace getConnectNamespace(); + + /** + * Disconnect. This operation will disconnect the local container instance + * from any previously joined target or group. Subsequent calls to + * getConnectedID() will return null. + */ + public void disconnect(); + + /** + * This specialization of IAdaptable.getAdapter() returns additional + * services supported by this container. A container that supports + * additional services over and above the methods on IContainer + * should return them using this method. It is recommended that clients use + * this method rather than instanceof checks and downcasts to find out about + * the capabilities of a specific container. + *

+ * Typically, after obtaining an IContainer, a client would use this method + * as a means to obtain a more meaningful interface to the container. This + * interface may or may not extend IContainer. For example, a client could + * use the following code to obtain an instance of ISharedObjectContainer: + *

+ * + *
+	 * IContainer newContainer = ContainerFactory.createContainer(type);
+	 * ISharedObjectContainer soContainer = (ISharedObjectContainer) newContainer
+	 * 		.getAdapter(ISharedObjectContainer.class);
+	 * if (soContainer == null)
+	 * 	throw new ContainerCreateException(message);
+	 * 
+ * + *

+ * Implementations of this method should delegate to + * IAdapterManager.loadAdapter() if the service + * cannot be provided directly to ensure extensibility by third-party + * plug-ins. + *

+ * + * @param serviceType + * the service type to look up + * @return the service instance castable to the given class, or + * null if this container does not support the given + * service + */ + public T getAdapter(Class serviceType); + + /** + * Dispose this IContainer instance. The container instance will be made + * inactive after the completion of this method and will be unavailable for + * subsequent usage. + * + */ + public void dispose(); + + /** + * Add listener to IContainer. The listener's handleEvent method will be + * synchronously called when container methods are called. Minimally, the + * events delivered to the listener are as follows
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Container Events
container actionEvent
connect startIContainerConnectingEvent
connect completeIContainerConnectedEvent
disconnect startIContainerDisconnectingEvent
disconnect completeIContainerDisconnectedEvent
+ * + * @param listener + * the IContainerListener to add + */ + public void addListener(IContainerListener listener); + + /** + * Remove listener from IContainer. + * + * @param listener + * the IContainerListener to remove + */ + public void removeListener(IContainerListener listener); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerFactory.java new file mode 100644 index 0000000000..a8bc67ff33 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerFactory.java @@ -0,0 +1,336 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import java.util.List; +import java.util.Map; +import org.eclipse.ecf.core.identity.ID; + +/** + * Container factory contract {@link ContainerFactory} for default + * implementation. + */ +public interface IContainerFactory { + /** + * Add a ContainerTypeDescription to the set of known ContainerDescriptions. + * + * @param containerTypeDescription + * the ContainerTypeDescription to add to this factory. Must not + * be null. + * @return ContainerTypeDescription the old description of the same name, + * null if none found + */ + public ContainerTypeDescription addDescription(ContainerTypeDescription containerTypeDescription); + + /** + * Get a collection of the ContainerDescriptions currently known to this + * factory. This allows clients to query the factory to determine what if + * any other ContainerDescriptions are currently registered with the + * factory, and if so, what they are. + * + * @return List of ContainerTypeDescription instances + */ + public List /* ContainerTypeDescription */ getDescriptions(); + + /** + * Check to see if a given named description is already contained by this + * factory + * + * @param containerTypeDescription + * the ContainerTypeDescription to look for + * @return true if description is already known to factory, false otherwise + */ + public boolean containsDescription(ContainerTypeDescription containerTypeDescription); + + /** + * Get the known ContainerTypeDescription given it's name. + * + * @param containerTypeDescriptionName + * the name to use as key to find ContainerTypeDescription. Must not be null. + * @return ContainerTypeDescription found. Null if not found. + */ + public ContainerTypeDescription getDescriptionByName(String containerTypeDescriptionName); + + /** + * Remove given description from set known to this factory. + * + * @param containerTypeDescription + * the ContainerTypeDescription to remove + * @return the removed ContainerTypeDescription, null if nothing removed + */ + public ContainerTypeDescription removeDescription(ContainerTypeDescription containerTypeDescription); + + /** + * Get container type descriptions that support the given containerAdapter + * + * @param containerAdapter the container adapter. Must not be null. + * @return ContainerTypeDescription[] of descriptions that support the given container adapter. If no + * ContainerTypeDescriptions found that support the given adapter, an empty array will be returned. + */ + public ContainerTypeDescription[] getDescriptionsForContainerAdapter(Class containerAdapter); + + /** + * Make a base IContainer instance. + * + * @return IContainer instance. A non-null instance will be returned. + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer() throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerID the container's new ID. Must not be null. + * @return IContainer instance. A non-null. instance will be returned. + * @throws ContainerCreateException if some problem creating a base IContainer instance. + */ + public IContainer createContainer(ID containerID) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use. Must not be null. + * @return a valid instance of IContainer. Will not be null. + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to lookup. Must not be null. + * @return a valid instance of IContainer. Will not be null. + * @throws ContainerCreateException if cannot create container of given name + */ + public IContainer createContainer(String containerTypeDescriptionName) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use to create the instance. Must not be null. + * @param parameters + * an Object [] of parameters passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer. A non-null instance will be returned. + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, Object[] parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to lookup. Must not be null. + * @param parameters + * the Object [] of parameters passed to the + * IContainerInstantiator.createInstance method. May be null. + * @return a valid instance of IContainer. Will not be null. + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer(String containerTypeDescriptionName, Object[] parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to use to create the instance. Must not be null. + * @param containerId the container's new ID. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, String containerId) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to use to create the instance. Must not be null. + * @param containerId the container's new ID. May be null. + * @param parameters + * an Object [] of parameters passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, String containerId, Object[] parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use to create the instance. Must not be null. + * @param containerId the container's new ID. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, String containerId) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use to create the instance. Must not be null. + * @param containerId the container's new ID. May be null. + * @param parameters + * an Object [] of parameters passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, String containerId, Object[] parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use to create the instance. Must not be null. + * @param containerID the container's new ID. May be null. + * @param parameters + * an Object [] of parameters passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, ID containerID, Object[] parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to lookup. Must not be null. + * @param containerID the new container's id. May be null. + * @param parameters + * the Object [] of parameters passed to the + * IContainerInstantiator.createInstance method. May be null. + * @return a valid instance of IContainer. Will not be null. + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer(String containerTypeDescriptionName, ID containerID, Object[] parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to lookup. Must not be null. + * @param containerID the new container's id. May be null. + * @return a valid instance of IContainer. Will not be null. + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, ID containerID) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to lookup. Must not be null. + * @param containerID the new container's id. May be null. + * @return a valid instance of IContainer. Will not be null. + * @throws ContainerCreateException if some problem creating the instance. + */ + public IContainer createContainer(String containerTypeDescriptionName, ID containerID) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use to create the instance. Must not be null. + * @param containerID the container's new ID. Must not be null. + * @param parameters + * a Map of parameters (name/value pairs) passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, ID containerID, Map parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use to create the instance. Must not be null. + * @param containerId the container's new ID. May be null. + * @param parameters + * a Map of parameters (name/value pairs) passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, String containerId, Map parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to lookup. Must not be null. + * @param containerID the container's new ID. May be null. + * @param parameters + * a Map of parameters (name/value pairs) passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, ID containerID, Map parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to lookup. Must not be null. + * @param containerId the container's new ID. May be null. + * @param parameters + * a Map of parameters (name/value pairs) passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, String containerId, Map parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescription + * the ContainerTypeDescription to use to create the instance. Must not be null. + * @param parameters + * a Map of parameters (name/value pairs) passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(ContainerTypeDescription containerTypeDescription, Map parameters) throws ContainerCreateException; + + /** + * Create a new container. + * + * @param containerTypeDescriptionName + * the ContainerTypeDescription name to lookup. Must not be null. + * @param parameters + * a Map of parameters (name/value pairs) passed to the createInstance method + * of the IContainerInstantiator. May be null. + * @return a valid instance of IContainer + * @throws ContainerCreateException if some problem creating the instance. + * @since 3.1 + */ + public IContainer createContainer(String containerTypeDescriptionName, Map parameters) throws ContainerCreateException; + +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerListener.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerListener.java new file mode 100644 index 0000000000..40b179afb4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerListener.java @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import org.eclipse.ecf.core.events.IContainerEvent; + +/** + * Listener for objects that wish to receive events from an IContainer + * instances. + * + * @see IContainer#addListener(IContainerListener) + *

+ * Note these methods will be called asynchronously when notifications of remote + * changes are received by the provider implementation code. The provider is + * free to call the methods below with an arbitrary thread, so the + * implementation of these methods must be appropriately prepared. + *

+ * For example, if the code implementing any of these methods must interact with + * user interface code, then it should use code such as the following to execute + * on the SWT UI thread: + * + *

+ * 	Display.getDefault().asyncExec(new Runnable() {
+ * 		public void run() {
+ * 		... UI code here
+ * 		}
+ * 	});
+ * 
+ * + * Further, the code in the implementations of these methods should not block via + * I/O operations or blocking UI calls. + */ +public interface IContainerListener { + /** + * Handle event from IContainer + * + * @param event the event to handle + */ + public void handleEvent(IContainerEvent event); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManager.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManager.java new file mode 100644 index 0000000000..a8cd2f170b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManager.java @@ -0,0 +1,131 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Container manager for getting access to existing container instances + * previously created via {@link IContainerFactory}. + */ +public interface IContainerManager { + + /** + * Get container factory associated with this container manager. + * @return IContainerFactory. Will not return null. + * + * @since 3.0 + */ + public IContainerFactory getContainerFactory(); + + /** + * Get container for given ID. If containerID is + * null then null will be returned. If + * active container with given containerID, is not known to this container manager, + * then null will also be returned. + * @param containerID the ID of the container instance to retrieve from this manager. If null + * null will be returned. + * @return IContainer instance with given containerID. Will be null if there + * is no container with given ID known to this container manager. + */ + public IContainer getContainer(ID containerID); + + /** + * Get the container type description used to create the container with the given ID. + * + * @param containerID the ID of the container to get the description for. + * @return ContainerTypeDescription for the container with the given ID. Will return null + * if no container with the given containerID exists under this manager. + */ + public ContainerTypeDescription getContainerTypeDescription(ID containerID); + + /** + * Get all containers known to this container manager. + * + * @return IContainer[] of active container instances known to this + * container manager. Will not return null, but may + * return empty IContainer[]. + */ + public IContainer[] getAllContainers(); + + /** + * Return true if this container manager has the given container under + * management, false otherwise. + * + * @param containerID + * the ID of the container to find. If null this + * method returns false. + * + * @return true if this container manager has the given container under + * management, false otherwise. + */ + public boolean hasContainer(ID containerID); + + /** + * Add given container to manager. + * + * @param container + * to add. Must not be null. Also + * container.getID() must return a non-null + * value. If container.getID() returns + * null then this method will throw a + * {@link NullPointerException}. + * @param typeDescription the container type description used to create the given container. Must not be null. + * @return IContainer previously added (with same ID). + */ + public IContainer addContainer(IContainer container, ContainerTypeDescription typeDescription); + + /** + * Remove given container from manager. + * @param container the container to remove. Must not be null. + * + * @return IContainer instance removed. If no instance with same ID is found + * then null will be returned. + */ + public IContainer removeContainer(IContainer container); + + /** + * Remove given container from manager. + * @param containerID the ID of the container to remove. Must not be null. + * + * @return IContainer instance removed. If no instance with same ID is found + * then null will be returned. + * + * @since 3.0 + */ + public IContainer removeContainer(ID containerID); + + /** + * Add listener to this {@link IContainerManager}. + * + * @param listener the listener to add. Must not be null. + * @return true if listener successfully added + */ + public boolean addListener(IContainerManagerListener listener); + + /** + * Remove listener from this {@link IContainerManager}. + * + * @param listener the listener to remove. Must not be null. + * @return true if listener successfully removed + */ + public boolean removeListener(IContainerManagerListener listener); + + /** + * Remove all containers from this manager + * + * @since 3.0 + */ + public void removeAllContainers(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManagerListener.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManagerListener.java new file mode 100644 index 0000000000..5cfa6f0e18 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IContainerManagerListener.java @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core; + +/** + * Container manager listener. Instances of this interface may be registered via + * calls to {@link IContainerManager#addListener(IContainerManagerListener)}. + * When subsequent additions to the {@link IContainerManager} occur, the + * {@link #containerAdded(IContainer)} method will be called. When container + * removals occur, {@link #containerRemoved(IContainer)}. Note that these + * methods will be called by arbitrary threads. + * + */ +public interface IContainerManagerListener { + + /** + * Container added to the implementing IContainerManager. + * + * @param container + * the {@link IContainer} added. Will not be null. + */ + public void containerAdded(IContainer container); + + /** + * Container removed from the implementing IContainerManager. + * + * @param container + * the {@link IContainer} removed. Will not be null. + */ + public void containerRemoved(IContainer container); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IReliableContainer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IReliableContainer.java new file mode 100644 index 0000000000..4ca8b66d2c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/IReliableContainer.java @@ -0,0 +1,35 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Contract for reliable container. Extends IContainer + * + * @see IContainer + */ +public interface IReliableContainer extends IContainer { + /** + * Get the current membership of the joined group. This method will + * accurately report the current group membership of the connected group. + * + * @return ID[] the IDs of the current group membership + */ + public ID[] getGroupMemberIDs(); + + /** + * @return true if this IReliableContainer instance is in the 'manager' role + * for the group, false otherwise. + */ + public boolean isGroupManager(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectedEvent.java new file mode 100644 index 0000000000..2c6db38e8f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectedEvent.java @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Container connected event + * + */ +public class ContainerConnectedEvent implements IContainerConnectedEvent { + private final ID joinedContainerID; + + private final ID localContainerID; + + public ContainerConnectedEvent(ID localContainerID, ID targetID) { + super(); + this.localContainerID = localContainerID; + this.joinedContainerID = targetID; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerConnectedEvent#getTargetID() + */ + public ID getTargetID() { + return joinedContainerID; + } + + public ID getLocalContainerID() { + return localContainerID; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf = new StringBuffer("ContainerConnectedEvent["); //$NON-NLS-1$ + buf.append(getLocalContainerID()).append("]"); //$NON-NLS-1$ + buf.append(getTargetID()).append(";"); //$NON-NLS-1$ + return buf.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectingEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectingEvent.java new file mode 100644 index 0000000000..3bb0e29427 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerConnectingEvent.java @@ -0,0 +1,62 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +public class ContainerConnectingEvent implements IContainerConnectingEvent { + ID localContainerID; + + ID targetID; + + Object data; + + public ContainerConnectingEvent(ID localContainerID, ID targetID, Object data) { + this.localContainerID = localContainerID; + this.targetID = targetID; + this.data = data; + } + + public ContainerConnectingEvent(ID localContainerID, ID targetID) { + this(localContainerID, targetID, null); + } + + public ID getTargetID() { + return targetID; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerConnectingEvent#getData() + */ + public Object getData() { + return data; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerEvent#getLocalContainerID() + */ + public ID getLocalContainerID() { + return localContainerID; + } + + public String toString() { + StringBuffer buf = new StringBuffer("ContainerConnectingEvent["); //$NON-NLS-1$ + buf.append(getLocalContainerID()).append(";"); //$NON-NLS-1$ + buf.append(getTargetID()).append(";"); //$NON-NLS-1$ + buf.append(getData()).append("]"); //$NON-NLS-1$ + return buf.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectedEvent.java new file mode 100644 index 0000000000..8b96f157f9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectedEvent.java @@ -0,0 +1,68 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Container disconnected event. + */ +public class ContainerDisconnectedEvent implements IContainerDisconnectedEvent { + private final ID departedContainerID; + + private final ID localContainerID; + + /** + * Creates a new ContainerDisconnectedEvent to indicate that the container + * has now completely disconnected from its target host. + * + * @param localContainerID + * the ID of the local container + * @param targetID + * the ID of the target + */ + public ContainerDisconnectedEvent(ID localContainerID, ID targetID) { + this.localContainerID = localContainerID; + this.departedContainerID = targetID; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerDisconnectedEvent#getTargetID() + */ + public ID getTargetID() { + return departedContainerID; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerEvent#getLocalContainerID() + */ + public ID getLocalContainerID() { + return localContainerID; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf = new StringBuffer("ContainerDisconnectedEvent["); //$NON-NLS-1$ + buf.append(getLocalContainerID()).append(";").append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append(getTargetID()).append(";"); //$NON-NLS-1$ + return buf.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectingEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectingEvent.java new file mode 100644 index 0000000000..7211c71ac8 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisconnectingEvent.java @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +public class ContainerDisconnectingEvent implements IContainerDisconnectingEvent { + ID localContainerID; + + ID groupID; + + public ContainerDisconnectingEvent(ID localContainerID, ID targetID) { + this.localContainerID = localContainerID; + this.groupID = targetID; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerEvent#getLocalContainerID() + */ + public ID getLocalContainerID() { + return localContainerID; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerDisconnectingEvent#getTargetID() + */ + public ID getTargetID() { + return groupID; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf = new StringBuffer("ContainerDisconnectingEvent["); //$NON-NLS-1$ + buf.append(getLocalContainerID()).append(";"); //$NON-NLS-1$ + buf.append(getTargetID()).append("]"); //$NON-NLS-1$ + return buf.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisposeEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisposeEvent.java new file mode 100644 index 0000000000..f968e9fe09 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerDisposeEvent.java @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +public class ContainerDisposeEvent implements IContainerDisposeEvent { + private final ID localContainerID; + + public ContainerDisposeEvent(ID localContainerID) { + super(); + this.localContainerID = localContainerID; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.events.IContainerEvent#getLocalContainerID() + */ + public ID getLocalContainerID() { + return localContainerID; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf = new StringBuffer("ContainerDisposeEvent["); //$NON-NLS-1$ + buf.append(getLocalContainerID()).append("]"); //$NON-NLS-1$ + return buf.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerEjectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerEjectedEvent.java new file mode 100644 index 0000000000..49c8b54ac6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/ContainerEjectedEvent.java @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import java.io.Serializable; +import org.eclipse.ecf.core.identity.ID; + +public class ContainerEjectedEvent implements IContainerEjectedEvent { + private final ID localContainerID; + + private final ID groupID; + + private final Serializable reason; + + public ContainerEjectedEvent(ID localContainerID, ID targetID, Serializable reason) { + super(); + this.localContainerID = localContainerID; + this.groupID = targetID; + this.reason = reason; + } + + public ID getTargetID() { + return groupID; + } + + public ID getLocalContainerID() { + return localContainerID; + } + + public Serializable getReason() { + return reason; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuffer buf = new StringBuffer("ContainerEjectedEvent["); //$NON-NLS-1$ + buf.append(getLocalContainerID()).append(";"); //$NON-NLS-1$ + buf.append(getTargetID()).append(";"); //$NON-NLS-1$ + buf.append(getReason()).append("]"); //$NON-NLS-1$ + return buf.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectedEvent.java new file mode 100644 index 0000000000..766ee7a7f8 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectedEvent.java @@ -0,0 +1,27 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Container connected event interface + * + */ +public interface IContainerConnectedEvent extends IContainerEvent { + /** + * Get ID of container target (the container we are now connected to) + * + * @return ID the ID of the container we connected to. Will not be null. + */ + public ID getTargetID(); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectingEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectingEvent.java new file mode 100644 index 0000000000..ee5f840989 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerConnectingEvent.java @@ -0,0 +1,34 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Container connecting event + * + */ +public interface IContainerConnectingEvent extends IContainerEvent { + /** + * Get ID of container target (the container we are connecting to) + * + * @return ID the ID of the container we connecting to. Will not be null. + */ + public ID getTargetID(); + + /** + * Get data associated with connecting + * + * @return Object the object data for connect. May be null + */ + public Object getData(); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectedEvent.java new file mode 100644 index 0000000000..f78bd017e1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectedEvent.java @@ -0,0 +1,28 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Container disconnected event + * + */ +public interface IContainerDisconnectedEvent extends IContainerEvent { + /** + * Get ID of container target (the container we were disconnected from) + * + * @return ID the ID of the container were disconnected from. Will not be + * null. + */ + public ID getTargetID(); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectingEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectingEvent.java new file mode 100644 index 0000000000..d5a4a2a09c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisconnectingEvent.java @@ -0,0 +1,28 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; + +/** + * Container disconnecting event + * + */ +public interface IContainerDisconnectingEvent extends IContainerEvent { + /** + * Get ID of container target (the container we are disconnecting from) + * + * @return ID the ID of the container we are disconnecting from. Will not be + * null. + */ + public ID getTargetID(); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisposeEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisposeEvent.java new file mode 100644 index 0000000000..0d72aa38fc --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerDisposeEvent.java @@ -0,0 +1,20 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +/** + * Event sent to listeners when a container is disposed + * + */ +public interface IContainerDisposeEvent extends IContainerEvent { + // No methods +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEjectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEjectedEvent.java new file mode 100644 index 0000000000..3789f2251b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEjectedEvent.java @@ -0,0 +1,37 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import java.io.Serializable; +import org.eclipse.ecf.core.identity.ID; + +/** + * Container ejected event. This event is received when a local container has + * been ejected from a remote group + * + */ +public interface IContainerEjectedEvent extends IContainerEvent { + /** + * Get ID of container target (the container we were ejected from) + * + * @return ID the ID of the container we were ejected from. Will not be + * null. + */ + public ID getTargetID(); + + /** + * Get reason for ejection + * + * @return Serializable reason for ejection. May be null. + */ + public Serializable getReason(); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEvent.java new file mode 100644 index 0000000000..e0e8048f54 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/events/IContainerEvent.java @@ -0,0 +1,28 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.events; + +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.core.util.Event; + +/** + * An event received by a container + * + */ +public interface IContainerEvent extends Event { + /** + * Get ID of local discovery container (the discovery container receiving this event). + * + * @return ID for local container. Will not return null. + */ + public ID getLocalContainerID(); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/BaseID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/BaseID.java new file mode 100644 index 0000000000..c7b5ce56f4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/BaseID.java @@ -0,0 +1,164 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.internal.core.identity.Activator; + +/** + * Base class for ID implementation classes + * + * Extensions for the org.eclipse.ecf.namespace extension point that + * expose new Namespace subclasses and their own ID implementations are + * recommended (but not required) to use this class as a superclass. + * + */ +public abstract class BaseID implements ID { + + private static final long serialVersionUID = -6242599410460002514L; + + protected Namespace namespace; + + /** + * @since 3.9 + */ + public BaseID() { + // + } + + protected BaseID(Namespace namespace) { + Assert.isNotNull(namespace, "namespace cannot be null"); //$NON-NLS-1$ + this.namespace = namespace; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Comparable#compareTo(T) + */ + public int compareTo(Object o) { + Assert.isTrue(o != null && o instanceof BaseID, "incompatible types for compare"); //$NON-NLS-1$ + return namespace.getCompareToForObject(this, (BaseID) o); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || !(o instanceof BaseID)) { + return false; + } + return namespace.testIDEquals(this, (BaseID) o); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.ID#getName() + */ + public String getName() { + return namespace.getNameForID(this); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.ID#getNamespace() + */ + public Namespace getNamespace() { + return namespace; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return namespace.getHashCodeForID(this); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.ID#toExternalForm() + */ + public String toExternalForm() { + return namespace.toExternalForm(this); + } + + /** + * Called by {@link Namespace#getCompareToForObject(BaseID, BaseID)}. + * + * @param o + * the other ID to compare to. Will not be null. + * @return the appropriate value as per {@link Comparable} contract. + */ + protected abstract int namespaceCompareTo(BaseID o); + + /** + * Called by {@link Namespace#testIDEquals(BaseID, BaseID)}. + * + * @param o + * the other ID to test against. May be null. + * @return true if this ID is equal to the given ID. + * false otherwise. + */ + protected abstract boolean namespaceEquals(BaseID o); + + /** + * Called by {@link Namespace#getNameForID(BaseID)}. + * + * @return String name for this ID. Must not be null. Value + * returned should be unique within this Namespace. + */ + protected abstract String namespaceGetName(); + + /** + * Called by {@link Namespace#getHashCodeForID(BaseID)}. + * + * @return int hashCode for this ID. Returned value must be unique within this + * process. + */ + protected abstract int namespaceHashCode(); + + /** + * Called by {@link Namespace#toExternalForm(BaseID)}. + * + * @return String that represents this ID. Default implementation is to return + * + *
+	 * namespace.getScheme() + Namespace.SCHEME_SEPARATOR + namespaceGetName();
+	 *         
+ */ + protected String namespaceToExternalForm() { + return namespace.getScheme() + Namespace.SCHEME_SEPARATOR + namespaceGetName(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @SuppressWarnings("unchecked") + public Object getAdapter(@SuppressWarnings("rawtypes") Class clazz) { + IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + if (adapterManager == null) + return null; + return adapterManager.getAdapter(this, clazz.getName()); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/GUID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/GUID.java new file mode 100644 index 0000000000..ea91de6065 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/GUID.java @@ -0,0 +1,164 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.security.SecureRandom; +import org.eclipse.ecf.core.util.Base64; + +/** + * Globally unique ID implementation class. Uses + * {@link java.security.SecureRandom} to create a unique number of given byte + * length. Default byte length for secure number is 20 bytes. Default algorithm + * used for creating a SecureRandom instance is SHA1PRNG. + */ +public class GUID extends StringID { + private static final long serialVersionUID = 3545794369039972407L; + + public static class GUIDNamespace extends Namespace { + private static final long serialVersionUID = -8546568877571886386L; + + public GUIDNamespace() { + super(GUID.class.getName(), "GUID Namespace. Default based upon 20-byte SecureRandom in Base64 format"); //$NON-NLS-1$ + } + + public ID createInstance(Object[] args) throws IDCreateException { + try { + String init = getInitStringFromExternalForm(args); + if (init != null) + return new GUID(this, init); + if (args == null || args.length <= 0) + return new GUID(this); + else if (args.length == 1 && args[0] instanceof Integer) + return new GUID(this, ((Integer) args[0]).intValue()); + else if (args.length == 1 && args[0] instanceof String) + return new GUID(this, ((String) args[0])); + else + return new GUID(this); + } catch (Exception e) { + throw new IDCreateException(getName() + " createInstance()", e); //$NON-NLS-1$ + } + } + + public String getScheme() { + return GUID.class.getName(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.core.identity.Namespace# + * getSupportedParameterTypesForCreateInstance() + */ + public Class[][] getSupportedParameterTypes() { + return new Class[][] { {}, { Integer.class }, { String.class } }; + } + + } + + public static final String SR_DEFAULT_ALGO = null; + + public static final String SR_DEFAULT_PROVIDER = null; + + public static final int DEFAULT_BYTE_LENGTH = 20; + + // Class specific SecureRandom instance + protected static transient SecureRandom random; + + /** + * @since 3.9 + */ + public GUID() { + + } + + /** + * Protected constructor for factory-based construction + * + * @param n + * the Namespace this identity will belong to + * @param provider + * the name of the algorithm to use. See {@link SecureRandom} + * @param byteLength + * the length of the target number (in bytes) + */ + protected GUID(Namespace n, String algo, String provider, int byteLength) throws IDCreateException { + super(n, ""); //$NON-NLS-1$ + // Get SecureRandom instance for class + try { + getRandom(algo, provider); + } catch (Exception e) { + throw new IDCreateException("GUID creation failure: " + e.getMessage()); //$NON-NLS-1$ + } + // make sure we have reasonable byteLength + if (byteLength <= 0) + byteLength = 1; + byte[] newBytes = new byte[byteLength]; + // Fill up random bytes + random.nextBytes(newBytes); + // Set value + value = Base64.encode(newBytes); + } + + protected GUID(Namespace n, String value) { + super(n, value); + } + + protected GUID(Namespace n, int byteLength) throws IDCreateException { + this(n, SR_DEFAULT_ALGO, SR_DEFAULT_PROVIDER, byteLength); + } + + protected GUID(Namespace n) throws IDCreateException { + this(n, DEFAULT_BYTE_LENGTH); + } + + /** + * Get SecureRandom instance for creation of random number. + * + * @param algo + * the String algorithm specification (e.g. "SHA1PRNG") for creation + * of the SecureRandom instance + * @param provider + * the provider of the implementation of the given algorighm (e.g. + * "SUN") + * @return SecureRandom + * @exception Exception + * thrown if SecureRandom instance cannot be created/accessed + */ + protected static synchronized SecureRandom getRandom(String algo, String provider) throws Exception { + // Given algo and provider, get SecureRandom instance + if (random == null) { + initializeRandom(algo, provider); + } + return random; + } + + protected static synchronized void initializeRandom(String algo, String provider) throws Exception { + if (provider == null) { + if (algo == null) { + try { + random = SecureRandom.getInstance("IBMSECURERANDOM"); //$NON-NLS-1$ + } catch (Exception e) { + random = SecureRandom.getInstance("SHA1PRNG"); //$NON-NLS-1$ + } + } else + random = SecureRandom.getInstance(algo); + } else { + random = SecureRandom.getInstance(algo, provider); + } + } + + public String toString() { + StringBuilder sb = new StringBuilder("GUID["); //$NON-NLS-1$ + sb.append(value).append("]"); //$NON-NLS-1$ + return sb.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/ID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/ID.java new file mode 100644 index 0000000000..d23fcba4e5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/ID.java @@ -0,0 +1,66 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import org.eclipse.core.runtime.IAdaptable; + +/** + * Contract for ECF identity + *

+ * ECF IDs are immutable once constructed, and unique within the containing + * {@link Namespace}. + *

+ * ID instances are created via the Namespace.createInstance(...) method. This + * method is called by the IDFactory.createID(...) methods for the given + * Namespace. So, for example, to create an ID instance with the name "slewis": + * + *

+ * ID id = IDFactory.getDefault().createID(namespace, "slewis");
+ * 
+ * + *

+ * + * @see Namespace + * + */ +@SuppressWarnings("rawtypes") +public interface ID extends java.io.Serializable, java.lang.Comparable, + java.security.Principal, IAdaptable { + + public boolean equals(Object obj); + + public int hashCode(); + + /** + * Get the unique name of this identity. + * + * @return String unique name for this identity. Will not be null, and must + * be a unique String within the Namespace returned by + * getNamespace() + */ + public String getName(); + + /** + * Get the Namespace instance associated with this identity + * + * @return Namespace the Namespace corresponding to this identity. Will not + * return null. + */ + public Namespace getNamespace(); + + /** + * Get this ID instance in String form. Will not return null. + * + * @return String that is external representation of this ID + */ + public String toExternalForm(); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDCreateException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDCreateException.java new file mode 100644 index 0000000000..60979f6386 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDCreateException.java @@ -0,0 +1,39 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFRuntimeException; + +public class IDCreateException extends ECFRuntimeException { + private static final long serialVersionUID = 3258416140119323960L; + + public IDCreateException() { + super(); + } + + public IDCreateException(IStatus status) { + super(status); + } + + public IDCreateException(String message) { + super(message); + } + + public IDCreateException(Throwable cause) { + super(cause); + } + + public IDCreateException(String message, Throwable cause) { + super(message, cause); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDFactory.java new file mode 100644 index 0000000000..d4eb482c33 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IDFactory.java @@ -0,0 +1,306 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.net.URI; +import java.util.*; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.ecf.internal.core.identity.Activator; + +/** + * A factory class for creating ID instances. This is the factory for plugins to + * manufacture ID instances. + * + */ +public class IDFactory implements IIDFactory { + public static final String SECURITY_PROPERTY = IDFactory.class.getName() + ".security"; //$NON-NLS-1$ + + private static Hashtable namespaces = new Hashtable(); + + protected static IIDFactory instance = null; + + static { + instance = new IDFactory(); + addNamespace0(new StringID.StringIDNamespace()); + addNamespace0(new GUID.GUIDNamespace()); + addNamespace0(new LongID.LongNamespace()); + addNamespace0(new URIID.URIIDNamespace()); + addNamespace0(new UuID.UuIDNamespace()); + } + + private synchronized static void initialize() { + if (!initialized) { + Activator a = Activator.getDefault(); + if (a != null) + a.setupNamespaceExtensionPoint(); + initialized = true; + } + } + + private static boolean initialized = false; + + public synchronized static IIDFactory getDefault() { + return instance; + } + + private IDFactory() { + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.core.identity.IIDFactory#addNamespace(org.eclipse.ecf + * .core.identity.Namespace) + */ + public Namespace addNamespace(Namespace namespace) throws SecurityException { + if (namespace == null) + return null; + initialize(); + return addNamespace0(namespace); + } + + public final static Namespace addNamespace0(Namespace namespace) { + if (namespace == null) + return null; + return (Namespace) namespaces.put(namespace.getName(), namespace); + } + + protected final static void checkPermission(NamespacePermission namespacepermission) throws SecurityException { + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.core.identity.IIDFactory#containsNamespace(org.eclipse + * .ecf.core.identity.Namespace) + */ + public boolean containsNamespace(Namespace namespace) throws SecurityException { + if (namespace == null) + return false; + initialize(); + return containsNamespace0(namespace); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.IIDFactory#getNamespaces() + */ + public List getNamespaces() { + initialize(); + return new ArrayList(namespaces.values()); + } + + public final static boolean containsNamespace0(Namespace n) { + if (n == null) + return false; + return namespaces.containsKey(n.getName()); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.core.identity.IIDFactory#getNamespace(org.eclipse.ecf + * .core.identity.Namespace) + */ + public Namespace getNamespace(Namespace namespace) throws SecurityException { + if (namespace == null) + return null; + initialize(); + return getNamespace0(namespace); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.core.identity.IIDFactory#getNamespaceByName(java.lang + * .String) + */ + public Namespace getNamespaceByName(String name) throws SecurityException { + initialize(); + return getNamespace0(name); + } + + protected final static Namespace getNamespace0(Namespace n) { + if (n == null) + return null; + return (Namespace) namespaces.get(n.getName()); + } + + protected final static Namespace getNamespace0(String name) { + if (name == null) + return null; + return (Namespace) namespaces.get(name); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.IIDFactory#createGUID() + */ + public ID createGUID() throws IDCreateException { + return createGUID(GUID.DEFAULT_BYTE_LENGTH); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.IIDFactory#createGUID(int) + */ + public ID createGUID(int length) throws IDCreateException { + return createID(new GUID.GUIDNamespace(), new Integer[] { Integer.valueOf(length) }); + } + + protected static void logAndThrow(String s, Throwable t) throws IDCreateException { + IDCreateException e = null; + if (t != null) { + e = new IDCreateException(s + ": " + t.getClass().getName() + ": " //$NON-NLS-1$ //$NON-NLS-2$ + + t.getMessage(), t); + } else { + e = new IDCreateException(s); + } + Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, s, e)); + throw e; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.core.identity.IIDFactory#createID(org.eclipse.ecf.core + * .identity.Namespace, java.lang.Object[]) + */ + public ID createID(Namespace n, Object[] args) throws IDCreateException { + // Verify namespace is non-null + if (n == null) + logAndThrow("Namespace cannot be null", null); //$NON-NLS-1$ + initialize(); + // Make sure that namespace is in table of known namespace. If not, + // throw...we don't create any instances that we don't know about! + Namespace ns = getNamespace0(n); + if (ns == null) + logAndThrow("Namespace " + n.getName() + " not found", null); //$NON-NLS-1$ + return ns.createInstance(args); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.IIDFactory#createID(java.lang.String, + * java.lang.Object[]) + */ + public ID createID(String namespaceName, Object[] args) throws IDCreateException { + Namespace n = getNamespaceByName(namespaceName); + if (n == null) + throw new IDCreateException("Namespace " + namespaceName + " not found"); //$NON-NLS-1$ + return createID(n, args); + } + + public ID createID(Namespace namespace, String uri) throws IDCreateException { + return createID(namespace, new Object[] { uri }); + } + + public ID createID(String namespace, String uri) throws IDCreateException { + return createID(namespace, new Object[] { uri }); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.core.identity.IIDFactory#createStringID(java.lang.String) + */ + public ID createStringID(String idstring) throws IDCreateException { + if (idstring == null) + throw new IDCreateException("StringID cannot be null"); //$NON-NLS-1$ + return createID(new StringID.StringIDNamespace(), new String[] { idstring }); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.IIDFactory#createLongID(long) + */ + public ID createLongID(long l) throws IDCreateException { + return createID(new LongID.LongNamespace(), new Long[] { Long.valueOf(l) }); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.core.identity.IIDFactory#removeNamespace(org.eclipse. + * ecf.core.identity.Namespace) + */ + public Namespace removeNamespace(Namespace n) throws SecurityException { + if (n == null) + return null; + initialize(); + return removeNamespace0(n); + } + + /** + * @since 3.4 + */ + public final static Namespace removeNamespace0(Namespace n) { + if (n == null) + return null; + return (Namespace) namespaces.remove(n.getName()); + } + + /** + * @since 3.5 + */ + public ID createUuID(String uuid) throws IDCreateException { + return createID(new UuID.UuIDNamespace(), new Object[] { uuid }); + } + + /** + * @since 3.5 + */ + public ID createUuID(UUID uuid) throws IDCreateException { + return createID(new UuID.UuIDNamespace(), new Object[] { uuid }); + } + + /** + * @since 3.5 + */ + public ID createUuID(URI uuidURI) throws IDCreateException { + return createID(new UuID.UuIDNamespace(), new Object[] { uuidURI }); + } + + /** + * @since 3.5 + */ + public ID createURIID(URI uri) throws IDCreateException { + return createID(new URIID.URIIDNamespace(), new Object[] { uri }); + } + + /** + * @since 3.5 + */ + public ID createURIID(String uri) throws IDCreateException { + return createID(new URIID.URIIDNamespace(), new Object[] { uri }); + } + + /** + * @since 3.5 + */ + public ID createUuID() throws IDCreateException { + return createID(new UuID.UuIDNamespace(), (Object[]) null); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIDFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIDFactory.java new file mode 100644 index 0000000000..23543a8e6a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIDFactory.java @@ -0,0 +1,288 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.net.URI; +import java.util.List; +import java.util.UUID; + +/** + * Contract for {@link IDFactory} + * + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IIDFactory { + /** + * Add the given Namespace to our table of available Namespaces + * + * @param n + * the Namespace to add + * @return Namespace the namespace already in table (null if Namespace not + * previously in table) + * @exception SecurityException + * thrown if caller does not have appropriate + * NamespacePermission for given namespace + */ + public Namespace addNamespace(Namespace n) throws SecurityException; + + /** + * Check whether table contains given Namespace instance + * + * @param n + * the Namespace to look for + * @return true if table does contain given Namespace, false otherwise + * @exception SecurityException + * thrown if caller does not have appropriate + * NamespacePermission for given namespace + */ + public boolean containsNamespace(Namespace n) throws SecurityException; + + /** + * Get a list of the current Namespace instances exposed by this factory. + * + * @return List of Namespace instances + * @exception SecurityException + * thrown if caller does not have appropriate + * NamespacePermission for given namespace + */ + public List getNamespaces() throws SecurityException; + + /** + * Get the given Namespace instance from table + * + * @param n + * the Namespace to look for + * @return Namespace + * @exception SecurityException + * thrown if caller does not have appropriate + * NamespacePermission for given namespace + */ + public Namespace getNamespace(Namespace n) throws SecurityException; + + /** + * Get a Namespace instance by its string name. + * + * @param name + * the name to use for lookup + * @return Namespace instance. Null if not found. + * @exception SecurityException + * thrown if caller does not have appropriate + * NamespacePermission for given namespace + */ + public Namespace getNamespaceByName(String name) throws SecurityException; + + /** + * Make a GUID using SHA-1 hash algorithm and a default of 16bits of data + * length. The value is Base64 encoded to allow for easy display. + * + * @return new ID instance + * @throws IDCreateException + * if ID cannot be constructed + */ + public ID createGUID() throws IDCreateException; + + /** + * Make a GUID using SHA-1 hash algorithm and a default of 16bits of data + * length. The value is Base64 encoded to allow for easy display. + * + * @param length + * the byte-length of data used to create a GUID + * @return new ID instance + * @throws IDCreateException + * if ID cannot be constructed + */ + public ID createGUID(int length) throws IDCreateException; + + /** + * Make a new identity. Given a Namespace, and an array of instance + * constructor parameters, return a new instance of an ID belonging to the + * given Namespace + * + * @param n + * the Namespace to which the ID will belong + * @param args + * an Object [] of the parameters for the ID instance constructor + * @exception IDCreateException + * thrown if class for instantiator or instance can't be + * loaded, if something goes wrong during instance + * construction + */ + public ID createID(Namespace n, Object[] args) throws IDCreateException; + + /** + * Make a new identity. Given a Namespace name, and an array of instance + * constructor parameters, return a new instance of an ID belonging to the + * given Namespace + * + * @param namespaceName + * the name of the Namespace to which the ID will belong + * @param args + * an Object [] of the parameters for the ID instance constructor + * @exception IDCreateException + * thrown if class for instantiator or ID instance can't be + * loaded, if something goes wrong during instance + * construction + */ + public ID createID(String namespaceName, Object[] args) + throws IDCreateException; + + /** + * Make a new identity instance from a namespace and String. + * + * @param namespace + * the namespace to use to create the ID + * @param uri + * the String uri to use to create the ID + * @exception IDCreateException + * thrown if class for instantiator or ID instance can't be + * loaded, if something goes wrong during instance + * construction + */ + public ID createID(Namespace namespace, String uri) + throws IDCreateException; + + /** + * Make a new identity instance from a namespaceName and idValue. The + * namespaceName is first used to lookup the namespace with + * {@link #getNamespaceByName(String)}, and then the result is passed into + * {@link #createID(Namespace,String)}. + * + * @param namespaceName + * the name of the namespace that should be used to create the ID + * @param idValue + * the String value to use to create the ID + * @exception IDCreateException + * thrown if class for instantiator or ID instance can't be + * loaded, if something goes wrong during instance + * construction + */ + public ID createID(String namespaceName, String idValue) + throws IDCreateException; + + /** + * Make a an ID from a String + * + * @param idString + * the String to use as this ID's unique value. Note: It is + * incumbent upon the caller of this method to be sure that the + * given string allows the resulting ID to satisfy the ID + * contract for global uniqueness within the associated + * Namespace. + * + * @return valid ID instance + * @throws IDCreateException + * thrown if class for instantiator or ID instance can't be + * loaded, if something goes wrong during instance construction + */ + public ID createStringID(String idString) throws IDCreateException; + + /** + * Make a an ID from a long + * + * @param l + * the long to use as this ID's unique value. Note: It is + * incumbent upon the caller of this method to be sure that the + * given long allows the resulting ID to satisfy the ID contract + * for global uniqueness within the associated Namespace. + * + * @return valid ID instance + * @throws IDCreateException + * thrown if class for instantiator or ID instance can't be + * loaded, if something goes wrong during instance construction + */ + public ID createLongID(long l) throws IDCreateException; + + /** + * Create a UuID from String + * + * @param uuid + * the String to use. Must be in UUID format as returned from + * UUID.toString(). Must not be null. + * @return valid ID instance + * + * @since 3.5 + */ + public ID createUuID(String uuid) throws IDCreateException; + + /** + * Create a UuID from UUID + * + * @param uuid + * the UUID to use. Must not be null. + * @return valid ID instance + * + * @since 3.5 + */ + public ID createUuID(UUID uuid) throws IDCreateException; + + /** + * Create a random UuID + * + * @return valid ID instance from UUID.randomUUID() + * + * @since 3.5 + */ + public ID createUuID() throws IDCreateException; + + /** + * Create a UuID from URI. + * + * @param uuidURI + * the URI. Must not be null and must be in valid uuid syntax + * form as specified by rfc4122 see + * http://tools.ietf.org/html/rfc4122. Example: + * 'uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6' + * + * @return valid ID instance + * + * @since 3.5 + */ + public ID createUuID(URI uuidURI) throws IDCreateException; + + /** + * Create a URIID from URI. + * + * @param uri + * the URI to use for the URIID. Must not be null. + * + * @return valid ID instance + * + * @since 3.5 + */ + public ID createURIID(URI uri) throws IDCreateException; + + /** + * Create a URIID from String. + * + * @param uri + * the String to use for the URIID. Must not be null, and must be + * valid URI format as per URI.toString(). + * + * @return valid ID instance + * + * @since 3.5 + */ + public ID createURIID(String uri) throws IDCreateException; + + /** + * Remove the given Namespace from our table of available Namespaces + * + * @param n + * the Namespace to remove + * @return Namespace the namespace already in table (null if Namespace not + * previously in table) + * @exception SecurityException + * thrown if caller does not have appropriate + * NamespacePermission for given namespace + */ + public Namespace removeNamespace(Namespace n) throws SecurityException; +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIdentifiable.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIdentifiable.java new file mode 100644 index 0000000000..8cb4a4d8a0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IIdentifiable.java @@ -0,0 +1,26 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +/** + * Defines implementing classes as being identifiable with an ECF ID. + * + */ +public interface IIdentifiable { + /** + * Return the ID for this 'identifiable' object. The returned ID should be + * unique within its namespace. May return null. + * + * @return the ID for this identifiable object. May return null. + */ + public ID getID(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IResourceID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IResourceID.java new file mode 100644 index 0000000000..0f5d6ac619 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/IResourceID.java @@ -0,0 +1,34 @@ +/**************************************************************************** + * Copyright (c) 2009 EclipseSource and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.net.URI; + +/** + * Resource id. ID instances that implement this interface are expected to be + * resources (files, directories, URLs, etc) and so can be identified via a + * {@link URI}. + * + * @since 3.0 + * + */ +public interface IResourceID extends ID { + + /** + * Convert this resource ID to a {@link URI}. + * + * @return URI for this resource ID + */ + public URI toURI(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/LongID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/LongID.java new file mode 100644 index 0000000000..08c078a4ea --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/LongID.java @@ -0,0 +1,108 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +/** + * A unique ID class based upon Long/long + * + */ +public class LongID extends BaseID { + private static final long serialVersionUID = 4049072748317914423L; + + Long value = null; + + public static class LongNamespace extends Namespace { + private static final long serialVersionUID = -1580533392719331665L; + + public LongNamespace() { + super(LongID.class.getName(), "LongID Namespace"); //$NON-NLS-1$ + } + + /** + * @param args must not be null> + * @return ID created. Will not be null. + * @throws IDCreateException never thrown + */ + public ID createInstance(Object[] args) throws IDCreateException { + try { + String init = getInitStringFromExternalForm(args); + if (init != null) + return new LongID(this, Long.decode(init)); + return new LongID(this, (Long) args[0]); + } catch (Exception e) { + throw new IDCreateException(getName() + " createInstance()", e); //$NON-NLS-1$ + } + } + + public String getScheme() { + return LongID.class.getName(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.core.identity.Namespace# + * getSupportedParameterTypesForCreateInstance() + */ + public Class[][] getSupportedParameterTypes() { + return new Class[][] { { Long.class }, { String.class } }; + } + } + + /** + * @since 3.9 + */ + public LongID() { + + } + + protected LongID(Namespace n, Long v) { + super(n); + value = v; + } + + protected LongID(Namespace n, long v) { + super(n); + value = Long.valueOf(v); + } + + protected int namespaceCompareTo(BaseID o) { + Long ovalue = ((LongID) o).value; + return value.compareTo(ovalue); + } + + protected boolean namespaceEquals(BaseID o) { + if (!(o instanceof LongID)) + return false; + LongID obj = (LongID) o; + return value.equals(obj.value); + } + + protected String namespaceGetName() { + return value.toString(); + } + + protected int namespaceHashCode() { + return value.hashCode(); + } + + public long longValue() { + return value.longValue(); + } + + public String toString() { + StringBuilder sb = new StringBuilder("LongID["); //$NON-NLS-1$ + sb.append(value).append("]"); //$NON-NLS-1$ + return sb.toString(); + + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/Namespace.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/Namespace.java new file mode 100644 index 0000000000..71221c75b3 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/Namespace.java @@ -0,0 +1,328 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.io.Serializable; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.internal.core.identity.Activator; + +/** + * Namespace base class. + *

+ * This class and subclasses define a namespace for the creation and management + * of ID instances. Creation of ID instances is accomplished via the + * {@link #createInstance(Object[])} method, implemented by subclasses of this + * Namespace superclass. + *

+ * All Namespace instances must have a unique name passed to the Namespace upon + * construction. + *

+ * Typically Namespace instances are created via plugins that define extensions + * of the org.eclipse.ecf.namespace extension point. For example, to define a + * new Namespace subclass XMPPNamespace with name "ecf.xmpp" and add it to the + * ECF extension registry: + * + *

+ *        <extension
+ *             point="org.eclipse.ecf.namespace">
+ *          <namespace
+ *                class="XMPPNamespace"
+ *                name="ecf.xmpp"/>
+ *        </extension>
+ * 
+ * + * @see ID + */ +public abstract class Namespace implements Serializable, IAdaptable { + + private static final long serialVersionUID = 3976740272094720312L; + + public static final String SCHEME_SEPARATOR = ":"; //$NON-NLS-1$ + + private String name; + + private String description; + + private transient int hashCode; + + private transient boolean isInitialized = false; + + public Namespace() { + // public null constructor + } + + public final boolean initialize(String n, String desc) { + Assert.isNotNull(n, "Namespace name cannot be null"); //$NON-NLS-1$ + if (!isInitialized) { + this.name = n; + this.description = desc; + this.hashCode = name.hashCode(); + this.isInitialized = true; + return true; + } + return false; + } + + public Namespace(String name, String desc) { + initialize(name, desc); + } + + /** + * Override of Object.equals. This equals method returns true if the provided + * Object is also a Namespace instance, and the names of the two instances + * match. + * + * @param other + * the Object to test for equality + */ + public boolean equals(Object other) { + if (!(other instanceof Namespace)) + return false; + return ((Namespace) other).name.equals(name); + } + + /** + * Hashcode implementation. Subclasses should not override. + * + * @return int hashCode for this Namespace. Should be unique. + */ + public int hashCode() { + return hashCode; + } + + /** + * Test whether two IDs are equal to one another. + * + * @param first + * the first ID. Must not be null. + * @param second + * the second ID. Must not be null. + * @return true if this ID is equal to the given ID. + * false otherwise. + */ + protected boolean testIDEquals(BaseID first, BaseID second) { + // First check that namespaces are the same and non-null + Namespace sn = second.getNamespace(); + if (sn == null || !this.equals(sn)) + return false; + return first.namespaceEquals(second); + } + + /** + * The default implementation of this method is to call id.namespaceGetName(). + * Subclasses may override. + * + * @param id + * the ID to get the name for. Must not be null. + * @return String that is the unique name for the given id within this + * Namespace. + */ + protected String getNameForID(BaseID id) { + return id.namespaceGetName(); + } + + /** + * The default implementation of this method is to call + * first.namespaceCompareTo(second). Subclasses may override. + * + * @param first + * the first id to compare. Must not be null. + * @param second + * the second id to compare. Must not be null. + * @return int as specified by {@link Comparable}. + */ + protected int getCompareToForObject(BaseID first, BaseID second) { + return first.namespaceCompareTo(second); + } + + /** + * The default implementation of this method is to call id.namespaceHashCode(). + * Subclasses may override. + * + * @param id + * the id in this Namespace to get the hashcode for. Must not be + * null. + * @return the hashcode for the given id. Returned value must be unique within + * this process. + */ + protected int getHashCodeForID(BaseID id) { + return id.namespaceHashCode(); + } + + /** + * The default implementation of this method is to call + * id.namespaceToExternalForm(). Subclasses may override. + * + * @param id + * the id in this Namespace to convert to external form. + * @return String that represents the given id in an external form. Note that + * this external form may at some later time be passed to + * {@link #createInstance(Object[])} as a single String parameter, and + * should result in a valid ID instance of the appropriate Namespace. + */ + protected String toExternalForm(BaseID id) { + return id.namespaceToExternalForm(); + } + + /** + * Get the name of this namespace. Must not return null. + * + * @return String name of Namespace instance. Must not return null, + * and the returned value should be a globally unique name for this + * Namespace subclass. + * + */ + public String getName() { + return name; + } + + /** + * Get the description, associated with this Namespace. The returned value may + * be null. + * + * @return the description associated with this Namespace. May be + * null. + */ + public String getDescription() { + return description; + } + + /** + * Make an instance of this namespace. Namespace subclasses, provided by plugins + * must implement this method to construct ID instances for the given namespace. + *

+ *

+ * See {@link #getSupportedParameterTypes()} to get information relevant to + * deciding what parameter types are expected by this method. + *

+ *

+ * + * @param parameters + * an Object[] of parameters for creating ID instances. May be null. + * + * @return a non-null ID instance. The class used may extend BaseID or may + * implement the ID interface directly + * @throws IDCreateException + * if construction fails + */ + public abstract ID createInstance(Object[] parameters) throws IDCreateException; + + /** + * Get the primary scheme associated with this namespace. Subclasses must + * provide an implementation that returns a non-null scheme + * identifier. Note that the returned scheme should not contain the + * Namespace.SCHEME_SEPARATOR (\":\"). + * + * @return a String scheme identifier. Must not be null. + */ + public abstract String getScheme(); + + /** + * Get an array of schemes supported by this Namespace instance. Subclasses may + * override to support multiple schemes. + * + * @return String[] of schemes supported by this Namespace. Will not be + * null, but returned array may be of length 0. + */ + public String[] getSupportedSchemes() { + return new String[0]; + } + + /** + * Get the supported parameter types for IDs created via subsequent calls to + * {@link #createInstance(Object[])}. Callers may use this method to determine + * the available parameter types, and then create and pass in conforming Object + * arrays to to {@link #createInstance(Object[])}. + *

+ *

+ * An empty two-dimensional array (new Class[0][0]) is the default returned by + * this abstract superclass. This means that the Object [] passed to + * {@link #createInstance(Object[])} will be ignored. + *

+ *

+ * Subsclasses should override this method to specify the parameters that they + * will accept in calls to {@link #createInstance(Object[])}. The rows of the + * returned Class array are the acceptable types for a given invocation of + * createInstance. + *

+ *

+ * Consider the following example: + *

+ *

+ * + *
+	 * public Class[][] getSupportedParameterTypes() {
+	 * 	return new Class[][] { { String.class }, { String.class, String.class } };
+	 * }
+	 * 
+ * + * The above means that there are two acceptable values for the Object [] passed + * into {@link #createInstance(Object[])}: 1) a single String, and 2) two + * Strings. These would therefore be acceptable as input to createInstance: + * + *
+	 *        ID newID1 = namespace.createInstance(new Object[] { "Hello" });
+	 *        ID newID2 = namespace.createInstance(new Object[] { "Hello", "There"}};
+	 * 
+ * + * @return Class [][] an array of class []s. Rows of the returned + * two-dimensional array define the acceptable parameter types for a + * single call to {@link #createInstance(Object[])}. If zero-length + * Class arrays are returned (i.e. Class[0][0]), then Object [] + * parameters to {@link #createInstance(Object[])} will be ignored. + */ + public Class[][] getSupportedParameterTypes() { + return new Class[][] { {} }; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @SuppressWarnings("unchecked") + public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) { + if (adapter.isInstance(this)) { + return this; + } + IAdapterManager manager = Activator.getDefault().getAdapterManager(); + if (manager == null) + return null; + return manager.loadAdapter(this, adapter.getName()); + } + + /** + * @since 3.1 + */ + protected String getInitStringFromExternalForm(Object[] args) { + if (args == null || args.length < 1 || args[0] == null) + return null; + if (args[0] instanceof String) { + final String arg = (String) args[0]; + if (arg.startsWith(getScheme() + SCHEME_SEPARATOR)) { + final int index = arg.indexOf(SCHEME_SEPARATOR); + if (index >= arg.length()) + return null; + return arg.substring(index + 1); + } + } + return null; + } + + public String toString() { + StringBuilder b = new StringBuilder("Namespace["); //$NON-NLS-1$ + b.append("name=").append(name).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + b.append("scheme=").append(getScheme()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + b.append("description=").append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + return b.toString(); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/NamespacePermission.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/NamespacePermission.java new file mode 100644 index 0000000000..e2f4d6f82e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/NamespacePermission.java @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.security.BasicPermission; +import java.security.Permission; + +public class NamespacePermission extends BasicPermission { + private static final long serialVersionUID = 3257004371500806969L; + + public static final String ADD_NAMESPACE = "add"; //$NON-NLS-1$ + + public static final String ALL_NAMESPACE = "all"; //$NON-NLS-1$ + + public static final String CONTAINS_NAMESPACE = "contains"; //$NON-NLS-1$ + + public static final String GET_NAMESPACE = "get"; //$NON-NLS-1$ + + public static final String REMOVE_NAMESPACE = "remove"; //$NON-NLS-1$ + + protected String actions; + + /** + * @since 3.9 + */ + public NamespacePermission() { + super("", ""); + } + + public NamespacePermission(String s) { + super(s); + } + + public NamespacePermission(String s, String s1) { + super(s, s1); + actions = s1; + } + + public String getActions() { + return actions; + } + + public boolean implies(Permission p) { + return false; + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/StringID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/StringID.java new file mode 100644 index 0000000000..3996a55168 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/StringID.java @@ -0,0 +1,144 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +/** + * A string-based identity + * + */ +public class StringID extends BaseID { + private static final long serialVersionUID = 3256437019155446068L; + + public static class StringIDNamespace extends Namespace { + private static final long serialVersionUID = 7924280015192029963L; + + public StringIDNamespace(String name, String desc) { + super(name, desc); + } + + public StringIDNamespace() { + super(StringID.class.getName(), "StringID Namespace"); //$NON-NLS-1$ + } + + public ID createInstance(Object[] parameters) throws IDCreateException { + try { + String init = getInitStringFromExternalForm(parameters); + if (init != null) + return new StringID(this, init); + return new StringID(this, (String) parameters[0]); + } catch (Exception e) { + throw new IDCreateException(StringIDNamespace.this.getName() + " createInstance()", e); //$NON-NLS-1$ + } + } + + public String getScheme() { + return StringID.class.getName(); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.core.identity.Namespace# + * getSupportedParameterTypesForCreateInstance() + */ + public Class[][] getSupportedParameterTypes() { + return new Class[][] { { String.class } }; + } + } + + protected String value; + + /** + * @since 3.9 + */ + public StringID() { + + } + + /** + * Protected constructor for factory-based construction + * + * @param n + * the Namespace this identity will belong to + * @param s + * the String defining this StringID + */ + protected StringID(Namespace n, String s) { + super(n); + value = s; + setEmptyNamespace(); + } + + public int compareTo(Object o) { + setEmptyNamespace(); + return super.compareTo(o); + } + + public boolean equals(Object o) { + setEmptyNamespace(); + return super.equals(o); + } + + public String getName() { + setEmptyNamespace(); + return super.getName(); + } + + public int hashCode() { + setEmptyNamespace(); + return super.hashCode(); + } + + public Namespace getNamespace() { + setEmptyNamespace(); + return namespace; + } + + public String toExternalForm() { + setEmptyNamespace(); + return super.toExternalForm(); + } + + public String toString() { + setEmptyNamespace(); + int strlen = value.length(); + StringBuilder sb = new StringBuilder(strlen + 10); + sb.insert(0, "StringID[").insert(9, value).insert(strlen + 9, ']'); //$NON-NLS-1$ + return sb.toString(); + } + + protected int namespaceCompareTo(BaseID obj) { + return getName().compareTo(obj.getName()); + } + + protected boolean namespaceEquals(BaseID obj) { + if (!(obj instanceof StringID)) + return false; + StringID o = (StringID) obj; + return value.equals(o.getName()); + } + + protected String namespaceGetName() { + return value; + } + + protected int namespaceHashCode() { + return value.hashCode() ^ getClass().hashCode(); + } + + protected synchronized void setEmptyNamespace() { + if (namespace == null) { + namespace = IDFactory.getDefault().getNamespaceByName(StringID.class.getName()); + } + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/URIID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/URIID.java new file mode 100644 index 0000000000..7acda187c5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/URIID.java @@ -0,0 +1,131 @@ +/**************************************************************************** + * Copyright (c) 2011 Composent and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.net.URI; +import java.util.UUID; +import org.eclipse.core.runtime.Assert; + +/** + * URI ID class. + * + * @since 3.0 + */ +public class URIID extends BaseID implements IResourceID { + + /** + * @since 3.7 + */ + public static class URIIDNamespace extends Namespace { + + private static final long serialVersionUID = 115165512542491014L; + + /** + * @since 3.8 + */ + public static final String UUID_PROTOCOL = "uuid"; + + public URIIDNamespace(String name, String desc) { + super(name, desc); + } + + public URIIDNamespace() { + super(URIID.class.getName(), "URIID Namespace"); //$NON-NLS-1$ + } + + public ID createInstance(Object[] parameters) throws IDCreateException { + try { + String init = getInitStringFromExternalForm(parameters); + if (init != null) + return new URIID(this, new URI(init)); + if (parameters[0] instanceof URI) + return new URIID(this, (URI) parameters[0]); + if (parameters[0] instanceof String) + return new URIID(this, new URI((String) parameters[0])); + throw new IDCreateException("Cannot create URIID"); + } catch (Exception e) { + throw new IDCreateException(URIIDNamespace.this.getName() + " createInstance()", e); //$NON-NLS-1$ + } + } + + /** + * @since 3.8 + */ + public ID createRandomUUID() throws IDCreateException { + return createInstance(new Object[] { UUID_PROTOCOL + ":" + UUID.randomUUID().toString() }); + } + + public String getScheme() { + return "uri"; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.core.identity.Namespace# + * getSupportedParameterTypesForCreateInstance() + */ + public Class[][] getSupportedParameterTypes() { + return new Class[][] { { String.class }, { URI.class } }; + } + } + + private static final long serialVersionUID = 7328962407044918278L; + private URI uri; + + /** + * @since 3.9 + */ + public URIID() { + + } + + public URIID(Namespace namespace, URI uri) { + super(namespace); + Assert.isNotNull(uri); + this.uri = uri; + } + + protected int namespaceCompareTo(BaseID o) { + if (this == o) + return 0; + if (!this.getClass().equals(o.getClass())) + return Integer.MIN_VALUE; + return this.uri.compareTo(((URIID) o).uri); + } + + protected boolean namespaceEquals(BaseID o) { + if (this == o) + return true; + if (!this.getClass().equals(o.getClass())) + return false; + return this.uri.toString().equals((((URIID) o).uri).toString()); + } + + protected String namespaceGetName() { + return uri.toString(); + } + + protected int namespaceHashCode() { + return uri.toString().hashCode() ^ getClass().hashCode(); + } + + public URI toURI() { + return uri; + } + + public String toString() { + return "URIID [uri=" + uri + "]"; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/UuID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/UuID.java new file mode 100644 index 0000000000..26fefee157 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/identity/UuID.java @@ -0,0 +1,114 @@ +/**************************************************************************** + * Copyright (c) 2015 Composent and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Scott Lewis - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.identity; + +import java.net.URI; +import java.util.UUID; +import org.eclipse.core.runtime.Assert; + +/** + * @since 3.5 + */ +public class UuID extends BaseID { + + private static final long serialVersionUID = -2586540125532542205L; + + public static class UuIDNamespace extends Namespace { + + private static final long serialVersionUID = -7708511830843215943L; + public static final String SCHEME = "uuid"; + + public UuIDNamespace() { + this(UuID.class.getName(), "UuID Namespace"); + } + + public UuIDNamespace(String name, String description) { + super(name, description); + } + + @Override + public ID createInstance(Object[] parameters) throws IDCreateException { + try { + String init = getInitStringFromExternalForm(parameters); + if (init != null) + return new UuID(this, UUID.fromString(init)); + if (parameters != null && parameters.length > 0) { + if (parameters[0] instanceof String) + return new UuID(this, UUID.fromString((String) parameters[0])); + else if (parameters[0] instanceof URI) + return new UuID(this, UUID.fromString(((URI) parameters[0]).getSchemeSpecificPart())); + else if (parameters[0] instanceof UUID) + return new UuID(this, (UUID) parameters[0]); + } + // If we get here, then use random + return new UuID(this, UUID.randomUUID()); + } catch (Exception e) { + throw new IDCreateException(UuIDNamespace.this.getName() + " createInstance()", e); //$NON-NLS-1$ + } + } + + @Override + public String getScheme() { + return SCHEME; + } + + @Override + public Class[][] getSupportedParameterTypes() { + return new Class[][] { { String.class }, { UUID.class }, { URI.class } }; + } + } + + protected UUID uuid; + + /** + * @since 3.9 + */ + public UuID() { + + } + + protected UuID(UuIDNamespace ns, UUID uuid) { + super(ns); + Assert.isNotNull(uuid); + this.uuid = uuid; + } + + protected int namespaceCompareTo(BaseID obj) { + return getName().compareTo(obj.getName()); + } + + protected boolean namespaceEquals(BaseID obj) { + if (!(obj instanceof UuID)) + return false; + UuID o = (UuID) obj; + return uuid.equals(o.uuid); + } + + protected String namespaceGetName() { + return uuid.toString(); + } + + protected int namespaceHashCode() { + return uuid.hashCode() ^ getClass().hashCode(); + } + + public UUID getUUID() { + return uuid; + } + + @Override + public String toString() { + return "UuID[uuid=" + uuid + "]"; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/jobs/JobsExecutor.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/jobs/JobsExecutor.java new file mode 100644 index 0000000000..7ca01f8c06 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/jobs/JobsExecutor.java @@ -0,0 +1,99 @@ +/**************************************************************************** + * Copyright (c) 2008 EclipseSource, IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.jobs; + +import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.jobs.ISchedulingRule; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.equinox.concurrent.future.*; + +/** + * @since 3.2 + */ +public class JobsExecutor extends AbstractExecutor { + + protected int fJobCounter = 1; + protected String fExecutorName; + protected boolean fSystem; + protected ISchedulingRule fSchedulingRule; + protected long delay; + + public JobsExecutor(String executorName) { + this(executorName, false); + } + + public JobsExecutor(String executorName, boolean system) { + this(executorName, system, null); + } + + public JobsExecutor(String executorName, boolean system, ISchedulingRule schedulingRule) { + this(executorName, system, schedulingRule, 0L); + } + + public JobsExecutor(String executorName, boolean system, ISchedulingRule schedulingRule, long delay) { + this.fExecutorName = executorName; + this.fSystem = system; + this.fSchedulingRule = schedulingRule; + this.delay = delay; + } + + protected void setChildProgressMonitor(IProgressMonitor parent, IProgressMonitor child) { + if (parent instanceof FutureProgressMonitor) { + ((FutureProgressMonitor) parent).setChildProgressMonitor(child); + } + } + + protected void safeRun(ISafeProgressRunner runner, IProgressRunnable progressRunnable) { + runner.runWithProgress(progressRunnable); + } + + protected String createJobName(String executorName, int jobCounter, IProgressRunnable runnable) { + return "JobsExecutor(" + executorName + ")." + jobCounter; //$NON-NLS-1$ //$NON-NLS-2$ + } + + protected AbstractFuture createFuture(IProgressMonitor progressMonitor) { + return new SingleOperationFuture(progressMonitor); + } + + public IFuture execute(final IProgressRunnable runnable, final IProgressMonitor clientProgressMonitor) { + Assert.isNotNull(runnable); + final AbstractFuture sof = createFuture(clientProgressMonitor); + Job job = new Job(createJobName(fExecutorName, fJobCounter++, runnable)) { + { + setSystem(fSystem); + setRule(fSchedulingRule); + } + + protected IStatus run(IProgressMonitor monitor) { + // First check to make sure things haven't been canceled + if (sof.isCanceled()) + return sof.getStatus(); + // Now add progress monitor as child of future progress monitor + setChildProgressMonitor(sof.getProgressMonitor(), monitor); + // Now run safely + safeRun(sof, runnable); + return sof.getStatus(); + } + }; + // Configure job before scheduling + configureJobForExecution(job); + job.schedule(delay); + return sof; + } + + protected void configureJobForExecution(Job job) { + // do nothing by default + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseContainerInstantiator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseContainerInstantiator.java new file mode 100644 index 0000000000..42f57616b0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseContainerInstantiator.java @@ -0,0 +1,244 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.provider; + +import java.util.*; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.core.*; +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.internal.core.ECFPlugin; + +/** + * Default implementation of {@link IContainerInstantiator}. ECF provider implementers + * may subclass as desired. + */ +public class BaseContainerInstantiator implements IContainerInstantiator { + + protected static String[] NO_ADAPTERS_ARRAY = new String[] {IContainer.class.getName()}; + protected static String[] EMPTY_STRING_ARRAY = new String[] {}; + protected static Class[][] EMPTY_CLASS_ARRAY = new Class[][] {{}}; + + /** + * @param arg object to get Integer from + * @return Integer created from Object arg + * @since 3.6 + */ + protected Integer getIntegerFromArg(Object arg) { + if (arg == null) + return null; + if (arg instanceof Integer) + return (Integer) arg; + else if (arg instanceof String) { + return Integer.valueOf((String) arg); + } else + throw new IllegalArgumentException("arg=" + arg + " is not of integer type"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * @param arg object to get String from + * @return String created from Object arg + * @since 3.6 + */ + protected String getStringFromArg(Object arg) { + if (arg == null) + return null; + if (arg instanceof String) { + return (String) arg; + } + throw new IllegalArgumentException("arg=" + arg + " is not of String type"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + protected Set getAdaptersForClass(Class clazz) { + Set result = new HashSet(); + IAdapterManager adapterManager = ECFPlugin.getDefault().getAdapterManager(); + if (adapterManager != null) + result.addAll(Arrays.asList(adapterManager.computeAdapterTypes(clazz))); + return result; + } + + protected Set getInterfacesForClass(Set s, Class clazz) { + if (clazz.equals(Object.class)) + return s; + s.addAll(getInterfacesForClass(s, clazz.getSuperclass())); + s.addAll(Arrays.asList(clazz.getInterfaces())); + return s; + } + + protected Set getInterfacesForClass(Class clazz) { + Set clazzes = getInterfacesForClass(new HashSet(), clazz); + Set result = new HashSet(); + for (Iterator i = clazzes.iterator(); i.hasNext();) + result.add(((Class) i.next()).getName()); + return result; + } + + protected String[] getInterfacesAndAdaptersForClass(Class clazz) { + Set result = getAdaptersForClass(clazz); + result.addAll(getInterfacesForClass(clazz)); + return (String[]) result.toArray(new String[] {}); + } + + /** + * @param parameters parameters to get Map from + * @return Map from first of parameters that is instance of Map + * @since 3.6 + */ + protected Map getMap(Object[] parameters) { + if (parameters != null && parameters.length > 0) + for (Object p : parameters) + if (p instanceof Map) + return (Map) p; + return null; + } + + /** + * @param parameters Map parameters to get value from + * @param key the key to use to get value from parameters + * @param clazz the expected type of the value accessed by key + * @param def the default of the value accessed by key. May be null + * @param the expected value type + * @return T value from parameters with key and of type clazz + * @since 3.6 + */ + protected T getParameterValue(Map parameters, String key, Class clazz, T def) { + if (parameters != null) { + Object o = parameters.get(key); + if (clazz.isInstance(o)) + return (T) o; + } + return def; + } + + /** + * @param parameters Map parameters to get value from + * @param key the key to use to get value from parameters + * @param def the default of the value accessed by key. May be null + * @return String value from parameters with key + * @since 3.6 + */ + protected String getParameterValue(Map parameters, String key, String def) { + return getParameterValue(parameters, key, String.class, def); + } + + /** + * @param parameters Map parameters to get value from + * @param key the key to use to get value from parameters + * @return String value from parameters with key + * @since 3.6 + */ + protected String getParameterValue(Map parameters, String key) { + return getParameterValue(parameters, key, null); + } + + /** + * @param ns namespace to use for ID creation. Must not be null + * @param parameters Map parameters to get value from + * @param key the key to use to get value from parameters + * @param type the expected type of the value from parameters + * @param def a default value to use if value from parameters is null + * @param the expected value type + * @return ID the created ID + * @since 3.8 + */ + protected ID getIDParameterValue(Namespace ns, Map parameters, String key, Class type, T def) { + return ns.createInstance(new Object[] {getParameterValue(parameters, key, type, def)}); + } + + /** + * @param ns namespace to use for ID creation. Must not be null + * @param parameters Map parameters to get value from + * @param key the key to use to get value from parameters + * @param def a default String value to use if value from parameters is null + * @return ID the created ID + * @since 3.8 + */ + protected ID getIDParameterValue(Namespace ns, Map parameters, String key, String def) { + return getIDParameterValue(ns, parameters, key, String.class, def); + } + + /** + * @param ns namespace to use for ID creation. Must not be null + * @param parameters Map parameters to get value from + * @param key the key to use to get value from parameters + * @return ID the created ID + * @since 3.8 + */ + protected ID getIDParameterValue(Namespace ns, Map parameters, String key) { + return getIDParameterValue(ns, parameters, key, null); + } + + /** + * @param parameters parameters assumed to contain a Map + * @param key key to use to get parameter value from Map + * @param clazz the expected type of the value from Map + * @param def a default value to use if value from Map is null + * @param the expected value type + * @return T the parameter value with key from Map + * @since 3.6 + */ + protected T getParameterValue(Object[] parameters, String key, Class clazz, T def) { + return getParameterValue(getMap(parameters), key, clazz, def); + } + + /** + * @param parameters parameters assumed to contain a Map + * @param key key to use to get parameter value from Map + * @param clazz the expected type of the value from Map + * @param the expected value type + * @return T the parameter value with key from Map + * @since 3.6 + */ + protected T getParameterValue(Object[] parameters, String key, Class clazz) { + return getParameterValue(parameters, key, clazz, null); + } + + /** + * @param parameters parameters assumed to contain a Map + * @param key key to use to get parameter value from Map + * @param def a default String value to use if value from Map is null + * @return Sting the parameter value with key from Map + * @since 3.6 + */ + protected String getMapParameterString(Object[] parameters, String key, String def) { + return getParameterValue(parameters, key, String.class, def); + } + + /** + * @param parameters parameters assumed to contain a Map + * @param key key to use to get parameter value from Map + * @return Sting the parameter value with key from Map + * @since 3.6 + */ + protected String getMapParameterString(Object[] parameters, String key) { + return getParameterValue(parameters, key, String.class, null); + } + + public IContainer createInstance(ContainerTypeDescription description, Object[] parameters) throws ContainerCreateException { + throw new ContainerCreateException("createInstance not supported"); //$NON-NLS-1$ + } + + public String[] getSupportedAdapterTypes(ContainerTypeDescription description) { + return NO_ADAPTERS_ARRAY; + } + + public Class[][] getSupportedParameterTypes(ContainerTypeDescription description) { + return EMPTY_CLASS_ARRAY; + } + + public String[] getSupportedIntents(ContainerTypeDescription description) { + return null; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseRemoteServiceContainerInstantiator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseRemoteServiceContainerInstantiator.java new file mode 100644 index 0000000000..65b5b012f2 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/BaseRemoteServiceContainerInstantiator.java @@ -0,0 +1,38 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.provider; + +import java.util.Dictionary; +import org.eclipse.ecf.core.ContainerTypeDescription; + +/** + * Default implementation of {@link IRemoteServiceContainerInstantiator}. ECF provider implementers + * may subclass as desired. + * @since 3.1 + */ +public class BaseRemoteServiceContainerInstantiator extends BaseContainerInstantiator implements IRemoteServiceContainerInstantiator { + + public String[] getSupportedConfigs(ContainerTypeDescription description) { + return new String[] {description.getName()}; + } + + public String[] getImportedConfigs(ContainerTypeDescription description, String[] exporterSupportedConfigs) { + return new String[] {description.getName()}; + } + + public Dictionary getPropertiesForImportedConfigs(ContainerTypeDescription description, String[] importedConfigTypes, Dictionary exportedProperties) { + return null; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerInstantiatorUtils.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerInstantiatorUtils.java new file mode 100644 index 0000000000..77853c6950 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerInstantiatorUtils.java @@ -0,0 +1,136 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.provider; + +import java.net.*; +import java.util.*; +import org.eclipse.ecf.core.identity.ID; +import org.osgi.framework.Constants; + +/** + * @since 3.9 + */ +public class ContainerInstantiatorUtils { + + public static final String PRIVATE_INTENT = "osgi.private"; //$NON-NLS-1$ + + /** + * @since 3.9 + */ + public static String[] getContainerIntents(Map properties) { + return getStringArrayProperty(properties, Constants.SERVICE_INTENTS); + } + + /** + * @since 3.9 + */ + public static boolean containsIntent(String[] intents, String intent) { + if (intents == null) + return false; + return Arrays.asList(intents).contains(intent); + } + + /** + * @since 3.9 + */ + public static boolean containsPrivateIntent(String[] intents) { + return containsIntent(intents, PRIVATE_INTENT); + } + + /** + * @since 3.9 + */ + public static boolean containsPrivateIntent(Map properties) { + return containsPrivateIntent(getContainerIntents(properties)); + } + + /** + * @since 3.9 + */ + public static String[] getStringArrayProperty(Map properties, String key) { + if (properties == null) + return null; + Object value = properties.get(key); + List r = new ArrayList(); + if (value == null) + r = Collections.EMPTY_LIST; + + if (value instanceof String) + r = Collections.singletonList((String) value); + + if (value instanceof String[]) { + String[] values = (String[]) value; + for (int i = 0; i < values.length; i++) { + if (values[i] != null) + r.add(values[i]); + } + } + + if (value instanceof Collection) { + Collection values = (Collection) value; + List result = new ArrayList(values.size()); + for (Iterator iter = values.iterator(); iter.hasNext();) { + Object v = iter.next(); + if (v instanceof String) { + result.add(v); + } + } + } + return (r.size() == 0) ? null : r.toArray(new String[r.size()]); + } + + /** + * @since 3.9 + */ + public static void checkPrivate(InetAddress inetAddress) throws ContainerIntentException { + if (!inetAddress.isSiteLocalAddress()) + throw new ContainerIntentException(PRIVATE_INTENT, "Address " + inetAddress + " is not private"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + /** + * @since 3.9 + */ + public static void checkPrivate(String hostname) throws ContainerIntentException { + if (hostname == null) + throw new ContainerIntentException(PRIVATE_INTENT, "Null hostname cannot be private"); //$NON-NLS-1$ + + InetAddress ia = null; + if (hostname.equals("localhost") || hostname.equals("127.0.0.1")) { //$NON-NLS-1$ //$NON-NLS-2$ + try { + ia = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + throw new ContainerIntentException(PRIVATE_INTENT, "Could not get localhost inetaddress", e); //$NON-NLS-1$ + } + } else { + try { + ia = InetAddress.getByName(hostname); + } catch (UnknownHostException e) { + throw new ContainerIntentException(PRIVATE_INTENT, "Could not get address for hostname: " + hostname); //$NON-NLS-1$ + } + } + checkPrivate(ia); + } + + /** + * @since 3.9 + */ + public static void checkPrivate(ID serverID) throws ContainerIntentException { + String name = serverID.getName(); + try { + checkPrivate(new URI(name).getHost()); + } catch (URISyntaxException e) { + throw new ContainerIntentException(PRIVATE_INTENT, "Could not get hostname for serverID name: " + name); //$NON-NLS-1$ + } + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerIntentException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerIntentException.java new file mode 100644 index 0000000000..f6661ed818 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/ContainerIntentException.java @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright (c) 2018 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.provider; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.ContainerCreateException; + +/** + * @since 3.9 + */ +public class ContainerIntentException extends ContainerCreateException { + + private String intentName; + + public ContainerIntentException(String intentName, IStatus status) { + super(status); + this.intentName = intentName; + } + + public ContainerIntentException(String intentName, String message, Throwable cause) { + super(message, cause); + this.intentName = intentName; + } + + public ContainerIntentException(String intentName, String message) { + super(message); + this.intentName = intentName; + } + + private static final long serialVersionUID = -2199528348944072112L; + + public String getIntentName() { + return this.intentName; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IContainerInstantiator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IContainerInstantiator.java new file mode 100644 index 0000000000..0e1b85f967 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IContainerInstantiator.java @@ -0,0 +1,114 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.provider; + +import org.eclipse.ecf.core.*; + +/** + * Interface that must be implemented by ECF provider implementations. + * + */ +public interface IContainerInstantiator { + /** + * Create instance of IContainer. This is the interface that container + * provider implementations must implement for the containerFactory + * extension point. The caller may optionally specify both argument types + * and arguments that will be passed into this method (and therefore to the + * provider implementation implementing this method). For example: + *

+ * ContainerFactory.getDefault().createContainer("foocontainer",new + * Object { "hello" }); + *

+ * @param description + * the ContainerTypeDescription associated with the registered + * container provider implementation + * @param parameters + * parameters specified by the caller. May be null if no + * parameters are passed in by caller to + * ContainerFactory.getDefault().createContainer(...) + * @return IContainer instance. The provider implementation must return a + * valid object implementing IContainer OR throw a + * ContainerCreateException. Null will not be returned. + * @throws ContainerCreateException thrown if instance cannot be created + */ + public IContainer createInstance(ContainerTypeDescription description, Object[] parameters) throws ContainerCreateException; + + /** + * Get array of supported adapters for the given container type description. + * Providers implement this method to allow clients to inspect the adapter + * types exposed by the container described by the given description. + * + * The returned array entries will be the fully qualified names of the + * adapter classes. + * + * Note that the returned types do not guarantee that a subsequent call to + * {@link IContainer#getAdapter(Class)} with the same type name as a + * returned value will return a non-null result. In other + * words, even if the class name is in the returned array, subsequent calls + * to {@link IContainer#getAdapter(Class)} may still return + * null. + * + * @param description + * the ContainerTypeDescription to report adapters for. Must not + * be null. + * @return String[] of supported adapters. The entries in the returned array + * will be the fully qualified class names of adapters supported by + * the given description. null may be returned by + * the provider if no adapters are supported for this description. + */ + public String[] getSupportedAdapterTypes(ContainerTypeDescription description); + + /** + * Get array of parameter types for given container type description. + * Providers implement this method to allow clients to inspect the available + * set of parameter types understood for calls to + * {@link #createInstance(ContainerTypeDescription, Object[])}. + *

+ * Each of the rows of the returned array specifies a Class[] of parameter + * types. These parameter types correspond to the types of Object[] that can + * be passed into the second parameter of + * {@link #createInstance(ContainerTypeDescription, Object[])}. + *

+ * Consider the following example: + *

+	 * public Class[][] getSupportedParameterTypes() {
+	 * 	return new Class[][] { { String.class }, { String.class, String.class } };
+	 * }
+	 * 
+ * + * The above means that there are two acceptable values for the Object [] + * passed into {@link #createInstance(ContainerTypeDescription, Object[])}: + * 1) a single String, and 2) two Strings. These would therefore be + * acceptable as input to createInstance: + * + *
+	 * IContainer container = ContainerFactory.getDefault().createContainer(
+	 * 		description, new Object[] { "Hello" });
+	 * 
+	 * IContainer container2 = ContainerFactory.getDefault().createContainer(
+	 * 		description, new Object[] { "Hello" });
+	 * 
+ *

+ * @param description + * the ContainerTypeDescription to return parameter types for + * @return Class[][] array of Class[]s. Each row in the table corresponds to + * a Class[] that describes the types of Objects in Object[] for + * second parameter to + * {@link #createInstance(ContainerTypeDescription, Object[])}. + * null returned if no parameter types supported for + * given description. + */ + public Class[][] getSupportedParameterTypes(ContainerTypeDescription description); + + public String[] getSupportedIntents(ContainerTypeDescription description); + +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IRemoteServiceContainerInstantiator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IRemoteServiceContainerInstantiator.java new file mode 100644 index 0000000000..e769050537 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/provider/IRemoteServiceContainerInstantiator.java @@ -0,0 +1,85 @@ +/**************************************************************************** + * Copyright (c) 2009 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.provider; + +import java.util.Dictionary; +import org.eclipse.ecf.core.ContainerTypeDescription; + +/** + * Interface that must be implemented by ECF remote service provider implementations. + * @since 3.1 + * + */ +public interface IRemoteServiceContainerInstantiator { + + // Remote Service Exporter + /** + * Get supported configs for the given ContainerTypeDescription. This method + * will be called to determine what the OSGi remote service supported config types are for the given description during + * the search for the service exporter provider/containers upon remote service registration. + * + * @param description the ContainerTypeDescription to return the supported configs for. + * Will not be null. + * @return String[] the supported config types. null may be returned if the + * given description does not support any config types. + */ + public String[] getSupportedConfigs(ContainerTypeDescription description); + + /** + * Get supported intents for the given ContainerTypeDescription. This method + * will be called to determine what the OSGi remote service supported intents are for the given description during + * the search for the service exporter provider/containers upon remote service registration. + * + * @param description the ContainerTypeDescription to return the supported intents for. + * Will not be null. + * @return String[] the supported intents. null may be returned if the + * given description does not support any intents. + */ + public String[] getSupportedIntents(ContainerTypeDescription description); + + // Remote Service Importer + /** + *

Get the imported config types for a given ContainerTypeDescription for the given exporter supported config types. This + * method will be called to determine what the local container imported configs are for the given description and + * exporterSupportedConfigTypes. The local provider can decide which (if any) imported config types should be + * returned and return them. + *

+ * As an example, consider the config types for the ECF generic provider. A generic server has a config type + * of 'ecf.generic.server', and the client has 'ecf.generic.server'. If the generic server exports a given + * service, the exportersSupportedConfigTypes will be '[ecf.generic.server]'. When this method is called + * with the ecf.generic.client description (i.e. the container type description named 'ecf.generic.client'), it + * should respond with a non-null, non-empty array...e.g.: [ecf.generic.client]. This indicates that the + * ecf.generic.client can serve as an importer for the given exporter config type. All, other descriptions + * should return null, to indicate that they cannot import a remote service exported by the given + * exporterSupportedConfigTypes. + * + * @param description the container type description under consideration. + * @param exporterSupportedConfigs the exporter supported config types under consideration. + * @return String[] indicating the importer's supported config types. Should be null, unless + * one or more of the exporterSupportedConfigTypes is recognized for the given description. + */ + public String[] getImportedConfigs(ContainerTypeDescription description, String[] exporterSupportedConfigs); + + /** + * Get the properties associated with the given description, with the given importedConfigTypes, via the given exportedProperties. + * + * @param description the container type description under consideration. + * @param importedConfigs the imported config types for the given properties. Will not be null, and + * should be the same values as returned from {@link #getImportedConfigs(ContainerTypeDescription, String[])}. + * @param exportedProperties the properties from the exported service. Will not be null. + * @return Dictionary that has all of the properties for the importedConfigTypes. May be null if + * no properties are associated with the given description, importedConfigTypes, exportedProperties. + */ + public Dictionary getPropertiesForImportedConfigs(ContainerTypeDescription description, String[] importedConfigs, Dictionary exportedProperties); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/BooleanCallback.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/BooleanCallback.java new file mode 100644 index 0000000000..dc4e5f3b26 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/BooleanCallback.java @@ -0,0 +1,112 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +/** + * Callback that handles Boolean types + * + */ +public class BooleanCallback implements Callback, java.io.Serializable { + + private static final long serialVersionUID = 8660509222691671868L; + + private String prompt; + + private boolean defaultValue; + + private boolean value; + + /** + * Construct a BooleanCallback with a prompt. + * + *

+ * + * @param prompt + * the prompt used to request the boolean value. + * + * @exception IllegalArgumentException + * if prompt is null or if prompt + * has a length of 0. + */ + public BooleanCallback(String prompt) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + this.prompt = prompt; + } + + /** + * Construct a NameCallback with a prompt and default name. + * + *

+ * + * @param prompt + * the prompt used to request the information. + *

+ * + * @param defaultValue + * the value to be used as the default value displayed with the + * prompt. + * + * @exception IllegalArgumentException + * if prompt is null. + */ + public BooleanCallback(String prompt, boolean defaultValue) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + + this.prompt = prompt; + this.defaultValue = defaultValue; + } + + /** + * Get the prompt. + * + * @return the prompt value. + */ + public String getPrompt() { + return prompt; + } + + /** + * Get the default value. + * + * @return the default value, or null if this BooleanCallback was + * not instantiated with a defaultValue. + */ + public boolean getDefaultValue() { + return defaultValue; + } + + /** + * Set the retrieved name. + * + * @param val + * the retrieved value true or false. + * + * @see #getValue + */ + public void setValue(boolean val) { + this.value = val; + } + + /** + * Get the retrieved value. + * + * @return the retrieved value true or false. + * + * @see #setValue + */ + public boolean getValue() { + return value; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/Callback.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/Callback.java new file mode 100644 index 0000000000..3a1fa5c84c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/Callback.java @@ -0,0 +1,16 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +public interface Callback { + // no method defined on this interface +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/CallbackHandler.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/CallbackHandler.java new file mode 100644 index 0000000000..b04a7c4c62 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/CallbackHandler.java @@ -0,0 +1,18 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +public interface CallbackHandler { + + void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException; + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ConnectContextFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ConnectContextFactory.java new file mode 100644 index 0000000000..053e0c2347 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ConnectContextFactory.java @@ -0,0 +1,106 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +import java.io.IOException; + +/** + * Helper class for creating instances of IConnectContext + * + */ +public class ConnectContextFactory { + private ConnectContextFactory() { + super(); + } + + /** + * Create username and password connect context, where username is + * represented as a String and password as an Object. + * + * @param username + * the username + * @param password + * the password + * @return IConnectContext for accessing the username and password + */ + public static IConnectContext createUsernamePasswordConnectContext(final String username, final Object password) { + return new IConnectContext() { + public CallbackHandler getCallbackHandler() { + return new CallbackHandler() { + /** + * @param callbacks + * @throws IOException not thrown by this implementation. + * @throws UnsupportedCallbackException not thrown by this implementation. + */ + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + if (callbacks == null) + return; + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof NameCallback) { + NameCallback ncb = (NameCallback) callbacks[i]; + ncb.setName(username); + } else if (callbacks[i] instanceof ObjectCallback) { + ObjectCallback ocb = (ObjectCallback) callbacks[i]; + ocb.setObject(password); + } else if (callbacks[i] instanceof PasswordCallback && password instanceof String) { + PasswordCallback pc = (PasswordCallback) callbacks[i]; + pc.setPassword((String) password); + } else if (callbacks[i] instanceof PassphraseCallback && password instanceof String) { + PassphraseCallback pc = (PassphraseCallback) callbacks[i]; + pc.setPassphrase((String) password); + } + } + } + }; + } + }; + } + + /** + * Create password connect context, where password is represented as a + * String + * + * @param password + * the password to use + * @return IConnectContext for accessing the given password + */ + public static IConnectContext createPasswordConnectContext(final String password) { + return new IConnectContext() { + public CallbackHandler getCallbackHandler() { + return new CallbackHandler() { + /** + * @param callbacks + * @throws IOException not thrown by this implementation. + * @throws UnsupportedCallbackException not thrown by this implementation. + */ + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + if (callbacks == null) + return; + for (int i = 0; i < callbacks.length; i++) { + if (callbacks[i] instanceof ObjectCallback) { + ObjectCallback ocb = (ObjectCallback) callbacks[i]; + ocb.setObject(password); + } else if (callbacks[i] instanceof PasswordCallback) { + PasswordCallback pc = (PasswordCallback) callbacks[i]; + pc.setPassword(password); + } else if (callbacks[i] instanceof PassphraseCallback) { + PassphraseCallback pc = (PassphraseCallback) callbacks[i]; + pc.setPassphrase(password); + } + } + } + }; + } + }; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ECFSSLContextFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ECFSSLContextFactory.java new file mode 100644 index 0000000000..608310d41d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ECFSSLContextFactory.java @@ -0,0 +1,111 @@ +/**************************************************************************** + * Copyright (c) 2024 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +import java.security.*; +import java.util.Optional; +import javax.net.ssl.SSLContext; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.ecf.internal.core.identity.Activator; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * @since 3.12 + */ +public class ECFSSLContextFactory implements SSLContextFactory { + + private ServiceTracker providerTracker; + private final String defaultProtocol; + private final String defaultProviderName; + + public ECFSSLContextFactory(BundleContext context) throws NoSuchAlgorithmException { + this(context, null); + } + + public ECFSSLContextFactory(BundleContext context, String defaultProtocol) throws NoSuchAlgorithmException { + this(context, defaultProtocol, null); + } + + public ECFSSLContextFactory(BundleContext context, String defaultProtocol, String defaultProviderName) throws NoSuchAlgorithmException { + if (context == null) + throw new NullPointerException("context must not be null"); //$NON-NLS-1$ + if (defaultProviderName == null) { + defaultProviderName = SSLContext.getDefault().getProvider().getName(); + } + if (defaultProtocol == null) { + defaultProtocol = SSLContext.getDefault().getProtocol(); + } + this.defaultProtocol = defaultProtocol; + this.defaultProviderName = defaultProviderName; + this.providerTracker = new ServiceTracker(context, Provider.class, null); + this.providerTracker.open(); + } + + @Override + public SSLContext getDefault() throws NoSuchAlgorithmException, NoSuchProviderException { + return getInstance0(this.defaultProtocol, this.defaultProviderName); + } + + protected SSLContext getInstance0(String protocol, String providerName) throws NoSuchAlgorithmException, NoSuchProviderException { + if (protocol == null) { + return SSLContext.getDefault(); + } + Provider provider = findProvider(providerName); + if (provider == null) + throw new NoSuchProviderException("No provider registered named '" + providerName + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + return SSLContext.getInstance(protocol, provider); + } + + @Override + public SSLContext getInstance(String protocol) throws NoSuchAlgorithmException, NoSuchProviderException { + return getInstance0(protocol, this.defaultProviderName); + } + + public synchronized void close() { + if (this.providerTracker != null) { + this.providerTracker.close(); + this.providerTracker = null; + } + } + + protected Provider findProvider(String providerName) { + if (providerName == null) { + return this.providerTracker.getService(); + } + Optional optResult = this.providerTracker.getTracked().values().stream().filter(p -> + // test that providerName is equal to Provider.getName() + providerName.equals(p.getName())).findFirst(); + // If there are matching Providers, use first (highest priority from sorted map) and use to create SSLContext. + // If none, then throw + if (optResult.isPresent()) { + return optResult.get(); + } + // If providerName is same as current default SSLContext then use it + try { + SSLContext defaultContext = SSLContext.getDefault(); + if (providerName.equals(defaultContext.getProvider().getName())) { + return defaultContext.getProvider(); + } + } catch (NoSuchAlgorithmException e) { + Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Could not get SSLContext.getDefault()", e)); //$NON-NLS-1$ + } + return null; + } + + @Override + public SSLContext getInstance(String protocol, String providerName) throws NoSuchAlgorithmException, NoSuchProviderException { + return getInstance0(protocol, providerName); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectContext.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectContext.java new file mode 100644 index 0000000000..3b785d69af --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectContext.java @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +/** + * A connect context for passing in information to the + * {@link org.eclipse.ecf.core.IContainer#connect(org.eclipse.ecf.core.identity.ID, IConnectContext)} + * call. + * + * @see org.eclipse.ecf.core.IContainer#connect(org.eclipse.ecf.core.identity.ID, + * IConnectContext) + * @see ConnectContextFactory + */ +public interface IConnectContext { + /** + * Get the callbackhandler instance used by the provider to callback into + * application code. The provider will typically use the callback handler to + * provide a set of callbacks for getting/retrieving authorization info + * + * @return CallbackHandler + */ + public CallbackHandler getCallbackHandler(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectHandlerPolicy.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectHandlerPolicy.java new file mode 100644 index 0000000000..48427e07c3 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectHandlerPolicy.java @@ -0,0 +1,40 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +import java.security.PermissionCollection; +import org.eclipse.ecf.core.identity.ID; + +/** + * Connect policy typically implemented by servers + * + */ +public interface IConnectHandlerPolicy extends IContainerPolicy { + /** + * Check connect request + * + * @param address + * the address for the remote client + * @param fromID + * the ID of the container making the connect request + * @param targetID + * the ID of the container responding to that connect request + * @param targetGroup + * the target name of the group that is being connected to + * @param connectData + * arbitrary data associated with the join request + * @return PermissionCollection a collection of permissions associated with + * a successful acceptance of join request + * @throws Exception thrown if connect should not be allowed + */ + public PermissionCollection checkConnect(Object address, ID fromID, ID targetID, String targetGroup, Object connectData) throws Exception; +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectInitiatorPolicy.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectInitiatorPolicy.java new file mode 100644 index 0000000000..f2a61b501c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IConnectInitiatorPolicy.java @@ -0,0 +1,38 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +import org.eclipse.ecf.core.IContainer; +import org.eclipse.ecf.core.identity.ID; + +/** + * Policy handler for connect initiator (clients). + * + */ +public interface IConnectInitiatorPolicy extends IContainerPolicy { + + /** + * Create connect data for given IContainer, given targetID and given context + * + * @param container the container that is doing the connecting + * @param targetID the target ID from {@link IContainer#connect(ID, IConnectContext)} + * @param context from {@link IContainer#connect(ID, IConnectContext)} + * @return Object that will be used as data for the connect call + */ + public Object createConnectData(IContainer container, ID targetID, IConnectContext context); + + /** + * Get connect timeout (in ms) + * @return int connect timeout in ms + */ + public int getConnectTimeout(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IContainerPolicy.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IContainerPolicy.java new file mode 100644 index 0000000000..3e70a21438 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/IContainerPolicy.java @@ -0,0 +1,20 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +public interface IContainerPolicy { + /** + * Refresh the policy + * + */ + public void refresh(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/NameCallback.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/NameCallback.java new file mode 100644 index 0000000000..419aa02cae --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/NameCallback.java @@ -0,0 +1,116 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +/** + * Callback that handles String types + * + */ +public class NameCallback implements Callback, java.io.Serializable { + + private static final long serialVersionUID = -2506493444608585718L; + + private String prompt; + + private String defaultName; + + private String inputName; + + /** + * Construct a NameCallback with a prompt. + * + * @param prompt + * the prompt used to request the name. + * + * @exception IllegalArgumentException + * if prompt is null. + */ + public NameCallback(String prompt) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + this.prompt = prompt; + } + + /** + * Construct a NameCallback with a prompt and default name. + * + *

+ * + * @param prompt + * the prompt used to request the information. + *

+ * + * @param defaultName + * the name to be used as the default name displayed with the + * prompt. + * + * @exception IllegalArgumentException + * if prompt is null. + */ + public NameCallback(String prompt, String defaultName) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + this.prompt = prompt; + this.defaultName = defaultName; + } + + /** + * Get the prompt. + * + *

+ * + * @return the prompt. + */ + public String getPrompt() { + return prompt; + } + + /** + * Get the default name. + * + *

+ * + * @return the default name, or null if this NameCallback was + * not instantiated with a defaultName. + */ + public String getDefaultName() { + return defaultName; + } + + /** + * Set the retrieved name. + * + *

+ * + * @param name + * the retrieved name (which may be null). + * + * @see #getName + */ + public void setName(String name) { + this.inputName = name; + } + + /** + * Get the retrieved name. + * + *

+ * + * @return the retrieved name (which may be null) + * + * @see #setName + */ + public String getName() { + return inputName; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ObjectCallback.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ObjectCallback.java new file mode 100644 index 0000000000..ef23602720 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/ObjectCallback.java @@ -0,0 +1,36 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +/** + * Callback that handles arbitrary Objects + * + */ +public class ObjectCallback implements Callback { + Object data; + + public ObjectCallback() { + data = null; + } + + public ObjectCallback(Object val) { + this.data = val; + } + + public void setObject(Object val) { + this.data = val; + } + + public Object getObject() { + return this.data; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PassphraseCallback.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PassphraseCallback.java new file mode 100644 index 0000000000..f3c8242571 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PassphraseCallback.java @@ -0,0 +1,116 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +/** + * Callback that handles passphrases + * + */ +public class PassphraseCallback implements Callback, java.io.Serializable { + + private static final long serialVersionUID = -6036907502015127266L; + + private String prompt; + + private String defaultPassphrase; + + private String inputPassphrase; + + /** + * Construct a PassphraseCallback with a prompt. + * + * @param prompt + * the prompt used to request the passphrase. + * + * @exception IllegalArgumentException + * if prompt is null. + */ + public PassphraseCallback(String prompt) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + this.prompt = prompt; + } + + /** + * Construct a PassphraseCallback with a prompt and default passphrase. + * + *

+ * + * @param prompt + * the prompt used to request the information. + *

+ * + * @param defaultPassphrase + * the name to be used as the default name displayed with the + * prompt. + * + * @exception IllegalArgumentException + * if prompt is null. + */ + public PassphraseCallback(String prompt, String defaultPassphrase) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + this.prompt = prompt; + this.defaultPassphrase = defaultPassphrase; + } + + /** + * Get the prompt. + * + *

+ * + * @return the prompt. + */ + public String getPrompt() { + return prompt; + } + + /** + * Get the default passphrase. + * + *

+ * + * @return the default passphrase, or null if this PassphraseCallback was + * not instantiated with a defaultPassphrase. + */ + public String getDefaultPassphrase() { + return defaultPassphrase; + } + + /** + * Set the retrieved passphrase. + * + *

+ * + * @param pw + * the passphrase (which may be null). + * + * @see #getPassphrase + */ + public void setPassphrase(String pw) { + this.inputPassphrase = pw; + } + + /** + * Get the retrieved passphrase. + * + *

+ * + * @return the retrieved passphrase (which may be null) + * + * @see #setPassphrase + */ + public String getPassphrase() { + return inputPassphrase; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PasswordCallback.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PasswordCallback.java new file mode 100644 index 0000000000..f0f6e78eaf --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/PasswordCallback.java @@ -0,0 +1,116 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +/** + * Callback that handles passwords + * + */ +public class PasswordCallback implements Callback, java.io.Serializable { + + private static final long serialVersionUID = 6940002988125290335L; + + private String prompt; + + private String defaultPassword; + + private String inputPassword; + + /** + * Construct a PasswordCallback with a prompt. + * + * @param prompt + * the prompt used to request the name. + * + * @exception IllegalArgumentException + * if prompt is null. + */ + public PasswordCallback(String prompt) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + this.prompt = prompt; + } + + /** + * Construct a PasswordCallback with a prompt and default password. + * + *

+ * + * @param prompt + * the prompt used to request the information. + *

+ * + * @param defaultPassword + * the name to be used as the default name displayed with the + * prompt. + * + * @exception IllegalArgumentException + * if prompt is null. + */ + public PasswordCallback(String prompt, String defaultPassword) { + if (prompt == null) + throw new IllegalArgumentException("Prompt cannot be null"); //$NON-NLS-1$ + this.prompt = prompt; + this.defaultPassword = defaultPassword; + } + + /** + * Get the prompt. + * + *

+ * + * @return the prompt. + */ + public String getPrompt() { + return prompt; + } + + /** + * Get the default password. + * + *

+ * + * @return the default password, or null if this PasswordCallback was + * not instantiated with a defaultPassword. + */ + public String getDefaultPassword() { + return defaultPassword; + } + + /** + * Set the retrieved password. + * + *

+ * + * @param pw + * the password (which may be null). + * + * @see #getPassword + */ + public void setPassword(String pw) { + this.inputPassword = pw; + } + + /** + * Get the retrieved password. + * + *

+ * + * @return the retrieved password (which may be null) + * + * @see #setPassword + */ + public String getPassword() { + return inputPassword; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/SSLContextFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/SSLContextFactory.java new file mode 100644 index 0000000000..289b340461 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/SSLContextFactory.java @@ -0,0 +1,44 @@ +/**************************************************************************** + * Copyright (c) 2024 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import javax.net.ssl.SSLContext; + +/** + * This class exposes three legacy static methods from the {@link SSLContext} class as + * methods on an implementing instance. Implementing instances should be registered + * as OSGi services. + * + * @since 3.12 + */ +public interface SSLContextFactory { + + /** + * See SSLContext.getDefault()
+ * NOTE: Rather than the using the {@link #SSLContext.setDefault SSLContext.setDefault(SSLContext)} + * to set the default SSLContext as described in the SSLContext.getDefault() javadocs, the default for the implementer is set upon construction of the service instance. + */ + SSLContext getDefault() throws NoSuchAlgorithmException, NoSuchProviderException; + + /** + * See SSLContext.getInstance(String protocol)
+ */ + SSLContext getInstance(String protocol) throws NoSuchAlgorithmException, NoSuchProviderException; + + /** + * See SSLContext.getInstance(String protocol, String provider)
+ */ + SSLContext getInstance(String protocol, String providerName) throws NoSuchAlgorithmException, NoSuchProviderException; + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/UnsupportedCallbackException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/UnsupportedCallbackException.java new file mode 100644 index 0000000000..5a2055e3cc --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/security/UnsupportedCallbackException.java @@ -0,0 +1,64 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.security; + +public class UnsupportedCallbackException extends Exception { + + private static final long serialVersionUID = -1821878324884011143L; + + private Callback callback; + + /** + * Constructs a UnsupportedCallbackException with no detail + * message. + * + *

+ * + * @param callback + * the unrecognized Callback. + */ + public UnsupportedCallbackException(Callback callback) { + super(); + this.callback = callback; + } + + /** + * Constructs a UnsupportedCallbackException with the specified detail + * message. A detail message is a String that describes this particular + * exception. + * + *

+ * + * @param callback + * the unrecognized Callback. + *

+ * + * @param msg + * the detail message. + */ + public UnsupportedCallbackException(Callback callback, String msg) { + super(msg); + this.callback = callback; + } + + /** + * Get the unrecognized Callback. + * + *

+ * + * @return the unrecognized Callback. + */ + public Callback getCallback() { + return callback; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/ECFStartJob.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/ECFStartJob.java new file mode 100644 index 0000000000..a0ce785dd5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/ECFStartJob.java @@ -0,0 +1,35 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.start; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.jobs.Job; + +/** + * Start job for running extensions of the org.eclipse.ecf.start extension point + * + */ +public class ECFStartJob extends Job { + + IECFStart start; + + public ECFStartJob(String name, IECFStart start) { + super(name); + this.start = start; + } + + protected IStatus run(IProgressMonitor monitor) { + return start.run(monitor); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/IECFStart.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/IECFStart.java new file mode 100644 index 0000000000..8fdbc05539 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/start/IECFStart.java @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.start; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; + +/** + * Interface that must be implemented by extensions of the org.eclipse.ecf.start + * extension point. Such extensions will have their start method called by a new + * Job upon ECF startup. + */ +public interface IECFStart { + /** + * Run some startup task. + * @param monitor + * + * @return IStatus the status of the start + */ + public IStatus run(IProgressMonitor monitor); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableMultiStatus.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableMultiStatus.java new file mode 100644 index 0000000000..f095dd8add --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableMultiStatus.java @@ -0,0 +1,165 @@ +/**************************************************************************** + * Copyright (c) 2008 EclipseSource and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.status; + +import org.eclipse.core.runtime.*; + +/** + * @since 3.2 + */ +public class SerializableMultiStatus extends SerializableStatus { + + private static final long serialVersionUID = 2971900808938367039L; + /** + * List of child statuses. + */ + private IStatus[] children = new IStatus[0]; + + public SerializableMultiStatus(IStatus status) { + this(status.getPlugin(), status.getCode(), status.getMessage(), status.getException()); + IStatus[] childs = status.getChildren(); + if (childs != null) { + for (int i = 0; i < childs.length; i++) { + if (childs[i].isMultiStatus()) { + add(new SerializableMultiStatus(childs[i])); + } else { + add(new SerializableStatus(childs[i])); + } + } + } + } + + public SerializableMultiStatus(MultiStatus multiStatus) { + this(multiStatus.getPlugin(), multiStatus.getCode(), multiStatus.getMessage(), multiStatus.getException()); + IStatus[] childs = multiStatus.getChildren(); + if (childs != null) { + for (int i = 0; i < childs.length; i++) { + if (childs[i].isMultiStatus()) { + add(new SerializableMultiStatus(childs[i])); + } else { + add(new SerializableStatus(childs[i])); + } + } + } + } + + public SerializableMultiStatus(String pluginId, int code, IStatus[] newChildren, String message, Throwable exception) { + this(pluginId, code, message, exception); + Assert.isLegal(newChildren != null); + int maxSeverity = getSeverity(); + if (newChildren != null) { + for (int i = 0; i < newChildren.length; i++) { + Assert.isLegal(newChildren[i] != null); + int severity = newChildren[i].getSeverity(); + if (severity > maxSeverity) + maxSeverity = severity; + } + this.children = new IStatus[newChildren.length]; + System.arraycopy(newChildren, 0, this.children, 0, newChildren.length); + } + setSeverity(maxSeverity); + } + + public SerializableMultiStatus(String pluginId, int code, String message, Throwable exception) { + super(OK, pluginId, code, message, exception); + } + + /** + * Adds the given status to this multi-status. + * + * @param status + * the new child status + */ + public void add(SerializableStatus status) { + Assert.isLegal(status != null); + IStatus[] result = new IStatus[children.length + 1]; + System.arraycopy(children, 0, result, 0, children.length); + result[result.length - 1] = status; + children = result; + int newSev = status.getSeverity(); + if (newSev > getSeverity()) { + setSeverity(newSev); + } + } + + /** + * Adds all of the children of the given status to this multi-status. Does + * nothing if the given status has no children (which includes the case + * where it is not a multi-status). + * + * @param status + * the status whose children are to be added to this one + */ + public void addAll(SerializableStatus status) { + Assert.isLegal(status != null); + SerializableStatus[] statuses = (SerializableStatus[]) status.getChildren(); + for (int i = 0; i < statuses.length; i++) { + add(statuses[i]); + } + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public IStatus[] getChildren() { + return children; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public boolean isMultiStatus() { + return true; + } + + /** + * Merges the given status into this multi-status. Equivalent to + * add(status) if the given status is not a multi-status. + * Equivalent to addAll(status) if the given status is a + * multi-status. + * + * @param status + * the status to merge into this one + * @see #add(SerializableStatus) + * @see #addAll(SerializableStatus) + */ + public void merge(SerializableStatus status) { + Assert.isLegal(status != null); + if (!status.isMultiStatus()) { + add(status); + } else { + addAll(status); + } + } + + /** + * Returns a string representation of the status, suitable for debugging + * purposes only. + * @return String + */ + public String toString() { + StringBuffer buf = new StringBuffer(super.toString()); + buf.append(" children=["); //$NON-NLS-1$ + for (int i = 0; i < children.length; i++) { + if (i != 0) { + buf.append(" "); //$NON-NLS-1$ + } + buf.append(children[i].toString()); + } + buf.append("]"); //$NON-NLS-1$ + return buf.toString(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableStatus.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableStatus.java new file mode 100644 index 0000000000..b60075d042 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/status/SerializableStatus.java @@ -0,0 +1,289 @@ +/**************************************************************************** + * Copyright (c) 2008 EclipseSource and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.status; + +import java.io.*; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.internal.core.ECFPlugin; + +/** + * @since 3.2 + */ +public class SerializableStatus implements IStatus, Serializable { + + private static final long serialVersionUID = -1874392357776889683L; + + public static final IStatus OK_STATUS = new SerializableStatus(OK, ECFPlugin.PLUGIN_ID, OK, "ok", null); //$NON-NLS-1$ + public static final IStatus CANCEL_STATUS = new SerializableStatus(CANCEL, ECFPlugin.PLUGIN_ID, 1, "", null); //$NON-NLS-1$ + + /** + * The severity. One of + *

    + *
  • CANCEL
  • + *
  • ERROR
  • + *
  • WARNING
  • + *
  • INFO
  • + *
  • or OK (0)
  • + *
+ */ + private int severity = OK; + + /** + * Unique identifier of plug-in. + */ + private String pluginId; + + /** + * Plug-in-specific status code. + */ + private int code; + + /** + * Message, localized to the current locale. + */ + private String message; + + /** + * Wrapped exception, or null if none. + */ + private Throwable exception = null; + + /** + * Constant to avoid generating garbage. + */ + private static final IStatus[] theEmptyStatusArray = new IStatus[0]; + + public SerializableStatus(IStatus status) { + setSeverity(status.getSeverity()); + setPlugin(status.getPlugin()); + setCode(status.getCode()); + setMessage(status.getMessage()); + setException(status.getException()); + } + + public SerializableStatus(int severity, String pluginId, int code, String message, Throwable exception) { + setSeverity(severity); + setPlugin(pluginId); + setCode(code); + setMessage(message); + setException(exception); + } + + public SerializableStatus(int severity, String pluginId, String message, Throwable exception) { + setSeverity(severity); + setPlugin(pluginId); + setMessage(message); + setException(exception); + setCode(OK); + } + + public SerializableStatus(int severity, String pluginId, String message) { + setSeverity(severity); + setPlugin(pluginId); + setMessage(message); + setCode(OK); + setException(null); + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public IStatus[] getChildren() { + return theEmptyStatusArray; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public int getCode() { + return code; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public Throwable getException() { + return exception; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public String getMessage() { + return message; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public String getPlugin() { + return pluginId; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public int getSeverity() { + return severity; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public boolean isMultiStatus() { + return false; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public boolean isOK() { + return severity == OK; + } + + /* + * (Intentionally not javadoc'd) Implements the corresponding method on + * IStatus. + */ + public boolean matches(int severityMask) { + return (severity & severityMask) != 0; + } + + /** + * Sets the status code. + * + * @param code + * the plug-in-specific status code, or OK + */ + protected void setCode(int code) { + this.code = code; + } + + /** + * Sets the exception. + * + * @param exception + * a low-level exception, or null if not applicable + */ + protected void setException(Throwable exception) { + // null is never serializable (https://bugs.eclipse.org/328772) + if (exception != null) + this.exception = checkForSerializable(exception); + } + + private Throwable checkForSerializable(Throwable exception2) { + ObjectOutputStream oos = null; + try { + oos = new ObjectOutputStream(new ByteArrayOutputStream()); + oos.writeObject(exception2); + } catch (IOException e) { + ECFPlugin.getDefault().log(new Status(IStatus.WARNING, ECFPlugin.PLUGIN_ID, IStatus.WARNING, "Exception " + exception2 + " could not be serialized for SerializableStatus", e)); //$NON-NLS-1$ //$NON-NLS-2$ + // In this case, we'll create a new exception that can be serialized + return createNewExceptionFor(exception2); + } finally { + try { + if (oos != null) + oos.close(); + } catch (IOException e) { + // do nothing + } + } + return exception2; + } + + private Throwable createNewExceptionFor(Throwable exception2) { + Exception re = new Exception(exception2.getMessage()); + // setStackTrace not in Foundation 1.1 as per + // bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=261781 + // re.setStackTrace(exception2.getStackTrace()); + return re; + } + + /** + * Sets the message. If null is passed, message is set to an empty string. + * + * @param message + * a human-readable message, localized to the current locale + */ + protected void setMessage(String message) { + if (message == null) + this.message = ""; //$NON-NLS-1$ + else + this.message = message; + } + + /** + * Sets the plug-in id. + * + * @param pluginId + * the unique identifier of the relevant plug-in + */ + protected void setPlugin(String pluginId) { + Assert.isLegal(pluginId != null && pluginId.length() > 0); + this.pluginId = pluginId; + } + + /** + * Sets the severity. + * + * @param severity + * the severity; one of OK, ERROR, + * INFO, WARNING, or + * CANCEL + */ + protected void setSeverity(int severity) { + Assert.isLegal(severity == OK || severity == ERROR || severity == WARNING || severity == INFO || severity == CANCEL); + this.severity = severity; + } + + /** + * Returns a string representation of the status, suitable for debugging + * purposes only. + * @return String + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("SerializableStatus "); //$NON-NLS-1$ + if (severity == OK) { + buf.append("OK"); //$NON-NLS-1$ + } else if (severity == ERROR) { + buf.append("ERROR"); //$NON-NLS-1$ + } else if (severity == WARNING) { + buf.append("WARNING"); //$NON-NLS-1$ + } else if (severity == INFO) { + buf.append("INFO"); //$NON-NLS-1$ + } else if (severity == CANCEL) { + buf.append("CANCEL"); //$NON-NLS-1$ + } else { + buf.append("severity="); //$NON-NLS-1$ + buf.append(severity); + } + buf.append(": "); //$NON-NLS-1$ + buf.append(pluginId); + buf.append(" code="); //$NON-NLS-1$ + buf.append(code); + buf.append(' '); + buf.append(message); + buf.append(' '); + buf.append(exception); + return buf.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/IUser.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/IUser.java new file mode 100644 index 0000000000..e8aed6dd8c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/IUser.java @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.user; + +import java.io.Serializable; +import java.util.Map; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.core.identity.IIdentifiable; + +/** + * Interface for arbitrary ECF system user. Instances represent a user within + * ECF providers and/or clients. + */ +public interface IUser extends IIdentifiable, Serializable, IAdaptable { + /** + * Get basic name for user. Will not return null. + * @return String name + */ + public String getName(); + + /** + * Get nick name for user. + * + * @return String the user's nickname. May be null if user + * has no nickname. + */ + public String getNickname(); + + /** + * Get map of properties associated with this user. May be null. + * + * @return Map properties + */ + public Map getProperties(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/User.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/User.java new file mode 100644 index 0000000000..7330432c73 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/user/User.java @@ -0,0 +1,111 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.user; + +import java.util.Map; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.internal.core.ECFPlugin; + +public class User implements IUser { + + private static final long serialVersionUID = 3978709484518586169L; + + protected ID id; + + protected String name; + + protected String nickname; + + protected Map properties; + + public User(ID userID) { + this(userID, userID.getName()); + } + + public User(ID userID, String name) { + this(userID, name, null); + } + + public User(ID userID, String name, Map properties) { + this(userID, name, null, properties); + } + + public User(ID userID, String name, String nickname, Map properties) { + this.id = userID; + this.name = name; + this.nickname = nickname; + this.properties = properties; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.user.IUser#getProperties() + */ + public Map getProperties() { + return properties; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.IIdentifiable#getID() + */ + public ID getID() { + return id; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.user.IUser#getName() + */ + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.user.IUser#getNickname() + */ + public String getNickname() { + return nickname; + } + + public void setName(String name) { + this.name = name; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public T getAdapter(Class adapter) { + if (adapter.isInstance(this)) { + return adapter.cast(this); + } + IAdapterManager adapterManager = ECFPlugin.getDefault().getAdapterManager(); + if (adapterManager == null) + return null; + return (T) adapterManager.loadAdapter(this, adapter.getName()); + } + + public String toString() { + StringBuffer sb = new StringBuffer("User["); //$NON-NLS-1$ + sb.append("id=" + getID()).append(";name=" + getName()); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append(";nickname=").append(getNickname()); //$NON-NLS-1$ + sb.append(";props=" + getProperties()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + return sb.toString(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AbstractFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AbstractFactory.java new file mode 100644 index 0000000000..2d458b23f9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AbstractFactory.java @@ -0,0 +1,37 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +public class AbstractFactory { + @SuppressWarnings("rawtypes") + public static Class[] getClassesForTypes(String[] argTypes, Object[] args, ClassLoader cl) + throws ClassNotFoundException { + Class clazzes[] = null; + if (args == null || args.length == 0) + clazzes = new Class[0]; + else if (argTypes != null) { + clazzes = new Class[argTypes.length]; + for (int i = 0; i < argTypes.length; i++) { + clazzes[i] = Class.forName(argTypes[i], true, cl); + } + } else { + clazzes = new Class[args.length]; + for (int i = 0; i < args.length; i++) { + if (args[i] == null) + clazzes[i] = null; + else + clazzes[i] = args[i].getClass(); + } + } + return clazzes; + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterContainerFilter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterContainerFilter.java new file mode 100644 index 0000000000..843b32b6bf --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterContainerFilter.java @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.ecf.core.IContainer; + +/** + * + */ +public class AdapterContainerFilter implements IContainerFilter { + + private Class clazz; + private Object result; + + public AdapterContainerFilter(Class clazz) { + Assert.isNotNull(clazz); + this.clazz = clazz; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.util.IContainerFilter#match(org.eclipse.ecf.core.IContainer) + */ + public boolean match(IContainer containerToMatch) { + result = containerToMatch.getAdapter(clazz); + return result != null; + } + + public Object getMatchResult() { + return result; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterManagerTracker.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterManagerTracker.java new file mode 100644 index 0000000000..ab39e8249e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/AdapterManagerTracker.java @@ -0,0 +1,43 @@ +/**************************************************************************** + * Copyright (c) 2014 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import org.eclipse.core.runtime.IAdapterManager; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +/** + * @since 3.4 + */ +@SuppressWarnings("rawtypes") +public class AdapterManagerTracker extends ServiceTracker { + + @SuppressWarnings("unchecked") + public AdapterManagerTracker(BundleContext context, ServiceTrackerCustomizer customizer) { + super(context, IAdapterManager.class.getName(), customizer); + } + + public AdapterManagerTracker(BundleContext context) { + this(context, null); + } + + public IAdapterManager getAdapterManager() { + IAdapterManager adapterManager = (IAdapterManager) getService(); + // Then, if the service isn't there, try to get from Platform class via + // PlatformHelper class + if (adapterManager == null) + adapterManager = PlatformHelper.getPlatformAdapterManager(); + return adapterManager; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Base64.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Base64.java new file mode 100644 index 0000000000..05a1f1518f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Base64.java @@ -0,0 +1,219 @@ +/**************************************************************************** + * Copyright (c) 2008 IBM Corporation and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * Composent, Inc. - enhanced API + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.UnsupportedEncodingException; + +public class Base64 { + + private static final byte equalSign = (byte) '='; + + static char digits[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // + 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; + + /** + * This method decodes the byte array in base 64 encoding into a char array + * Base 64 encoding has to be according to the specification given by the + * RFC 1521 (5.2). + * + * @param data the encoded byte array + * @return the decoded byte array + */ + public static byte[] decodeFromCharArray(byte[] data) { + if (data.length == 0) + return data; + int lastRealDataIndex = data.length - 1; + while (data[lastRealDataIndex] == equalSign) + lastRealDataIndex--; + // original data digit is 8 bits long, but base64 digit is 6 bits long + int padBytes = data.length - 1 - lastRealDataIndex; + int byteLength = data.length * 6 / 8 - padBytes; + byte[] result = new byte[byteLength]; + // Each 4 bytes of input (encoded) we end up with 3 bytes of output + int dataIndex = 0; + int resultIndex = 0; + int allBits = 0; + // how many result chunks we can process before getting to pad bytes + int resultChunks = (lastRealDataIndex + 1) / 4; + for (int i = 0; i < resultChunks; i++) { + allBits = 0; + // Loop 4 times gathering input bits (4 * 6 = 24) + for (int j = 0; j < 4; j++) + allBits = (allBits << 6) | decodeDigit(data[dataIndex++]); + // Loop 3 times generating output bits (3 * 8 = 24) + for (int j = resultIndex + 2; j >= resultIndex; j--) { + result[j] = (byte) (allBits & 0xff); // Bottom 8 bits + allBits = allBits >>> 8; + } + resultIndex += 3; // processed 3 result bytes + } + // Now we do the extra bytes in case the original (non-encoded) data + // was not multiple of 3 bytes + switch (padBytes) { + case 1 : + // 1 pad byte means 3 (4-1) extra Base64 bytes of input, 18 + // bits, of which only 16 are meaningful + // Or: 2 bytes of result data + allBits = 0; + // Loop 3 times gathering input bits + for (int j = 0; j < 3; j++) + allBits = (allBits << 6) | decodeDigit(data[dataIndex++]); + // NOTE - The code below ends up being equivalent to allBits = + // allBits>>>2 + // But we code it in a non-optimized way for clarity + // The 4th, missing 6 bits are all 0 + allBits = allBits << 6; + // The 3rd, missing 8 bits are all 0 + allBits = allBits >>> 8; + // Loop 2 times generating output bits + for (int j = resultIndex + 1; j >= resultIndex; j--) { + result[j] = (byte) (allBits & 0xff); // Bottom 8 + // bits + allBits = allBits >>> 8; + } + break; + case 2 : + // 2 pad bytes mean 2 (4-2) extra Base64 bytes of input, 12 bits + // of data, of which only 8 are meaningful + // Or: 1 byte of result data + allBits = 0; + // Loop 2 times gathering input bits + for (int j = 0; j < 2; j++) + allBits = (allBits << 6) | decodeDigit(data[dataIndex++]); + // NOTE - The code below ends up being equivalent to allBits = + // allBits>>>4 + // But we code it in a non-optimized way for clarity + // The 3rd and 4th, missing 6 bits are all 0 + allBits = allBits << 6; + allBits = allBits << 6; + // The 3rd and 4th, missing 8 bits are all 0 + allBits = allBits >>> 8; + allBits = allBits >>> 8; + result[resultIndex] = (byte) (allBits & 0xff); // Bottom + // 8 + // bits + break; + } + return result; + } + + /** + * This method converts a Base 64 digit to its numeric value. + * + * @param data digit (character) to convert + * @return value for the digit + */ + static int decodeDigit(byte data) { + char charData = (char) data; + if (charData <= 'Z' && charData >= 'A') + return charData - 'A'; + if (charData <= 'z' && charData >= 'a') + return charData - 'a' + 26; + if (charData <= '9' && charData >= '0') + return charData - '0' + 52; + switch (charData) { + case '+' : + return 62; + case '/' : + return 63; + default : + throw new IllegalArgumentException("Invalid char to decode: " + data); //$NON-NLS-1$ + } + } + + /** + * This method encodes the byte array into a char array in base 64 according + * to the specification given by the RFC 1521 (5.2). + * + * @param data the encoded char array + * @return the byte array that needs to be encoded + */ + public static byte[] encodeToCharArray(byte[] data) { + int sourceChunks = data.length / 3; + int len = ((data.length + 2) / 3) * 4; + byte[] result = new byte[len]; + int extraBytes = data.length - (sourceChunks * 3); + // Each 4 bytes of input (encoded) we end up with 3 bytes of output + int dataIndex = 0; + int resultIndex = 0; + int allBits = 0; + for (int i = 0; i < sourceChunks; i++) { + allBits = 0; + // Loop 3 times gathering input bits (3 * 8 = 24) + for (int j = 0; j < 3; j++) + allBits = (allBits << 8) | (data[dataIndex++] & 0xff); + // Loop 4 times generating output bits (4 * 6 = 24) + for (int j = resultIndex + 3; j >= resultIndex; j--) { + result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom + // 6 + // bits + allBits = allBits >>> 6; + } + resultIndex += 4; // processed 4 result bytes + } + // Now we do the extra bytes in case the original (non-encoded) data + // is not multiple of 4 bytes + switch (extraBytes) { + case 1 : + allBits = data[dataIndex++]; // actual byte + allBits = allBits << 8; // 8 bits of zeroes + allBits = allBits << 8; // 8 bits of zeroes + // Loop 4 times generating output bits (4 * 6 = 24) + for (int j = resultIndex + 3; j >= resultIndex; j--) { + result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom + // 6 + // bits + allBits = allBits >>> 6; + } + // 2 pad tags + result[result.length - 1] = (byte) '='; + result[result.length - 2] = (byte) '='; + break; + case 2 : + allBits = data[dataIndex++]; // actual byte + allBits = (allBits << 8) | (data[dataIndex++] & 0xff); // actual + // byte + allBits = allBits << 8; // 8 bits of zeroes + // Loop 4 times generating output bits (4 * 6 = 24) + for (int j = resultIndex + 3; j >= resultIndex; j--) { + result[j] = (byte) digits[(allBits & 0x3f)]; // Bottom + // 6 + // bits + allBits = allBits >>> 6; + } + // 1 pad tag + result[result.length - 1] = (byte) '='; + break; + } + return result; + } + + public static String encode(byte[] bytes) { + try { + return new String(encodeToCharArray(bytes), "ISO8859_1"); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + throw new NullPointerException("Do not have ISO8859_1 encoder"); //$NON-NLS-1$ + } + } + + public static byte[] decode(String encoded) { + try { + return decodeFromCharArray(encoded.getBytes("ISO8859_1")); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + throw new NullPointerException("Do not have ISO8859_1 encoder"); //$NON-NLS-1$ + } + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleClassResolver.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleClassResolver.java new file mode 100644 index 0000000000..7f0467bb8a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleClassResolver.java @@ -0,0 +1,48 @@ +/**************************************************************************** + * Copyright (c) 2015 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.ObjectStreamClass; +import org.eclipse.core.runtime.Assert; +import org.osgi.framework.Bundle; + +/** + * @since 3.7 + */ +public class BundleClassResolver implements IClassResolver { + + private final Bundle bundle; + + public BundleClassResolver(Bundle b) { + Assert.isNotNull(b); + this.bundle = b; + } + + @SuppressWarnings("unused") + protected void verifyClass(ObjectStreamClass desc) throws ClassNotFoundException { + // do nothing by default + } + + public Class resolveClass(ObjectStreamClass desc) throws ClassNotFoundException { + + verifyClass(desc); + + try { + return this.bundle.loadClass(desc.getName()); + } catch (IllegalStateException e) { + throw new ClassNotFoundException("Cannot load class=" + desc + " because bundle=" + this.bundle.getSymbolicName() + " has been uninstalled"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } catch (ClassNotFoundException e) { + return ClassResolverObjectInputStream.resolvePrimitiveClass(desc, e); + } + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleStarter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleStarter.java new file mode 100644 index 0000000000..93bdf42f83 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/BundleStarter.java @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (c) 2018 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.util.Arrays; +import java.util.List; +import org.osgi.framework.*; + +/** + * @since 3.9 + */ +public class BundleStarter { + + public static void startDependents(BundleContext context, String[] bundleSymbolicNames, int stateMask) + throws BundleException { + List bsns = Arrays.asList(bundleSymbolicNames); + for (Bundle b : context.getBundles()) + if (bsns.contains(b.getSymbolicName()) && ((b.getState() & stateMask) != 0)) + b.start(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ClassResolverObjectInputStream.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ClassResolverObjectInputStream.java new file mode 100644 index 0000000000..553d7b6d70 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ClassResolverObjectInputStream.java @@ -0,0 +1,109 @@ +/**************************************************************************** + * Copyright (c) 2015 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.*; +import java.util.HashMap; +import org.osgi.framework.*; +import org.osgi.util.tracker.ServiceTracker; + +/** + * @since 3.7 + */ +public class ClassResolverObjectInputStream extends ObjectInputStream { + + public static final HashMap> primClasses = new HashMap>(8, 1.0F); + + static { + primClasses.put("boolean", boolean.class); //$NON-NLS-1$ + primClasses.put("byte", byte.class); //$NON-NLS-1$ + primClasses.put("char", char.class); //$NON-NLS-1$ + primClasses.put("short", short.class); //$NON-NLS-1$ + primClasses.put("int", int.class); //$NON-NLS-1$ + primClasses.put("long", long.class); //$NON-NLS-1$ + primClasses.put("float", float.class); //$NON-NLS-1$ + primClasses.put("double", double.class); //$NON-NLS-1$ + primClasses.put("void", void.class); //$NON-NLS-1$ + } + + public static ObjectInputStream create(BundleContext ctxt, InputStream ins, String filter) throws IOException, SecurityException { + if (ctxt == null) + return new ObjectInputStream(ins); + try { + return new ClassResolverObjectInputStream(ctxt, ins, filter); + } catch (InvalidSyntaxException e) { + throw new IOException("Could not create ClassResolverObjectInputStream because of InvalidSyntaxException in filter=" + filter); //$NON-NLS-1$ + } + } + + public static ObjectInputStream create(BundleContext ctxt, InputStream ins) throws IOException { + return create(ctxt, ins, "(" + IClassResolver.BUNDLE_PROP_NAME + "=" + ctxt.getBundle().getSymbolicName() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + private final BundleContext bundleContext; + private ServiceTracker classResolverST; + + private Filter createClassResolverFilter(String classResolverFilterString) throws InvalidSyntaxException { + String objectClassFilterString = "(" + Constants.OBJECTCLASS + "=" + IClassResolver.class.getName() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (classResolverFilterString != null) + objectClassFilterString = "(&" + objectClassFilterString + classResolverFilterString + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + return this.bundleContext.createFilter(objectClassFilterString); + } + + protected ClassResolverObjectInputStream(BundleContext ctxt, String classResolverFilter) throws IOException, SecurityException, InvalidSyntaxException { + super(); + this.bundleContext = ctxt; + this.classResolverST = new ServiceTracker(this.bundleContext, createClassResolverFilter(classResolverFilter), null); + } + + protected ClassResolverObjectInputStream(BundleContext ctxt) throws IOException, SecurityException, InvalidSyntaxException { + this(ctxt, (String) null); + } + + public ClassResolverObjectInputStream(BundleContext ctxt, InputStream ins, String classResolverFilter) throws IOException, SecurityException, InvalidSyntaxException { + super(ins); + this.bundleContext = ctxt; + this.classResolverST = new ServiceTracker(this.bundleContext, createClassResolverFilter(classResolverFilter), null); + } + + public ClassResolverObjectInputStream(BundleContext ctxt, InputStream ins) throws IOException, SecurityException, InvalidSyntaxException { + this(ctxt, ins, null); + } + + protected BundleContext getContext() { + return this.bundleContext; + } + + @SuppressWarnings("unused") + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + IClassResolver classResolver = null; + if (this.classResolverST != null) { + this.classResolverST.open(); + classResolver = this.classResolverST.getService(); + this.classResolverST.close(); + } + if (classResolver != null) + return classResolver.resolveClass(desc); + throw new ClassNotFoundException("Cannot deserialize class=" + desc + " because no IClassResolver service available"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + public static Class resolvePrimitiveClass(ObjectStreamClass desc, ClassNotFoundException cnfe) throws ClassNotFoundException { + Class cl = primClasses.get(desc.getName()); + if (cl != null) + return cl; + if (cnfe != null) + throw cnfe; + throw new ClassNotFoundException("Could not find class=" + desc); //$NON-NLS-1$ + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ConnectedContainerFilter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ConnectedContainerFilter.java new file mode 100644 index 0000000000..ef28b50c04 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ConnectedContainerFilter.java @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import org.eclipse.ecf.core.IContainer; +import org.eclipse.ecf.core.identity.ID; + +/** + * + */ +public class ConnectedContainerFilter implements IContainerFilter { + + private ID result; + + public ConnectedContainerFilter() { + // XXX nothing to do + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.util.IContainerFilter#match(org.eclipse.ecf.core.IContainer) + */ + public boolean match(IContainer containerToMatch) { + result = containerToMatch.getConnectedID(); + return result != null; + } + + public ID getResult() { + return result; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerFactoryTracker.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerFactoryTracker.java new file mode 100644 index 0000000000..875198ac20 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerFactoryTracker.java @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright (c) 2009 EclipseSource and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import org.eclipse.ecf.core.IContainerFactory; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * Service tracker customized to handle tracking the ECF container factory service (singleton). + * @since 3.1 + * + */ +public class ContainerFactoryTracker extends ServiceTracker { + + public ContainerFactoryTracker(BundleContext context) { + super(context, IContainerFactory.class.getName(), null); + } + + public IContainerFactory getContainerFactory() { + return (IContainerFactory) getService(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerManagerTracker.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerManagerTracker.java new file mode 100644 index 0000000000..e9b51d2468 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ContainerManagerTracker.java @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright (c) 2009 EclipseSource and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import org.eclipse.ecf.core.IContainerManager; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * Service tracker customized to handle tracking the ECF container manager service (singleton). + * @since 3.1 + * + */ +public class ContainerManagerTracker extends ServiceTracker { + + public ContainerManagerTracker(BundleContext context) { + super(context, IContainerManager.class.getName(), null); + } + + public IContainerManager getContainerManager() { + return (IContainerManager) getService(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFException.java new file mode 100644 index 0000000000..2f82fda9c1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFException.java @@ -0,0 +1,57 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.internal.core.identity.Activator; + +public class ECFException extends CoreException { + private static final long serialVersionUID = 3256440309134406707L; + + public ECFException() { + this(null, null); + } + + /** + * @param message + * message associated with exception + */ + public ECFException(String message) { + this(message, null); + } + + /** + * @param cause + * the cause of the new exception + */ + public ECFException(Throwable cause) { + this(null, cause); + } + + /** + * @param message + * @param cause + */ + public ECFException(String message, Throwable cause) { + this(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, ((message == null) ? "" : message), cause)); //$NON-NLS-1$ + } + + /** + * @param status + * the status for th + */ + public ECFException(IStatus status) { + super(status); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFRuntimeException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFRuntimeException.java new file mode 100644 index 0000000000..c6055eaab0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ECFRuntimeException.java @@ -0,0 +1,87 @@ +/**************************************************************************** + * Copyright (c) 2008 Versant Corp. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Markus Kuppe (mkuppe versant com) - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.ecf.internal.core.identity.Activator; + +/** + * @since 3.0 + */ +public class ECFRuntimeException extends RuntimeException { + + private static final long serialVersionUID = 456677468837349011L; + /** Status object. */ + private IStatus status; + + public ECFRuntimeException() { + super(); + } + + /** + * @param message + * message associated with exception + */ + public ECFRuntimeException(String message) { + this(message, null); + } + + /** + * @param cause + * the cause of the new exception + */ + public ECFRuntimeException(Throwable cause) { + this(cause.getMessage(), cause); + } + + /** + * @param message + * @param cause + */ + public ECFRuntimeException(String message, Throwable cause) { + this(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, + ((message == null) ? "" : message), cause)); //$NON-NLS-1$ + } + + /** + * Creates a new exception with the given status object. The message of the + * given status is used as the exception message. + * + * @param status + * the status object to be associated with this exception + */ + public ECFRuntimeException(IStatus status) { + super(status.getMessage()); + initCause(status.getException()); + this.status = status; + } + + /** + * Returns the status object for this exception. + *

+ * IMPORTANT:
+ * The result must NOT be used to log a CoreException (e.g., + * using yourPlugin.getLog().log(status);), since that code + * pattern hides the original stacktrace. Instead, create a new + * {@link Status} with your plug-in ID and this CoreException, + * and log that new status. + *

+ * + * @return a status object + */ + public IStatus getStatus() { + return status; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Event.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Event.java new file mode 100644 index 0000000000..d56a2c2a81 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Event.java @@ -0,0 +1,21 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +/** + * Event 'tag' interface. This is a super-interface for all ECF event + * interfaces/classes + * + */ +public interface Event { + // No methods. This is a 'tag' interface +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ExtensionRegistryRunnable.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ExtensionRegistryRunnable.java new file mode 100644 index 0000000000..1949248176 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ExtensionRegistryRunnable.java @@ -0,0 +1,74 @@ +/**************************************************************************** + * Copyright (c) 2014 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.internal.core.identity.Activator; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * @since 3.4 + */ +public class ExtensionRegistryRunnable implements ISafeRunnable { + + private BundleContext context; + + public ExtensionRegistryRunnable(BundleContext ctxt) { + this.context = ctxt; + } + + /** + * @since 3.8 + */ + protected BundleContext getContext() { + return this.context; + } + + protected void runWithoutRegistry() throws Exception { + // by default do nothing + } + + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + // by default do nothing + } + + protected void logWarning(Throwable exception) { + Activator a = Activator.getDefault(); + if (a != null) + a.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, "Warning: code cannot be run", //$NON-NLS-1$ + exception)); + } + + public void run() throws Exception { + try { + runWithRegistry(getExtensionRegistry()); + } catch (NoClassDefFoundError e) { + runWithoutRegistry(); + } + } + + private IExtensionRegistry getExtensionRegistry() { + if (context == null) + return null; + @SuppressWarnings({ "rawtypes", "unchecked" }) + ServiceTracker extensionRegistryTracker = new ServiceTracker(context, IExtensionRegistry.class.getName(), null); + extensionRegistryTracker.open(); + IExtensionRegistry result = (IExtensionRegistry) extensionRegistryTracker.getService(); + extensionRegistryTracker.close(); + return result; + } + + public void handleException(Throwable exception) { + logWarning(exception); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IClassResolver.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IClassResolver.java new file mode 100644 index 0000000000..a74fab53cb --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IClassResolver.java @@ -0,0 +1,24 @@ +/**************************************************************************** + * Copyright (c) 2015 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.ObjectStreamClass; + +/** + * @since 3.7 + */ +public interface IClassResolver { + + public static final String BUNDLE_PROP_NAME = "org.eclipse.ecf.core.util.classresolver.bundleSymbolicName"; //$NON-NLS-1$ + + public Class resolveClass(ObjectStreamClass desc) throws ClassNotFoundException; +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IContainerFilter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IContainerFilter.java new file mode 100644 index 0000000000..0d566db8ce --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IContainerFilter.java @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import org.eclipse.ecf.core.IContainer; + +/** + * Container filter contract. Classes implementing this interface + * will define specific rules for whether or not a the given container + * matches some set of criteria...e.g. whether the container is + * currently connected or not. + */ +public interface IContainerFilter { + + /** + * Match a given containerToMatch against some set of implementation-defined criteria. + * @param containerToMatch the containerToMatch. Will not be null. + * @return boolean true if the given containerToMatch fulfills some + * implementation-dependent criteria. false if not. + */ + public boolean match(IContainer containerToMatch); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IDFactoryTracker.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IDFactoryTracker.java new file mode 100644 index 0000000000..333c9fa720 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IDFactoryTracker.java @@ -0,0 +1,38 @@ +/**************************************************************************** + * Copyright (c) 2009 EclipseSource and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import org.eclipse.ecf.core.identity.IIDFactory; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * Service tracker customized to handle tracking the ECF id factory service + * (singleton). + * + * @since 3.1 + * + */ +@SuppressWarnings("rawtypes") +public class IDFactoryTracker extends ServiceTracker { + + @SuppressWarnings("unchecked") + public IDFactoryTracker(BundleContext context) { + super(context, IIDFactory.class.getName(), null); + } + + public IIDFactory getIDFactory() { + return (IIDFactory) getService(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IEventProcessor.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IEventProcessor.java new file mode 100644 index 0000000000..fd8ba2f0d3 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IEventProcessor.java @@ -0,0 +1,32 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +/** + * Event processor for processing events in a sequence. If the implementer of this interface + * intends to prevent further processing for the given event, then it should return true + * to prevent further processing. It should return false to allow further processing of + * the given event to continue (e.g. in a chain of event processors) + * + */ +public interface IEventProcessor { + /** + * Process given Event + * + * @param event + * the Event to process + * @return true if the event has been successfully processed and no further + * processing should occur. False if the event should receive + * further processing by another event processor (e.g. in a chain) + */ + public boolean processEvent(Event event); +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IExceptionHandler.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IExceptionHandler.java new file mode 100644 index 0000000000..6aa6ce102b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/IExceptionHandler.java @@ -0,0 +1,27 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import org.eclipse.core.runtime.IStatus; + +/** + * Contract for general exception handler + */ +public interface IExceptionHandler { + + /** + * Handle given exception + * @param exception the exception to handle. If null, no exception occurred. + * @return IStatus any status to return as part of asynchronous job. Should not be null. + */ + public IStatus handleException(Throwable exception); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/LogHelper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/LogHelper.java new file mode 100644 index 0000000000..c08b945d98 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/LogHelper.java @@ -0,0 +1,58 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import java.util.Arrays; + +import org.eclipse.core.runtime.IStatus; +import org.osgi.service.log.LogService; + +public class LogHelper { + + public static int getLogCode(IStatus status) { + switch (status.getCode()) { + case IStatus.CANCEL : + return LogService.LOG_INFO; + case IStatus.ERROR : + return LogService.LOG_ERROR; + case IStatus.INFO : + return LogService.LOG_INFO; + case IStatus.OK : + return LogService.LOG_INFO; + case IStatus.WARNING : + return LogService.LOG_WARNING; + default : + return IStatus.INFO; + } + } + + /** + * @param status + * @return String the string version of the status + */ + public static String getLogMessage(IStatus status) { + if (status == null) + return ""; //$NON-NLS-1$ + StringBuilder buf = new StringBuilder(status.getClass().getName() + '['); + buf.append("plugin=").append(status.getPlugin()); //$NON-NLS-1$ + buf.append(";code=").append(status.getCode()); //$NON-NLS-1$ + buf.append(";message=").append(status.getMessage()); //$NON-NLS-1$ + buf.append(";severity").append(status.getSeverity()); //$NON-NLS-1$ + buf.append(";exception=").append(status.getException()); //$NON-NLS-1$ + buf.append(";children=").append(Arrays.asList(status.getChildren())) //$NON-NLS-1$ + .append(']'); + return buf.toString(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectInputStream.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectInputStream.java new file mode 100644 index 0000000000..c2057b6deb --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectInputStream.java @@ -0,0 +1,446 @@ +/**************************************************************************** + * Copyright (c) 2018, 2020 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import org.osgi.framework.Bundle; +import org.osgi.framework.Version; +import org.osgi.service.log.LogService; + +/** + * @since 3.9 + */ +public class OSGIObjectInputStream extends ObjectInputStream implements OSGIObjectStreamConstants { + + protected ObjectInputStream in; + protected final Bundle b; + protected LogService logger; + + /** + * @since 3.10 + */ + ClassLoader classLoader; + + class ReplaceableObjectInputStream extends ObjectInputStream { + public ReplaceableObjectInputStream(InputStream ins) throws IOException { + super(ins); + enableResolveObject(true); + } + + @Override + protected Object resolveObject(Object obj) throws IOException { + if (obj instanceof SerVersion) { + return ((SerVersion) obj).toVersion(); + } + if (obj instanceof SerDTO) { + SerDTO serDTO = (SerDTO) obj; + String className = serDTO.getClassname(); + Class clazz = null; + try { + clazz = loadClass(className); + } catch (Exception e) { + throw new IOException("Could not load class for instance of SerDTO with className=" + className); //$NON-NLS-1$ + } + return serDTO.readObject(clazz); + } + return super.resolveObject(obj); + } + + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + try { + return loadClass(desc.getName()); + } catch (Exception e) { + return super.resolveClass(desc); + } + } + } + + public OSGIObjectInputStream(Bundle b, InputStream in, LogService logger) throws IOException { + super(); + this.b = b; + this.in = new ReplaceableObjectInputStream(in); + this.logger = logger; + } + + public OSGIObjectInputStream(Bundle b, InputStream in) throws IOException { + this(b, in, null); + } + + /** + * @since 3.10 + */ + public void setClassLoader(ClassLoader cl) { + this.classLoader = cl; + } + + public void setLogService(LogService log) { + this.logger = log; + } + + @SuppressWarnings("deprecation") + protected void trace(String message) { + LogService ls = this.logger; + if (ls != null) { + ls.log(LogService.LOG_DEBUG, message); + } + } + + protected Class loadClass(String classname) throws ClassNotFoundException { + ClassLoader cl = this.classLoader; + Bundle bundle = b; + if (cl != null) { + try { + return Class.forName(classname, false, cl); + } catch (Exception e) { + // Try bundle loading + } + } + return (bundle == null) ? Class.forName(classname) : bundle.loadClass(classname); + } + + protected Class getClassForType(String type) throws ClassNotFoundException { + if (type.equals(byte.class.getName())) + return byte.class; + else if (type.equals(long.class.getName())) + return long.class; + else if (type.equals(int.class.getName())) + return int.class; + else if (type.equals(short.class.getName())) + return short.class; + else if (type.equals(char.class.getName())) + return char.class; + else if (type.equals(boolean.class.getName())) + return boolean.class; + else if (type.equals(float.class.getName())) + return float.class; + else if (type.equals(double.class.getName())) + return double.class; + else + return loadClass(type); + } + + protected final Object readObjectOverride() throws IOException, ClassNotFoundException { + final byte type = in.readByte(); + switch (type) { + case C_NULL : // null + return null; + case C_SER : // Serializable + return readSerializedObject(); + case C_VER : // Version + return Version.parseVersion(in.readUTF()); + case C_ARRAY : // Object[] + // read array length + int ol = in.readInt(); + // read component type and create array for that component type + Class clazz = getClassForType(in.readUTF()); + Object oresult = Array.newInstance(clazz, ol); + for (int i = 0; i < ol; i++) + Array.set(oresult, i, readObjectOverride()); + return oresult; + case C_DICT : // Dictionary + Class dictClazz = loadClass(in.readUTF()); + Dictionary dict = null; + Constructor cons; + try { + cons = dictClazz.getDeclaredConstructor((Class[]) null); + cons.setAccessible(true); + dict = (Dictionary) cons.newInstance((Object[]) null); + } catch (Exception e) { + throw new IOException("Could not create dictionary instance of clazz=" + dictClazz.getName()); //$NON-NLS-1$ + } + int dsize = in.readInt(); + for (int i = 0; i < dsize; i++) { + Object key = readObjectOverride(); + Object val = readObjectOverride(); + dict.put(key, val); + } + return dict; + case C_MAP : // Map + // read map length + int ms = in.readInt(); + Map mr = new HashMap(); + for (int i = 0; i < ms; i++) { + Object key = readObjectOverride(); + Object val = readObjectOverride(); + mr.put(key, val); + } + return mr; + case C_LIST : // List + int lsize = in.readInt(); + List l = new ArrayList(lsize); + for (int i = 0; i < lsize; i++) + l.add(readObjectOverride()); + return l; + case C_SET : // Set + int ssize = in.readInt(); + Set s = new HashSet(ssize); + for (int i = 0; i < ssize; i++) + s.add(readObjectOverride()); + return s; + case C_COLL : // Collection + int csize = in.readInt(); + Collection c = new ArrayList(csize); + for (int i = 0; i < csize; i++) + c.add(readObjectOverride()); + return c; + case C_ITER : // Iterable + int isize = in.readInt(); + List itr = new ArrayList(isize); + for (int i = 0; i < isize; i++) + itr.add(readObjectOverride()); + return itr; + case C_EXTER : // Externalizable + return in.readObject(); + case C_STRING : // String + return in.readUTF(); + case C_LONG : + case C_OLONG : + return in.readLong(); + case C_INT : + case C_OINT : + return in.readInt(); + case C_SHORT : + case C_OSHORT : + return in.readShort(); + case C_BOOL : + case C_OBOOL : + return in.readBoolean(); + case C_BYTE : + case C_OBYTE : + return in.readByte(); + case C_CHAR : + case C_OCHAR : + return in.readChar(); + case C_DOUBLE : + case C_ODOUBLE : + return in.readDouble(); + case C_FLOAT : + case C_OFLOAT : + return in.readFloat(); + case C_ENUM : + return Enum.valueOf(loadClass(in.readUTF()), in.readUTF()); + case C_OBJECT : + return readNonSerializedObject(); + default : + throw new IOException("Cannot deserialize object with type=" + type); //$NON-NLS-1$ + } + } + + protected Object readExternalizable() throws ClassNotFoundException, IOException { + return in.readObject(); + } + + protected Object readFields(Class clazz, Object inst) throws IOException { + try { + int fieldCount = in.readInt(); + while (fieldCount > -1) { + for (int i = 0; i < fieldCount; i++) { + final String fieldName = in.readUTF(); + final Field field = clazz.getDeclaredField(fieldName); + final int mod = field.getModifiers(); + if (!Modifier.isPublic(mod)) + field.setAccessible(true); + + // + final Object value = readObjectOverride(); + field.set(inst, value); + } + clazz = clazz.getSuperclass(); + fieldCount = in.readInt(); + } + return inst; + } catch (final Exception e) { + IOException t = new IOException("Error while deserializing class=" + clazz.getName() + ": " + e.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ + t.setStackTrace(e.getStackTrace()); + throw t; + } + } + + protected Object createInstance(Class clazz) throws IOException { + try { + return clazz.getDeclaredConstructor().newInstance(); + } catch (Exception e) { + throw new IOException("Could create new instance of class=" + clazz.getName() + ". Class must have public no-arg constructor"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + protected Object readNonSerializedObject() throws IOException, ClassNotFoundException { + // read object stream class + String className = in.readUTF(); + trace("readNonSerializedObject " + className); //$NON-NLS-1$ + Class clazz = loadClass(className); + // create instance + Object instance = createInstance(clazz); + return readFields(clazz, instance); + } + + protected Object readSerializedObject() throws IOException, ClassNotFoundException { + return in.readObject(); + } + + /** + * + * @see java.io.ObjectInputStream#read() + */ + public final int read() throws IOException { + return in.read(); + } + + /** + * + * @see java.io.ObjectInputStream#read(byte[], int, int) + */ + public final int read(final byte[] buf, final int off, final int len) throws IOException { + return in.read(buf, off, len); + } + + /** + * + * @see java.io.ObjectInputStream#available() + */ + public final int available() throws IOException { + return in.available(); + } + + /** + * + * @see java.io.ObjectInputStream#close() + */ + public final void close() throws IOException { + in.close(); + } + + /** + * + * @see java.io.ObjectInputStream#readBoolean() + */ + public final boolean readBoolean() throws IOException { + return in.readBoolean(); + } + + /** + * + * @see java.io.ObjectInputStream#readByte() + */ + public final byte readByte() throws IOException { + return in.readByte(); + } + + /** + * + * @see java.io.ObjectInputStream#readUnsignedByte() + */ + public final int readUnsignedByte() throws IOException { + return in.readUnsignedByte(); + } + + /** + * + * @see java.io.ObjectInputStream#readChar() + */ + public final char readChar() throws IOException { + return in.readChar(); + } + + /** + * + * @see java.io.ObjectInputStream#readShort() + */ + public final short readShort() throws IOException { + return in.readShort(); + } + + /** + * + * @see java.io.ObjectInputStream#readUnsignedShort() + */ + public final int readUnsignedShort() throws IOException { + return in.readUnsignedShort(); + } + + /** + * + * @see java.io.ObjectInputStream#readInt() + */ + public final int readInt() throws IOException { + return in.readInt(); + } + + /** + * + * @see java.io.ObjectInputStream#readLong() + */ + public final long readLong() throws IOException { + return in.readLong(); + } + + /** + * + * @see java.io.ObjectInputStream#readFloat() + */ + public final float readFloat() throws IOException { + return in.readFloat(); + } + + /** + * + * @see java.io.ObjectInputStream#readDouble() + */ + public final double readDouble() throws IOException { + return in.readDouble(); + } + + /** + * + * @see java.io.ObjectInputStream#readFully(byte[]) + */ + public final void readFully(final byte[] buf) throws IOException { + in.readFully(buf); + } + + /** + * + * @see java.io.ObjectInputStream#readFully(byte[], int, int) + */ + public final void readFully(final byte[] buf, final int off, final int len) throws IOException { + in.readFully(buf, off, len); + } + + /** + * + * @see java.io.ObjectInputStream#skipBytes(int) + */ + public final int skipBytes(final int len) throws IOException { + return in.skipBytes(len); + } + + /** + * @return String + * @throws IOException + * @deprecated + */ + public final String readLine() throws IOException { + return in.readLine(); + } + + /** + * + * @see java.io.ObjectInputStream#readUTF() + */ + public final String readUTF() throws IOException { + return in.readUTF(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectOutputStream.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectOutputStream.java new file mode 100644 index 0000000000..c6ab29cd74 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectOutputStream.java @@ -0,0 +1,446 @@ +/**************************************************************************** + * Copyright (c) 2018 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import org.osgi.framework.Version; +import org.osgi.service.log.LogService; + +/** + * @since 3.9 + */ +public class OSGIObjectOutputStream extends ObjectOutputStream implements OSGIObjectStreamConstants { + + protected final ObjectOutputStream out; + protected LogService logger; + protected boolean allowNonSerializable = false; + + class ReplaceableObjectOutputStream extends ObjectOutputStream { + + public ReplaceableObjectOutputStream(OutputStream out) throws IOException { + super(out); + enableReplaceObject(true); + } + + @Override + protected Object replaceObject(Object obj) throws IOException { + if (obj instanceof Version) { + return new SerVersion(((Version) obj)); + } else if (!(obj instanceof Serializable)) { + return new SerDTO(obj); + } + return super.replaceObject(obj); + } + } + + public OSGIObjectOutputStream(OutputStream out, boolean allowNonSerializable, LogService log) throws IOException { + super(); + this.out = new ReplaceableObjectOutputStream(out); + this.allowNonSerializable = allowNonSerializable; + this.logger = log; + } + + public OSGIObjectOutputStream(OutputStream out, boolean allowNonSerializable) throws IOException { + this(out, allowNonSerializable, null); + } + + public OSGIObjectOutputStream(OutputStream out) throws IOException { + this(out, false, null); + } + + public void setAllowNonSerializable(boolean value) { + this.allowNonSerializable = value; + } + + public void setLogService(LogService log) { + this.logger = log; + } + + protected void writeExternalizable(Externalizable obj, Class clazz) throws IOException { + out.writeObject(obj); + } + + @SuppressWarnings("deprecation") + protected void trace(String message) { + LogService ls = this.logger; + if (ls != null) { + ls.log(LogService.LOG_DEBUG, message); + } + } + + protected void writeFields(Object obj, Class clazz) throws IOException { + while (clazz != Object.class) { + try { + final Field[] allFields = clazz.getDeclaredFields(); + final int allFieldCount = allFields.length; + int actualFieldCount = 0; + for (int i = 0; i < allFieldCount; i++) { + final int mod = allFields[i].getModifiers(); + if (!(Modifier.isStatic(mod) || Modifier.isTransient(mod))) + actualFieldCount++; + } + // write field count + out.writeInt(actualFieldCount); + for (int i = 0; i < allFieldCount; i++) { + final int mod = allFields[i].getModifiers(); + if (Modifier.isStatic(mod) || Modifier.isTransient(mod)) + continue; + else if (!Modifier.isPublic(mod)) + allFields[i].setAccessible(true); + Object val = allFields[i].get(obj); + // Check to see it's not a circular ref + if (val != obj) { + // write field name + out.writeUTF(allFields[i].getName()); + // field value + writeObjectOverride(val); + } + } + } catch (final Exception e) { + throw new NotSerializableException("Exception while serializing " + obj.toString() //$NON-NLS-1$ + + ":\n" + e.getMessage()); //$NON-NLS-1$ + } + clazz = clazz.getSuperclass(); + } + // Write out a terminator so reader can detect end of object + out.writeInt(-1); + } + + protected void writeNonSerializable(Object obj, Class clazz) throws IOException { + // write class name + out.writeObject(clazz.getName()); + writeFields(obj, clazz); + } + + protected void writeSerializable(Object obj, Class clazz) throws IOException { + out.writeObject(obj); + } + + @Override + protected void writeObjectOverride(Object obj) throws IOException { + if (obj == null) { + out.writeByte(C_NULL); + return; + } + Class clazz = obj.getClass(); + if (clazz.isArray()) { + out.writeByte(C_ARRAY); + int len = Array.getLength(obj); + // write length + out.writeInt(len); + // write component type + out.writeUTF(clazz.getComponentType().getName()); + // write out each array entry + for (int i = 0; i < len; i++) + writeObjectOverride(Array.get(obj, i)); + return; + } else if (obj instanceof Long) { + if (clazz.isPrimitive()) { + out.writeByte(C_LONG); + } else { + out.writeByte(C_OLONG); + } + out.writeLong((Long) obj); + return; + } else if (obj instanceof Integer) { + if (clazz.isPrimitive()) { + out.writeByte(C_INT); + } else { + out.writeByte(C_OINT); + } + out.writeInt((Integer) obj); + return; + } else if (obj instanceof Short) { + if (clazz.isPrimitive()) { + out.writeByte(C_SHORT); + } else { + out.writeByte(C_OSHORT); + } + out.writeShort((Short) obj); + return; + } else if (obj instanceof Boolean) { + if (clazz.isPrimitive()) { + out.writeByte(C_BOOL); + } else { + out.writeByte(C_OBOOL); + } + out.writeBoolean((Boolean) obj); + return; + } else if (obj instanceof Byte) { + if (clazz.isPrimitive()) { + out.writeByte(C_BYTE); + } else { + out.writeByte(C_OBYTE); + } + out.writeByte((Byte) obj); + return; + } else if (obj instanceof Character) { + if (clazz.isPrimitive()) { + out.writeByte(C_CHAR); + } else { + out.writeByte(C_OCHAR); + } + out.writeChar((Character) obj); + return; + } else if (obj instanceof Float) { + if (clazz.isPrimitive()) { + out.writeByte(C_FLOAT); + } else { + out.writeByte(C_OFLOAT); + } + out.writeFloat((Float) obj); + return; + } else if (obj instanceof Double) { + if (clazz.isPrimitive()) { + out.writeByte(C_DOUBLE); + } else { + out.writeByte(C_ODOUBLE); + } + out.writeDouble((Double) obj); + return; + } else if (obj instanceof String) { + out.writeByte(C_STRING); + out.writeUTF((String) obj); + return; + } else if (obj instanceof Dictionary) { + trace("writing dictionary"); //$NON-NLS-1$ + out.writeByte(C_DICT); + out.writeUTF(clazz.getName()); + Dictionary dict = (Dictionary) obj; + // write size + int ds = dict.size(); + out.writeInt(ds); + // for each element in Map + for (Enumeration e = dict.keys(); e.hasMoreElements();) { + Object key = e.nextElement(); + writeObjectOverride(key); + writeObjectOverride(dict.get(key)); + } + return; + } else if (obj instanceof Map) { + out.writeByte(C_MAP); + Map map = (Map) obj; + // write size + int size = map.size(); + out.writeInt(size); + // for each element in Map + for (Object key : map.keySet()) { + // Write key + writeObjectOverride(key); + // Write value + writeObjectOverride(map.get(key)); + } + return; + } else if (obj instanceof List) { + out.writeByte(C_LIST); + List list = (List) obj; + // write size + int size = list.size(); + out.writeInt(size); + // write each element + for (Object item : list) + writeObjectOverride(item); + return; + } else if (obj instanceof Set) { + out.writeByte(C_SET); + Set set = (Set) obj; + // write size + int size = set.size(); + out.writeInt(size); + // then elements + for (Object item : set) + writeObjectOverride(item); + return; + } else if (obj instanceof Collection) { + out.writeByte(C_COLL); + Collection col = (Collection) obj; + // write size + int size = col.size(); + out.writeInt(size); + // then elements + for (Object item : col) + writeObjectOverride(item); + return; + } else if (obj instanceof Iterable) { + out.writeByte(C_ITER); + Iterable itr = (Iterable) obj; + int size = 0; + // Get size + for (@SuppressWarnings("unused") + Object v : itr) + size++; + // write size + out.writeInt(size); + // write elements + for (Object item : itr) + writeObjectOverride(item); + return; + } else if (obj instanceof Enum) { + out.writeByte(C_ENUM); + out.writeUTF(obj.getClass().getName()); + out.writeUTF(((Enum) obj).name()); + return; + } + if (obj instanceof Externalizable) { + out.writeByte(C_EXTER); + writeExternalizable((Externalizable) obj, clazz); + } else if (obj instanceof Serializable) { + out.writeByte(C_SER); + writeSerializable(obj, clazz); + return; + } else if (obj instanceof Version) { + writeObjectOverride(new SerVersion((Version) obj)); + } else { + writeObjectOverride(new SerDTO(obj)); + return; + } + } + + /** + * + * @see java.io.ObjectOutputStream#write(int) + */ + public final void write(final int val) throws IOException { + out.write(val); + } + + /** + * + * @see java.io.ObjectOutputStream#write(byte[]) + */ + public final void write(final byte[] buf) throws IOException { + out.write(buf); + } + + /** + * + * @see java.io.ObjectOutputStream#write(byte[], int, int) + */ + public final void write(final byte[] buf, final int off, final int len) throws IOException { + out.write(buf, off, len); + } + + /** + * + * @see java.io.ObjectOutputStream#flush() + */ + public final void flush() throws IOException { + out.flush(); + } + + /** + * + * @see java.io.ObjectOutputStream#reset() + */ + public final void reset() throws IOException { + out.reset(); + } + + /** + * + * @see java.io.ObjectOutputStream#close() + */ + public final void close() throws IOException { + out.close(); + } + + /** + * + * @see java.io.ObjectOutputStream#writeBoolean(boolean) + */ + public final void writeBoolean(final boolean val) throws IOException { + out.writeBoolean(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeByte(int) + */ + public final void writeByte(final int val) throws IOException { + out.writeByte(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeShort(int) + */ + public final void writeShort(final int val) throws IOException { + out.writeShort(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeChar(int) + */ + public final void writeChar(final int val) throws IOException { + out.writeChar(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeInt(int) + */ + public final void writeInt(final int val) throws IOException { + out.writeInt(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeLong(long) + */ + public final void writeLong(final long val) throws IOException { + out.writeLong(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeFloat(float) + */ + public final void writeFloat(final float val) throws IOException { + out.writeFloat(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeDouble(double) + */ + public final void writeDouble(final double val) throws IOException { + out.writeDouble(val); + } + + /** + * + * @see java.io.ObjectOutputStream#writeBytes(java.lang.String) + */ + public final void writeBytes(final String str) throws IOException { + out.writeBytes(str); + } + + /** + * + * @see java.io.ObjectOutputStream#writeChars(java.lang.String) + */ + public final void writeChars(final String str) throws IOException { + out.writeChars(str); + } + + /** + * + * @see java.io.ObjectOutputStream#writeUTF(java.lang.String) + */ + public final void writeUTF(final String str) throws IOException { + out.writeUTF(str); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectStreamConstants.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectStreamConstants.java new file mode 100644 index 0000000000..7163854ba0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/OSGIObjectStreamConstants.java @@ -0,0 +1,55 @@ +/**************************************************************************** + * Copyright (c) 2018 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +/** + * @since 3.9 + */ +public interface OSGIObjectStreamConstants { + + public static final byte C_NULL = 0; // null + public static final byte C_SER = 1; // Serializable + public static final byte C_VER = 2; // Version + public static final byte C_ARRAY = 3; // array + public static final byte C_DTO = 4; // DTO + public static final byte C_MAP = 5; // Map + public static final byte C_LIST = 6; // List + public static final byte C_SET = 7; // Set + public static final byte C_COLL = 8; // Collection + public static final byte C_ITER = 9; // Iterable + public static final byte C_EXTER = 10; // Externalizable + public static final byte C_STRING = 11; // String + public static final byte C_ENUM = 12; // Enum + public static final byte C_OBJECT = 13; // Everything else + public static final byte C_DICT = 14; // Dictionary + + // primitive types + public static final byte C_LONG = 20; // primitive long + public static final byte C_INT = 21; // primitive int + public static final byte C_SHORT = 22; // prim short + public static final byte C_BOOL = 23; // prim boolean + public static final byte C_BYTE = 24; // prim byte + public static final byte C_CHAR = 25; // primp character + public static final byte C_DOUBLE = 26; // prim double + public static final byte C_FLOAT = 27; // prim float + + // simple object types + public static final byte C_OLONG = 30; // Long + public static final byte C_OINT = 31; // Integer + public static final byte C_OSHORT = 32; // Short + public static final byte C_OBOOL = 33; // Boolean + public static final byte C_OBYTE = 34; // Byte + public static final byte C_OCHAR = 35; // Character + public static final byte C_ODOUBLE = 36; // Double + public static final byte C_OFLOAT = 37; // Float + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/PlatformHelper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/PlatformHelper.java new file mode 100644 index 0000000000..b6b8998bd6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/PlatformHelper.java @@ -0,0 +1,109 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import java.lang.reflect.Method; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.internal.core.identity.Activator; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +/** + * Helper class for eliminating direct references to Platform static methods + * getAdapterManager and getExtensionRegistry. Note that instead of + * Platform.getAdapterManager(), clients can call + * PlatformHelper.getAdapterManager(). If this returns null, the Platform class + * is not available. + */ +public class PlatformHelper { + + @SuppressWarnings("rawtypes") + private static Class platformClass = null; + + private static IAdapterManager adapterManagerCache = null; + + private static IExtensionRegistry extensionRegistryCache = null; + + static { + Activator a = Activator.getDefault(); + if (a != null) { + try { + BundleContext c = a.getBundleContext(); + if (c != null) { + Bundle[] bundles = c.getBundles(); + Bundle coreRuntime = null; + for (Bundle bundle : bundles) { + if (bundle.getSymbolicName().equals("org.eclipse.core.runtime")) { //$NON-NLS-1$ + coreRuntime = bundle; + platformClass = coreRuntime.loadClass("org.eclipse.core.runtime.Platform"); //$NON-NLS-1$ + break; + } + } + } + } catch (Exception e) { + // Platform not available...just leave platformClass == null and + // log + // as error + try { + a.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, + "Cannot load Platform class", //$NON-NLS-1$ + e)); + } catch (Throwable t) { + // Should never happen, if does irrecoverable + } + } + } + } + + public synchronized static boolean isPlatformAvailable() { + return platformClass != null; + } + + public synchronized static IAdapterManager getPlatformAdapterManager() { + if (adapterManagerCache != null) + return adapterManagerCache; + if (isPlatformAvailable()) { + try { + @SuppressWarnings("unchecked") + Method m = platformClass.getMethod("getAdapterManager", (Class[]) null); //$NON-NLS-1$ + adapterManagerCache = (IAdapterManager) m.invoke(null, (Object[]) null); + return adapterManagerCache; + } catch (Exception e) { + Activator.getDefault().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, + "Cannot get PlatformAdapterManager()", e)); //$NON-NLS-1$ + return null; + } + } + return null; + } + + public synchronized static IExtensionRegistry getExtensionRegistry() { + if (extensionRegistryCache != null) + return extensionRegistryCache; + if (isPlatformAvailable()) { + try { + @SuppressWarnings("unchecked") + Method m = platformClass.getMethod("getExtensionRegistry", (Class[]) null); //$NON-NLS-1$ + extensionRegistryCache = (IExtensionRegistry) m.invoke(null, (Object[]) null); + return extensionRegistryCache; + } catch (Exception e) { + Activator.getDefault().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, + "Cannot get PlatformExtensionRegistry()", e)); //$NON-NLS-1$ + return null; + } + + } + return null; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Proxy.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Proxy.java new file mode 100644 index 0000000000..8b99e8520d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Proxy.java @@ -0,0 +1,149 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import java.io.ObjectStreamException; +import java.io.Serializable; + +public class Proxy implements Serializable { + + private static final long serialVersionUID = -2481483596779542834L; + + public static class Type implements Serializable { + + private static final long serialVersionUID = 361071073081975271L; + + private static final String DIRECT_NAME = "direct"; //$NON-NLS-1$ + + private static final String HTTP_NAME = "http"; //$NON-NLS-1$ + + private static final String SOCKS_NAME = "socks"; //$NON-NLS-1$ + + private final transient String name; + + protected Type(String name) { + this.name = name; + } + + public static final Type DIRECT = new Type(DIRECT_NAME); + + public static final Type HTTP = new Type(HTTP_NAME); + + public static final Type SOCKS = new Type(SOCKS_NAME); + + public static Type fromString(String type) { + if (type == null) + return null; + else if (type.equals(DIRECT_NAME)) + return DIRECT; + else if (type.equals(HTTP_NAME)) + return HTTP; + else if (type.equals(SOCKS_NAME)) + return SOCKS; + else + return null; + } + + public String toString() { + return name; + } + + // For serialization + private static int nextOrdinal = 0; + + private final int ordinal = nextOrdinal++; + + private static final Type[] VALUES = {DIRECT, HTTP, SOCKS}; + + /** + * @return Object + * @throws ObjectStreamException not thrown by this implementation. + */ + Object readResolve() throws ObjectStreamException { + return VALUES[ordinal]; + } + } + + ProxyAddress address; + + Type type; + + String username; + + String password; + + public final static Proxy NO_PROXY = new Proxy(); + + private Proxy() { + this.type = Type.DIRECT; + this.address = null; + } + + public Proxy(Type type, ProxyAddress address, String username, String password) { + this.type = type; + this.address = address; + this.username = username; + this.password = password; + } + + public Proxy(Type type, ProxyAddress address) { + this(type, address, null, null); + } + + public Type getType() { + return type; + } + + public ProxyAddress getAddress() { + return address; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public boolean hasCredentials() { + return (username != null && !username.equals("")); //$NON-NLS-1$ + } + + public String toString() { + if (getType() == Type.DIRECT) + return "DIRECT"; //$NON-NLS-1$ + return getType() + " @ " + getAddress(); //$NON-NLS-1$ + } + + public final boolean equals(Object obj) { + if (obj == null || !(obj instanceof Proxy)) + return false; + Proxy p = (Proxy) obj; + if (p.getType() == getType()) { + if (getAddress() == null) { + return (p.getAddress() == null); + } + return getAddress().equals(p.getAddress()); + } + return false; + } + + public final int hashCode() { + if (getAddress() == null) + return getType().hashCode(); + return getType().hashCode() + getAddress().hashCode(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ProxyAddress.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ProxyAddress.java new file mode 100644 index 0000000000..d393ac1819 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/ProxyAddress.java @@ -0,0 +1,71 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import java.io.Serializable; + +/** + * Class to represent an proxy address + */ +public class ProxyAddress implements Serializable { + + private static final long serialVersionUID = 9076207407726734246L; + + protected static final int DEFAULT_PORT = -1; + + protected int port = -1; + protected String hostname = ""; //$NON-NLS-1$ + + public ProxyAddress(String hostname, int port) { + this.hostname = (hostname == null) ? "" : hostname; //$NON-NLS-1$ + this.port = port; + } + + public ProxyAddress(String hostname) { + this(hostname, DEFAULT_PORT); + } + + public String getHostName() { + return this.hostname; + } + + public int getPort() { + return this.port; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (obj == null || this.hostname == null) + return false; + if (!(obj instanceof ProxyAddress)) + return false; + ProxyAddress other = (ProxyAddress) obj; + return (this.hostname.equals(other.hostname) && this.port == other.port); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + if (this.hostname == null) + return super.hashCode(); + return this.hostname.hashCode() ^ Math.abs(this.port); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerDTO.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerDTO.java new file mode 100644 index 0000000000..8768884554 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerDTO.java @@ -0,0 +1,79 @@ +/**************************************************************************** + * Copyright (c) 2021 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; + +/** + * @since 3.10 + */ +public class SerDTO implements Serializable { + + private static final long serialVersionUID = -1739849704193630352L; + private String className; + private Map fields; + + public SerDTO(Object obj) { + Class clazz = obj.getClass(); + this.className = clazz.getName(); + this.fields = new HashMap(); + for (Field f : clazz.getFields()) { + final int mod = f.getModifiers(); + if (Modifier.isStatic(mod) || Modifier.isTransient(mod)) + continue; + Object value = null; + try { + value = f.get(obj); + } catch (Exception e) { + // + } + if (value != null) { + fields.put(f.getName(), value); + } + } + } + + public String getClassname() { + return this.className; + } + + public Map getFields() { + return fields; + } + + public Object readObject(Class clazz) throws IOException { + Object result = null; + try { + result = clazz.getConstructor(new Class[] {}).newInstance(); + for (Field f : clazz.getFields()) { + Object v = fields.get(f.getName()); + if (v != null) { + f.setAccessible(true); + try { + f.set(result, v); + } catch (Exception e) { + // ignore + } + } + } + } catch (Throwable e) { + throw new IOException("Unexpected exception reading DTO in SerDTO.readObject: " + e.getLocalizedMessage()); //$NON-NLS-1$ + } + return result; + + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerVersion.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerVersion.java new file mode 100644 index 0000000000..dd20c732cd --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SerVersion.java @@ -0,0 +1,31 @@ +/**************************************************************************** + * Copyright (c) 2021 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.io.Serializable; +import org.osgi.framework.Version; + +/** + * @since 3.10 + */ +public final class SerVersion implements Serializable { + private static final long serialVersionUID = 4785952431053485808L; + private String versionStr; + + public SerVersion(Version v) { + this.versionStr = v.toString(); + } + + public Version toVersion() { + return Version.parseVersion(this.versionStr); + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/StringUtils.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/StringUtils.java new file mode 100644 index 0000000000..0da7507c4f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/StringUtils.java @@ -0,0 +1,310 @@ +/**************************************************************************** + * Copyright (c) 2005, 2007 Remy Suen + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Remy Suen - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.util.ArrayList; + +/** + *

+ * The StringUtils class provides static methods that helps make string + * manipulation easy. The primary functionality it is meant to provide is the + * ability to split a string into a string array based on a given delimiter. + * This functionality is meant to take the place of the split(String) and + * split(String, int) method that was introduced in J2SE-1.4. Please note, + * however, that the splitting performed by this class simply splits the string + * based on the delimiter and does not perform any regular expression matching + * like the split methods provided in J2SE-1.4. + *

+ * + */ +public final class StringUtils { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static final String[] splitOnSpace(String string) { + int index = string.indexOf(' '); + if (index == -1) { + return new String[] { string }; + } + + ArrayList split = new ArrayList(); + while (index != -1) { + split.add(string.substring(0, index)); + string = string.substring(index + 1); + index = string.indexOf(' '); + } + + if (!string.equals("")) { //$NON-NLS-1$ + split.add(string); + } + + return (String[]) split.toArray(new String[split.size()]); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static final String[] split(String string, char character) { + int index = string.indexOf(character); + if (index == -1) { + return new String[] { string }; + } + + ArrayList split = new ArrayList(); + while (index != -1) { + split.add(string.substring(0, index)); + string = string.substring(index + 1); + index = string.indexOf(character); + } + + if (!string.equals("")) { //$NON-NLS-1$ + split.add(string); + } + + return (String[]) split.toArray(new String[split.size()]); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static final String[] split(String string, String delimiter) { + int index = string.indexOf(delimiter); + if (index == -1) { + return new String[] { string }; + } + + int length = delimiter.length(); + ArrayList split = new ArrayList(); + while (index != -1) { + split.add(string.substring(0, index)); + string = string.substring(index + length); + index = string.indexOf(delimiter); + } + + if (!string.equals("")) { //$NON-NLS-1$ + split.add(string); + } + + return (String[]) split.toArray(new String[split.size()]); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static final String[] split(String string, String delimiter, int limit) { + int index = string.indexOf(delimiter); + if (index == -1) { + return new String[] { string }; + } + + int count = 0; + int length = delimiter.length(); + ArrayList split = new ArrayList(limit); + while (index != -1 && count < limit - 1) { + split.add(string.substring(0, index)); + string = string.substring(index + length); + index = string.indexOf(delimiter); + count++; + } + + if (!string.equals("")) { //$NON-NLS-1$ + split.add(string); + } + + return (String[]) split.toArray(new String[split.size()]); + } + + public static final String splitSubstring(String string, String delimiter, int pos) { + int index = string.indexOf(delimiter); + if (index == -1) { + return string; + } + + int count = 0; + int length = delimiter.length(); + while (count < pos) { + string = string.substring(index + length); + index = string.indexOf(delimiter); + count++; + } + + return index == -1 ? string : string.substring(0, index); + } + + public static final String xmlDecode(String string) { + if (string.equals("")) { //$NON-NLS-1$ + return string; + } + + int index = string.indexOf("&"); //$NON-NLS-1$ + while (index != -1) { + string = string.substring(0, index) + '&' + string.substring(index + 5); + index = string.indexOf("&", index + 1); //$NON-NLS-1$ + } + + index = string.indexOf("""); //$NON-NLS-1$ + while (index != -1) { + string = string.substring(0, index) + '"' + string.substring(index + 6); + index = string.indexOf(""", index + 1); //$NON-NLS-1$ + } + + index = string.indexOf("'"); //$NON-NLS-1$ + while (index != -1) { + string = string.substring(0, index) + '\'' + string.substring(index + 6); + index = string.indexOf("'", index + 1); //$NON-NLS-1$ + } + + index = string.indexOf("<"); //$NON-NLS-1$ + while (index != -1) { + string = string.substring(0, index) + '<' + string.substring(index + 4); + index = string.indexOf("<", index + 1); //$NON-NLS-1$ + } + + index = string.indexOf(">"); //$NON-NLS-1$ + while (index != -1) { + string = string.substring(0, index) + '>' + string.substring(index + 4); + index = string.indexOf(">", index + 1); //$NON-NLS-1$ + } + return string; + } + + public static final String xmlEncode(String string) { + if (string.equals("")) { //$NON-NLS-1$ + return string; + } + + int index = string.indexOf('&'); + while (index != -1) { + string = string.substring(0, index) + "&" //$NON-NLS-1$ + + string.substring(index + 1); + index = string.indexOf('&', index + 1); + } + + index = string.indexOf('"'); + while (index != -1) { + string = string.substring(0, index) + """ //$NON-NLS-1$ + + string.substring(index + 1); + index = string.indexOf('"', index + 1); + } + + index = string.indexOf('\''); + while (index != -1) { + string = string.substring(0, index) + "'" //$NON-NLS-1$ + + string.substring(index + 1); + index = string.indexOf('\'', index + 1); + } + + index = string.indexOf('<'); + while (index != -1) { + string = string.substring(0, index) + "<" //$NON-NLS-1$ + + string.substring(index + 1); + index = string.indexOf('<', index + 1); + } + + index = string.indexOf('>'); + while (index != -1) { + string = string.substring(0, index) + ">" //$NON-NLS-1$ + + string.substring(index + 1); + index = string.indexOf('>', index + 1); + } + return string; + } + + /** + * Returns whether the first parameter contains the second parameter. + * + * @param string + * must not be . + * @param target + * must not be null. + * @return true if the target is contained within the string. + */ + public static boolean contains(String string, String target) { + return (string.contains(target)); + } + + /** + * Returns the string resulting from replacing all occurrences of the target + * with the replace string. Note that the target matches literally, and this + * is not the same behavior as the String.replaceAll, which uses regular + * expressions for doing the matching. + * + * @param string + * the start string. Must not be null. + * @param target + * the target to search for in the start string. Must not be + * null. + * @param replace + * the replacement string to substitute when the target is found. + * Must not be null. + * @return String result. Will not be null. If target is not + * found in the given string, then the result will be the entire + * input string. + */ + public static String replaceAll(String string, String target, String replace) { + final int index = string.indexOf(target); + if (index == -1) + return string; + return string.substring(0, index) + replace + + replaceAll(string.substring(index + target.length()), target, replace); + } + + /** + * Returns the string resulting from replacing all occurrences of the target + * with the replace string. Note that the target matches literally but + * ignoring the case, and this is not the same behavior as the + * String.replaceAll, which uses regular expressions for doing the matching. + * + * @param string + * the start string. Must not be null. + * @param target + * the target to search for in the start string. Must not be + * null. + * @param replace + * the replacement string to substitute when the target is found. + * Must not be null. + * @return String result. Will not be null. If target is not + * found in the given string, then the result will be the entire + * input string. + * + * @see StringUtils#replaceAll(String, String, String) but case insensitive + * @since 2.1 + */ + public static String replaceAllIgnoreCase(String string, String target, String replace) { + final int index = string.toLowerCase().indexOf(target.toLowerCase()); + if (index == -1) + return string; + return string.substring(0, index) + replace + + replaceAllIgnoreCase(string.substring(index + target.length()), target, replace); + } + + /** + * Returns the string resulting from replacing the first occurrences of the + * target with the replace string. Note that the target matches literally, + * and this is not the same behavior as the String.replaceAll, which uses + * regular expressions for doing the matching. + * + * @param string + * the start string. Must not be null. + * @param target + * the target to search for in the start string. Must not be + * null. + * @param replace + * the replacement string to substitute when the target is found. + * Must not be null. + * @return String result. Will not be null. If target is not + * found in the given string, then the result will be the entire + * input string. + * + * @since 3.0 + */ + public static String replaceFirst(String string, String target, String replace) { + final int index = string.indexOf(target); + if (index == -1) + return string; + return string.substring(0, index) + replace + string.substring(index + target.length()); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SystemLogService.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SystemLogService.java new file mode 100644 index 0000000000..636ffbe658 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/SystemLogService.java @@ -0,0 +1,125 @@ +/**************************************************************************** + * Copyright (c) 2007, 2018 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.core.util; + +import java.text.SimpleDateFormat; +import java.util.Date; +import org.osgi.framework.Bundle; +import org.osgi.framework.ServiceReference; +import org.osgi.service.log.LogService; + +/** + * + */ +public class SystemLogService implements LogService { + + private static final SimpleDateFormat dateFormat = new SimpleDateFormat("Z yyyy.MM.dd HH:mm:ss:S"); //$NON-NLS-1$ + + private final String pluginName; + + public SystemLogService(String pluginName) { + this.pluginName = pluginName; + } + + private static final String getLogCode(int level) { + switch (level) { + case LogService.LOG_INFO: + return "INFO"; //$NON-NLS-1$ + case LogService.LOG_ERROR: + return "ERROR"; //$NON-NLS-1$ + case LogService.LOG_DEBUG: + return "DEBUG"; //$NON-NLS-1$ + case LogService.LOG_WARNING: + return "WARNING"; //$NON-NLS-1$ + default: + return "UNKNOWN"; //$NON-NLS-1$ + } + } + + private final void doLog(@SuppressWarnings("rawtypes") ServiceReference sr, int level, String message, + Throwable t) { + final StringBuffer buf = new StringBuffer("[log;"); //$NON-NLS-1$ + buf.append(dateFormat.format(new Date())).append(";"); //$NON-NLS-1$ + buf.append(getLogCode(level)).append(";"); //$NON-NLS-1$ + if (sr != null) + buf.append(sr.getBundle().getSymbolicName()).append(";"); //$NON-NLS-1$ + else + buf.append(pluginName).append(";"); //$NON-NLS-1$ + buf.append(message).append("]"); //$NON-NLS-1$ + if (t != null) { + System.err.println(buf.toString()); + t.printStackTrace(System.err); + } else + System.out.println(buf.toString()); + } + + /* + * (non-Javadoc) + * + * @see org.osgi.service.log.LogService#log(int, java.lang.String) + */ + public void log(int level, String message) { + log(null, level, message, null); + } + + /* + * (non-Javadoc) + * + * @see org.osgi.service.log.LogService#log(int, java.lang.String, + * java.lang.Throwable) + */ + public void log(int level, String message, Throwable exception) { + doLog(null, level, message, exception); + } + + /* + * (non-Javadoc) + * + * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, + * int, java.lang.String) + */ + public void log(@SuppressWarnings("rawtypes") ServiceReference sr, int level, String message) { + log(sr, level, message, null); + } + + /* + * (non-Javadoc) + * + * @see org.osgi.service.log.LogService#log(org.osgi.framework.ServiceReference, + * int, java.lang.String, java.lang.Throwable) + */ + public void log(@SuppressWarnings("rawtypes") ServiceReference sr, int level, String message, Throwable exception) { + doLog(sr, level, message, exception); + } + + public org.osgi.service.log.Logger getLogger(String name) { + throw new UnsupportedOperationException(); + } + + public org.osgi.service.log.Logger getLogger(Class clazz) { + throw new UnsupportedOperationException(); + } + + public L getLogger(String name, Class loggerType) { + throw new UnsupportedOperationException(); + } + + public L getLogger(Class clazz, Class loggerType) { + throw new UnsupportedOperationException(); + } + + public L getLogger(Bundle bundle, String name, Class loggerType) { + throw new UnsupportedOperationException(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Trace.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Trace.java new file mode 100644 index 0000000000..f4612dabf6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/Trace.java @@ -0,0 +1,538 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util; + +import java.text.SimpleDateFormat; +import java.util.*; +import org.eclipse.ecf.internal.core.identity.Activator; +import org.eclipse.osgi.service.debug.DebugOptions; + +/** + * A utility for tracing debug information. Provides a simple interface for + * filtering and generating trace output. + * + */ +public class Trace { + + private static final boolean TRACEALL = Boolean + .getBoolean(System.getProperty("org.eclipse.ecf.core.util.traceAll", "false")); + + private static final List TRACE_BUNDLES = new ArrayList(); + + static { + if (!TRACEALL) { + String tracePlugins = System.getProperty("org.eclipse.ecf.core.util.traceBundles"); + if (tracePlugins != null) + try { + String[] plugins = tracePlugins.split(","); + TRACE_BUNDLES.addAll(Arrays.asList(plugins)); + } catch (Exception e) { + System.err.println("Unexpected exception in Trace class static initializer"); + e.printStackTrace(System.err); + } + } + } + + /** + * private constructor for the static class. + */ + private Trace() { + super(); + } + + /** + * String containing an open parenthesis. + * + */ + protected static final String PARENTHESIS_OPEN = "("; //$NON-NLS-1$ + + /** + * String containing a close parenthesis. + * + */ + protected static final String PARENTHESIS_CLOSE = ")"; //$NON-NLS-1$ + + /** + * String containing TRACE + * + */ + protected static final String TRACE_STR = "TRACE"; //$NON-NLS-1$ + + /** + * Prefix for tracing the changing of values. + * + */ + protected static final String PREFIX_TRACING = "TRACING "; //$NON-NLS-1$ + + /** + * Prefix for tracing the changing of values. + * + */ + protected static final String PREFIX_CHANGING = "CHANGING "; //$NON-NLS-1$ + + /** + * Prefix for tracing the catching of throwables. + * + */ + protected static final String PREFIX_CATCHING = "CAUGHT "; //$NON-NLS-1$ + + /** + * Prefix for tracing the throwing of throwables. + * + */ + protected static final String PREFIX_THROWING = "THROWN "; //$NON-NLS-1$ + + /** + * Prefix for tracing the entering of methods. + * + */ + protected static final String PREFIX_ENTERING = "ENTERING "; //$NON-NLS-1$ + + /** + * Prefix for tracing the exiting of methods. + * + */ + protected static final String PREFIX_EXITING = "EXITING "; //$NON-NLS-1$ + + /** + * Separator for methods. + * + */ + protected static final String SEPARATOR_METHOD = "#"; //$NON-NLS-1$ + + /** + * Separator for parameters. + * + */ + protected static final String SEPARATOR_PARAMETER = ", "; //$NON-NLS-1$ + + /** + * Separator for return values. + * + */ + protected static final String SEPARATOR_RETURN = ":"; //$NON-NLS-1$ + + /** + * Separator containing a space. + * + */ + protected static final String SEPARATOR_SPACE = " "; //$NON-NLS-1$ + + /** + * Label indicating old value. + * + */ + protected static final String LABEL_OLD_VALUE = "old="; //$NON-NLS-1$ + + /** + * Label indicating new value. + * + */ + protected static final String LABEL_NEW_VALUE = "new="; //$NON-NLS-1$ + + /** + * The cached debug options (for optimization). + */ + private static final Map cachedOptions = new HashMap(); + + /** + * Retrieves a Boolean value indicating whether tracing is enabled for the + * specified plug-in. + * + * @return Whether tracing is enabled for the plug-in. + * @param pluginId The symbolic plugin id for which to determine trace + * enablement. + * + */ + protected static boolean shouldTrace(String pluginId) { + return shouldTrace0(pluginId + "/debug"); //$NON-NLS-1$ + } + + protected static boolean shouldTrace0(String option) { + if (option == null) + return false; + Activator activator = Activator.getDefault(); + if (activator == null) + return false; + DebugOptions debugOptions = activator.getDebugOptions(); + if (debugOptions == null) + return false; + String result = debugOptions.getOption(option); + return (result == null) ? false : result.equalsIgnoreCase("true"); //$NON-NLS-1$ + } + + /** + * Retrieves a Boolean value indicating whether tracing is enabled for the + * specified debug option of the specified plug-in. + * + * @return Whether tracing is enabled for the debug option of the plug-in. + * @param pluginId The plug-in for which to determine trace enablement. + * @param option The debug option for which to determine trace enablement. + * + */ + public static boolean shouldTrace(String pluginId, String option) { + if (pluginId == null) + return false; + if (TRACEALL || TRACE_BUNDLES.contains(pluginId)) + return true; + if (shouldTrace(pluginId)) { + Boolean value = null; + + synchronized (cachedOptions) { + value = cachedOptions.get(option); + if (null == value) { + value = shouldTrace0(option); + cachedOptions.put(option, value); + } + } + + return value.booleanValue(); + } + + return false; + } + + /** + * Retrieves a textual representation of the specified argument. + * + * @return A textual representation of the specified argument. + * @param argument The argument for which to retrieve a textual + * representation. + * + */ + public static String getArgumentString(Object argument) { + if (argument == null) + return "null"; //$NON-NLS-1$ + if (argument instanceof byte[]) + return getStringFromByteArray((byte[]) argument); + if (argument.getClass().isArray()) + return getArgumentsString((Object[]) argument); + return String.valueOf(argument); + } + + private static String getStringFromByteArray(byte[] bytes) { + StringBuilder buf = new StringBuilder("["); //$NON-NLS-1$ + for (int i = 0; i < bytes.length; i++) { + buf.append(bytes[i]); + if (i == (bytes.length - 1)) + buf.append("]"); //$NON-NLS-1$ + else + buf.append(","); //$NON-NLS-1$ + } + return buf.toString(); + } + + /** + * Retrieves a textual representation of the specified arguments. + * + * @return A textual representation of the specified arguments. + * @param arguments The arguments for which to retrieve a textual + * representation. + * + */ + public static String getArgumentsString(Object[] arguments) { + if (arguments == null) + return "[]"; //$NON-NLS-1$ + StringBuilder buffer = new StringBuilder("["); //$NON-NLS-1$ + + for (int i = 0; i < arguments.length; i++) { + buffer.append(getArgumentString(arguments[i])); + + if (i < arguments.length - 1) + buffer.append(SEPARATOR_PARAMETER); + } + buffer.append("]"); //$NON-NLS-1$ + return buffer.toString(); + } + + /** + * Traces the specified message. + * + * @param message The message to be traced. + * + */ + protected static void trace(String message) { + StringBuilder buf = new StringBuilder(PARENTHESIS_OPEN); + buf.append(TRACE_STR).append(PARENTHESIS_CLOSE).append(getTimeString()).append(message).append(SEPARATOR_SPACE); + System.out.println(buf.toString()); + } + + /** + * Get date and time string + * + * @return String with current date and time + */ + protected static String getTimeString() { + Date d = new Date(); + SimpleDateFormat df = new SimpleDateFormat("[MM/dd/yy;HH:mm:ss:SSS]"); //$NON-NLS-1$ + return df.format(d); + } + + /** + * Traces the specified message from the specified plug-in. + * + * @param pluginId The plug-in from which to trace. + * @param message The message to be traced. + * + */ + public static void trace(String pluginId, String message) { + if (shouldTrace(pluginId)) + trace(message); + } + + /** + * Traces the specified message from the specified plug-in for the specified + * debug option. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param message The message to be traced. + * + */ + public static void trace(String pluginId, String option, String message) { + if (shouldTrace(pluginId, option)) + trace(message); + } + + /** + * Traces the specified message from the specified plug-in for the specified + * debug option. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class whose method is being entered. + * @param methodName The name of method that is being entered. + * @param message The message to be traced. + * + */ + public static void trace(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName, String message) { + if (shouldTrace(pluginId, option)) { + StringBuffer buf = new StringBuffer(PREFIX_TRACING).append(clazz.getName()); + buf.append(SEPARATOR_METHOD).append(methodName); + buf.append(PARENTHESIS_OPEN).append(message).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + } + } + + /** + * Traces the changing of a value. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param valueDescription The description of the value which is changing. + * @param oldValue The old value. + * @param newValue The new value. + */ + public static void changing(String pluginId, String option, String valueDescription, Object oldValue, + Object newValue) { + + if (shouldTrace(pluginId, option)) { + StringBuilder buf = new StringBuilder(PREFIX_CHANGING); + buf.append(valueDescription).append(SEPARATOR_SPACE).append(LABEL_OLD_VALUE) + .append(getArgumentString(oldValue)); + buf.append(SEPARATOR_PARAMETER).append(LABEL_NEW_VALUE).append(getArgumentString(newValue)); + trace(buf.toString()); + } + } + + /** + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class in which the value is changing. + * @param methodName The name of the method in which the value is changing. + * @param valueDescription The description of the value which is changing. + * @param oldValue The old value. + * @param newValue The new value. + */ + public static void changing(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName, String valueDescription, Object oldValue, Object newValue) { + if (shouldTrace(pluginId, option)) { + StringBuilder buf = new StringBuilder(PREFIX_CHANGING); + buf.append(valueDescription).append(SEPARATOR_SPACE).append(LABEL_OLD_VALUE) + .append(getArgumentString(oldValue)); + buf.append(SEPARATOR_PARAMETER).append(LABEL_NEW_VALUE).append(getArgumentString(newValue)); + buf.append(SEPARATOR_SPACE).append(PARENTHESIS_OPEN).append(clazz.getName()).append(SEPARATOR_METHOD); + buf.append(methodName).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + } + } + + /** + * Traces the catching of the specified throwable in the specified method of + * the specified class. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class in which the throwable is being caught. + * @param methodName The name of the method in which the throwable is being + * caught. + * @param throwable The throwable that is being caught. + * + */ + public static void catching(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName, Throwable throwable) { + + if (shouldTrace(pluginId, option)) { + StringBuilder buf = new StringBuilder(PREFIX_CATCHING); + if (throwable != null) { + String message = throwable.getMessage(); + if (message != null) + buf.append(message).append(SEPARATOR_SPACE); + } + buf.append(PARENTHESIS_OPEN).append(clazz.getName()).append(SEPARATOR_METHOD); + buf.append(methodName).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + if (throwable != null) { + throwable.printStackTrace(System.err); + } + } + } + + /** + * Traces the throwing of the specified throwable from the specified method + * of the specified class. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class from which the throwable is being thrown. + * @param methodName The name of the method from which the throwable is + * being thrown. + * @param throwable The throwable that is being thrown. + * + */ + public static void throwing(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName, Throwable throwable) { + + if (shouldTrace(pluginId, option)) { + StringBuilder buf = new StringBuilder(PREFIX_THROWING); + if (throwable != null) { + String message = throwable.getMessage(); + if (message != null) + buf.append(message).append(SEPARATOR_SPACE); + } + buf.append(PARENTHESIS_OPEN).append(clazz.getName()).append(SEPARATOR_METHOD); + buf.append(methodName).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + throwable.printStackTrace(System.err); + } + } + + /** + * Traces the entering into the specified method of the specified class. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class whose method is being entered. + * @param methodName The name of method that is being entered. + * + */ + public static void entering(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName) { + + if (shouldTrace(pluginId, option)) { + StringBuffer buf = new StringBuffer(PREFIX_ENTERING).append(clazz.getName()); + buf.append(SEPARATOR_METHOD).append(methodName).append(PARENTHESIS_OPEN).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + } + } + + /** + * Traces the entering into the specified method of the specified class, + * with the specified parameter. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class whose method is being entered. + * @param methodName The name of method that is being entered. + * @param parameter The parameter to the method being entered. + * + */ + public static void entering(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName, Object parameter) { + + if (shouldTrace(pluginId, option)) { + StringBuffer buf = new StringBuffer(PREFIX_ENTERING).append(clazz.getName()); + buf.append(SEPARATOR_METHOD).append(methodName); + buf.append(PARENTHESIS_OPEN).append(getArgumentString(parameter)).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + } + + } + + /** + * Traces the entering into the specified method of the specified class, + * with the specified parameters. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class whose method is being entered. + * @param methodName The name of method that is being entered. + * @param parameters The parameters to the method being entered. + * + */ + public static void entering(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName, Object[] parameters) { + + if (shouldTrace(pluginId, option)) { + StringBuffer buf = new StringBuffer(PREFIX_ENTERING).append(clazz.getName()); + buf.append(SEPARATOR_METHOD).append(methodName); + buf.append(PARENTHESIS_OPEN).append(getArgumentString(parameters)).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + } + + } + + /** + * Traces the exiting from the specified method of the specified class. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class whose method is being exited. + * @param methodName The name of method that is being exited. + * + */ + public static void exiting(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName) { + + if (shouldTrace(pluginId, option)) { + StringBuffer buf = new StringBuffer(PREFIX_EXITING).append(clazz.getName()); + buf.append(SEPARATOR_METHOD).append(methodName); + trace(buf.toString()); + } + } + + /** + * Traces the exiting from the specified method of the specified class, with + * the specified return value. + * + * @param pluginId The plug-in from which to trace. + * @param option The debug option for which to trace. + * @param clazz The class whose method is being exited. + * @param methodName The name of method that is being exited. + * @param returnValue The return value of the method being exited. + * + */ + public static void exiting(String pluginId, String option, @SuppressWarnings("rawtypes") Class clazz, + String methodName, Object returnValue) { + + if (shouldTrace(pluginId, option)) { + StringBuffer buf = new StringBuffer(PREFIX_EXITING).append(clazz.getName()); + buf.append(SEPARATOR_METHOD).append(methodName); + buf.append(PARENTHESIS_OPEN).append(getArgumentString(returnValue)).append(PARENTHESIS_CLOSE); + trace(buf.toString()); + } + + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java new file mode 100644 index 0000000000..92456b1a84 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/core/util/reflection/ClassUtil.java @@ -0,0 +1,130 @@ +/**************************************************************************** + * Copyright (c) 2010 Markus Alexander Kuppe. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Markus Alexander Kuppe (ecf-dev_eclipse.org lemmster de) - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.core.util.reflection; + +import java.lang.reflect.Method; +import java.util.*; + +/** + * @since 3.3 + */ +public class ClassUtil { + + private static Map convertor = new HashMap(); + + static { + convertor.put(boolean.class, Boolean.class); + convertor.put(byte.class, Byte.class); + convertor.put(char.class, Character.class); + convertor.put(double.class, Double.class); + convertor.put(float.class, Float.class); + convertor.put(int.class, Integer.class); + convertor.put(long.class, Long.class); + convertor.put(short.class, Short.class); + } + + /** + * @param aClass The Class providing method under question (Must not be null) + * @param aMethodName The method name to search for (Must not be null) + * @param someParameterTypes Method arguments (May be null or parameters) + * @return A match. If more than one method matched (due to overloading) an arbitrary match is taken + * @throws NoSuchMethodException If a match cannot be found + */ + public static Method getMethod(final Class aClass, String aMethodName, final Class[] someParameterTypes) throws NoSuchMethodException { + // no args makes matching simple + if (someParameterTypes == null || someParameterTypes.length == 0) { + return aClass.getMethod(aMethodName, (Class[]) null); + } + return getMethod(aClass.getMethods(), aMethodName, someParameterTypes); + } + + /** + * @param aClass The Class providing method under question (Must not be null) + * @param aMethodName The method name to search for (Must not be null) + * @param someParameterTypes Method arguments (May be null or parameters) + * @return A match. If more than one method matched (due to overloading) an arbitrary match is taken + * @throws NoSuchMethodException If a match cannot be found + */ + public static Method getDeclaredMethod(final Class aClass, String aMethodName, final Class[] someParameterTypes) throws NoSuchMethodException { + // no args makes matching simple + if (someParameterTypes == null || someParameterTypes.length == 0) { + return aClass.getDeclaredMethod(aMethodName, (Class[]) null); + } + return getMethod(aClass.getDeclaredMethods(), aMethodName, someParameterTypes); + } + + private static Method getMethod(final Method[] candidates, String aMethodName, final Class[] someParameterTypes) throws NoSuchMethodException { + // match parameters to determine callee + final int parameterCount = someParameterTypes.length; + aMethodName = aMethodName.intern(); + + final TreeSet matches = new TreeSet(new MethodComparator(someParameterTypes)); + OUTER: for (int i = 0; i < candidates.length; i++) { + final Method candidate = candidates[i]; + final String candidateMethodName = candidate.getName().intern(); + final Class[] candidateParameterTypes = candidate.getParameterTypes(); + final int candidateParameterCount = candidateParameterTypes.length; + if (candidateParameterCount == parameterCount && aMethodName == candidateMethodName) { + for (int j = 0; j < candidateParameterCount; j++) { + final Class clazzA = candidateParameterTypes[j]; + final Class clazzB = someParameterTypes[j]; + if (clazzB != null && !isAssignableFrom(clazzA, clazzB)) { + continue OUTER; + } + } + matches.add(candidate); + } + } + + // if no match has been found, fail with NSME + if (matches.size() == 0) { + throw new NoSuchMethodException("No such method: " + aMethodName + "(" + Arrays.asList(someParameterTypes) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + return (Method) matches.first(); + } + + // extends Class.isAssingable(Class) with autoboxing + private static boolean isAssignableFrom(Class clazzA, Class clazzB) { + if (!(clazzA.isPrimitive() ^ clazzB.isPrimitive())) { + return clazzA.isAssignableFrom(clazzB); + } else if (clazzA.isPrimitive()) { + final Class oClazzA = (Class) convertor.get(clazzA); + return oClazzA.isAssignableFrom(clazzB); + } else { + final Class oClazzB = (Class) convertor.get(clazzB); + return clazzA.isAssignableFrom(oClazzB); + } + } + + private static class MethodComparator implements Comparator { + + private final Class[] parameterTypes; + + public MethodComparator(Class[] someParameterTypes) { + parameterTypes = someParameterTypes; + } + + public int compare(Object object1, Object object2) { + final Class[] pt1 = ((Method) object1).getParameterTypes(); + final Class[] pt2 = ((Method) object2).getParameterTypes(); + + if (Arrays.equals(pt1, pt2)) { + return 0; + } else if (Arrays.equals(parameterTypes, pt1)) { + return -1; + } else { + return 1; + } + } + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/BrowseFileTransferException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/BrowseFileTransferException.java new file mode 100644 index 0000000000..324321f040 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/BrowseFileTransferException.java @@ -0,0 +1,70 @@ +/**************************************************************************** + * Copyright (c) 2009 EclipseSource, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: EclilpseSource, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * Exception thrown upon browse problem + * + * @since 3.0 + */ +public class BrowseFileTransferException extends ECFException { + + private static final long serialVersionUID = 3486429797589398022L; + private int errorCode = -1; + + public BrowseFileTransferException(IStatus status) { + super(status); + } + + public BrowseFileTransferException() { + // null constructor + } + + public BrowseFileTransferException(int errorCode) { + this(); + this.errorCode = errorCode; + } + + public BrowseFileTransferException(String message) { + super(message); + } + + public BrowseFileTransferException(String message, int errorCode) { + super(message); + this.errorCode = errorCode; + } + + public BrowseFileTransferException(Throwable cause) { + super(cause); + } + + public BrowseFileTransferException(Throwable cause, int errorCode) { + super(cause); + this.errorCode = errorCode; + } + + public BrowseFileTransferException(String message, Throwable cause) { + super(message, cause); + } + + public BrowseFileTransferException(String message, Throwable cause, int errorCode) { + super(message, cause); + this.errorCode = errorCode; + } + + public int getErrorCode() { + return errorCode; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferInfo.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferInfo.java new file mode 100644 index 0000000000..c3cc88e73c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferInfo.java @@ -0,0 +1,115 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import java.io.File; +import java.io.Serializable; +import java.net.URLConnection; +import java.util.HashMap; +import java.util.Map; +import org.eclipse.core.runtime.Assert; +import org.eclipse.ecf.filetransfer.events.IFileTransferRequestEvent; + +/** + * File transfer information delivered to + * {@link IIncomingFileTransferRequestListener} via an event implementing + * {@link IFileTransferRequestEvent#getFileTransferInfo()} + * + */ +public class FileTransferInfo implements IFileTransferInfo, Serializable { + + private static final long serialVersionUID = 8354226751625912190L; + + protected File file; + + protected Map properties; + + protected String description; + + protected String mimeType = null; + + public FileTransferInfo(File file) { + this(file, null); + } + + public FileTransferInfo(File file, Map properties) { + this(file, properties, null); + } + + public FileTransferInfo(File file, Map properties, String description) { + this(file, properties, description, null); + } + + public FileTransferInfo(File file, Map properties, String description, String mimeType) { + Assert.isNotNull(file, "file must not be null"); //$NON-NLS-1$ + this.file = file; + this.properties = (properties == null) ? new HashMap() : properties; + this.description = description; + this.mimeType = mimeType; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferInfo#getFile() + */ + public File getFile() { + return file; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferInfo#getProperties() + */ + public Map getProperties() { + return properties; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferInfo#getDescription() + */ + public String getDescription() { + return description; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferInfo#getFileSize() + */ + public long getFileSize() { + return file.length(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferInfo#getMimeType() + */ + public String getMimeType() { + if (mimeType == null) + return URLConnection.getFileNameMap().getContentTypeFor(file.getAbsolutePath()); + return mimeType; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferJob.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferJob.java new file mode 100644 index 0000000000..0c2d68666c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/FileTransferJob.java @@ -0,0 +1,85 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Contributors: Cloudsmith, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.*; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveStartEvent; + +/** + * {@link Job} subclass for executing file transfers. This class should + * be subclassed to create a customized {@link Job} for passing to + * an incoming or outgoing file transfer. For example, to use a custom + * job for doing a file transfer retrieval via {@link IIncomingFileTransferReceiveStartEvent#receive(java.io.File, FileTransferJob)}: + *
+ * class MyFileTransferJob extends FileTransferJob {
+ * 		public MyFileTransferJob(String name) {
+ * 			super(name);
+ * 		}
+ * 
+ * 		public boolean belongsTo(Object o) {
+ * 			// insert own logic to decide whether
+ *  		// this file transfer job should be part
+ *  		// of a group
+ *  		//
+ * 		}
+ * }
+ * 
+ * MyFileTransferJob myJob = new MyFileTransferJob("myname");
+ * incomingfiletransfer = event.receive(outputstream,myJob);
+ * 
+ * @since 2.0 + */ +public class FileTransferJob extends Job { + + private IFileTransferRunnable fileTransferRunnable; + private IFileTransfer fileTransfer; + + /** + * @param name the name for this file transfer job. Should not be null. + */ + public FileTransferJob(String name) { + super(name); + setSystem(true); + } + + public final void setFileTransferRunnable(IFileTransferRunnable fileTransferRunnable) { + this.fileTransferRunnable = fileTransferRunnable; + } + + /** + * @param fileTransfer file transfer instance + * @since 3.0 + */ + public final void setFileTransfer(IFileTransfer fileTransfer) { + this.fileTransfer = fileTransfer; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + protected final IStatus run(IProgressMonitor mntr) { + if (this.fileTransferRunnable == null) + return new Status(IStatus.ERROR, org.eclipse.ecf.internal.filetransfer.Activator.PLUGIN_ID, IStatus.ERROR, "Runnable cannot be null", null); //$NON-NLS-1$ + if (this.fileTransfer == null) + return new Status(IStatus.ERROR, org.eclipse.ecf.internal.filetransfer.Activator.PLUGIN_ID, IStatus.ERROR, "File transfer member cannot be null", null); //$NON-NLS-1$ + return this.fileTransferRunnable.performFileTransfer(mntr); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.jobs.Job#canceling() + */ + protected void canceling() { + fileTransfer.cancel(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileRangeSpecification.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileRangeSpecification.java new file mode 100644 index 0000000000..4a0447c17b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileRangeSpecification.java @@ -0,0 +1,74 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +/** + * An object that describes a file range specification. Object implementations of this + * class can be + */ +public interface IFileRangeSpecification { + + /** + * Get the start position to start from. The position is in bytes, and byte 0 is the first byte + * of the file, N-1 is the last position in the file, where N is the length of the file in bytes. + * @return the position in the file (in bytes) to start from. If the returned start position is + * less than 0, or equal to or greater than N, then it is an invalid range specification and + * when used in {@link IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, IFileRangeSpecification, IFileTransferListener, java.util.Map)} will result in a + * {@link InvalidFileRangeSpecificationException}. + * + * @see IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, IFileRangeSpecification, IFileTransferListener, java.util.Map) + * @see #getEndPosition() + */ + public long getStartPosition(); + + /** + * Get the end position of transfer range. The position is in bytes, and byte 0 is the first byte + * of the file, N-1 is the last position in the file, where N is the length of the file in bytes. + * @return the position in the file (in bytes) to indicate the end of range to retrieve. If equal to -1, + * then this means that no end position is specified, and the download will continue to the end of file. If gt or eq 0, + * but less than the {@link #getStartPosition()} then this range specification is invalid. If greater than or + * equal to N (where N is length of the file in bytes), then the remaining part of the given file will + * be downloaded. If both {@link #getStartPosition()} and {@link #getEndPosition()} are valid, then + * the number of bytes downloaded will be (endPosition - startPosition) + 1. So, for example: + *
+	 * For a fileLength = 20
+	 * 
+	 * startPosition = 10
+	 * endPosition = 19
+	 * bytesDownloaded = 10
+	 * 
+	 * startPosition = 0
+	 * endPosition = -1
+	 * bytesDownloaded = 20
+	 * 
+	 * startPosition = 5
+	 * endPosition = 3
+	 * invalid range
+	 * 
+	 * startPosition = 5
+	 * endPosition = 6
+	 * bytesDownloaded = 2
+	 * 
+	 * startPosition = 5
+	 * endPosition = -1
+	 * bytesDownloaded = 15
+	 * 
+	 * 
+ * + * @see IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, IFileRangeSpecification, IFileTransferListener, java.util.Map) + * @see #getStartPosition() + */ + public long getEndPosition(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransfer.java new file mode 100644 index 0000000000..30eb41ea55 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransfer.java @@ -0,0 +1,97 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.core.identity.IIdentifiable; +import org.eclipse.ecf.filetransfer.events.IFileTransferEvent; + +/** + * File transfer super interface. This interface provides the abstract file + * transfer semantics for both {@link IOutgoingFileTransfer} and + * {@link IIncomingFileTransfer} transfer sub interfaces. + */ +public interface IFileTransfer extends IAdaptable, IIdentifiable { + /** + * Cancel this file transfer. If file transfer has already been completed, + * then this method has no effect. If the file transfer has not been + * completed then calling this method will result in an + * {@link IFileTransferEvent} being delivered to the + * {@link IFileTransferListener} indicating that transfer is done ({@link #isDone()} + * returns true), and some exception will be made available + * + */ + public void cancel(); + + /** + * Get the percent complete for this file transfer. The returned value will + * be either -1.0, meaning that the underlying provider does not support + * reporting percent complete for this file transfer, or a value between 0 + * and 1 reflecting the percent complete for this file transfer. If 0.0 no + * data has been sent, if 1.0, the file transfer is 100 percent complete. + * + * The value returned from this method should not be used to + * determine whether the transfer has completed, as it may not show + * completion in the event of an transfer failure. Note that the + * {@link #isDone()} method should be consulted to determine if the file + * transfer has completed (with or without error). + * + * @return double percent complete. Returns -1.0 if the underlying provider + * does not support reporting percentage complete, or between 0 and + * 1 to indicate actual percent complete for this file transfer + */ + public double getPercentComplete(); + + /** + * Get any exception associated with this file transfer. The value returned + * from this method is valid only if {@link #isDone()} method returns true. + * If the file transfer completed successfully, {@link #isDone()} will + * return true, and this method will return null. If the file transfer + * completed unsuccessfully (some exception occurred), then + * {@link #isDone()} will return true, and this method will return a + * non-null Exception instance that occurred. + *

+ * If the the file transfer was canceled by the user, then the exception + * returned will be an instance of {@link UserCancelledException}. + * + * @return Exception associated with this file transfer. null + * if transfer completed successfully, non-null if transfer + * completed with some exception. Only valid after + * {@link #isDone()} returns true. + */ + public Exception getException(); + + /** + * Return true if this file transfer is done, false if not yet completed. + * The file transfer can be completed successfully, or an exception can + * occur and the file transfer will have failed. In either case of + * successful or unsuccessful transfer, this method will return true when + * the file transfer is complete. To determine whether the transfer + * completed successfully, it is necessary to also consult the + * {@link #getException()} method. + * + * @return boolean true if file transfer is done, false if file transfer is + * still in progress. + */ + public boolean isDone(); + + /** + * Return resulting file length (in bytes) for this file transfer instance. If the length is not known, + * -1 will be returned. Note that if a {@link IFileRangeSpecification} is provided that the returned + * file length is the expected file length of just the range retrieved (and not the entire file). + * + *@return long file length + * @since 2.0 + */ + public long getFileLength(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferInfo.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferInfo.java new file mode 100644 index 0000000000..e08c9a13e9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferInfo.java @@ -0,0 +1,64 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import java.io.File; +import java.util.Map; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.filetransfer.events.IFileTransferRequestEvent; + +/** + * File transfer information delivered to + * {@link IIncomingFileTransferRequestListener} via an event implementing + * {@link IFileTransferRequestEvent#getFileTransferInfo()} + * + */ +public interface IFileTransferInfo extends IAdaptable { + /** + * Get the file for the proposed file transfer + * + * @return the proposed file. Will not return null. + */ + public File getFile(); + + /** + * Get the file size (in bytes). + * + * @return long file size (in bytes). If file size is unknown, will return -1. + */ + public long getFileSize(); + + /** + * Get any properties associated with this file transfer. The map keys and + * values are assumed to be Strings. + * + * @return Map of properties associated with this file transfer info. Will + * not return null. + */ + public Map getProperties(); + + /** + * Get any description associated with this file transfer info. + * + * @return String description. May be null if no description + * provided. + */ + public String getDescription(); + + /** + * Get the mime type string for this file transfer info. + * + * @return String mime type. May return null if mime type is not known. + */ + public String getMimeType(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferListener.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferListener.java new file mode 100644 index 0000000000..7e9961a0fd --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferListener.java @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import org.eclipse.ecf.filetransfer.events.IFileTransferEvent; + +/** + * Listener for handling file transfer events. Instances implementing this + * interface or sub-interfaces will have their handleTransferEvent called + * asynchronously when a given event is received. Implementers must be prepared + * to have this method called asynchronously by an arbitrary thread. + * + *

+ * Note these methods will be called asynchronously when notifications of remote + * changes are received by the provider implementation code. The provider is + * free to call the methods below with an arbitrary thread, so the + * implementation of these methods must be appropriately prepared. + *

+ * For example, if the code implementing any of these methods must interact with + * user interface code, then it should use code such as the following to execute + * on the SWT UI thread: + * + *

+ * 	Display.getDefault().asyncExec(new Runnable() {
+ * 		public void run() {
+ * 		... UI code here
+ * 		}
+ * 	});
+ * 
+ * + * Further, the code in the implementations of these methods should not block + * via I/O operations or blocking UI calls. + */ +public interface IFileTransferListener { + /** + * Handle file transfer events + * + * @param event + * the event to be handled. should not be null. + */ + public void handleTransferEvent(IFileTransferEvent event); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferPausable.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferPausable.java new file mode 100644 index 0000000000..3e9b553485 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferPausable.java @@ -0,0 +1,57 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +/** + * Adapter interface for pausing and resuming IFileTransfer instances that + * expose this adapter interface via + * {@link IFileTransfer#getAdapter(Class adapter)}. To use this interface, + * clients should do the following: + * + *
+ *   IFileTransfer fileTransfer;
+ *   IFileTransferPausable pausable = (IFileTransferPausable) fileTransfer.getAdapter(IFileTransferPausable.class);
+ *   if (pausable !=null) {
+ *      ... use it
+ *   } else {
+ *      ... does not support pausing
+ *   }
+ * 
+ * + */ +public interface IFileTransferPausable { + + /** + * Pause file transfer. Returns true if the associated IFileTransfer is + * successfully paused. Returns false if the implementing file transfer + * cannot be paused, or transfer has already completed. + * + * @return boolean true if file transfer successfully paused. False if cannot be + * paused, or the transfer has already completed + */ + public boolean pause(); + + /** + * + * @return boolean true if file transfer paused, false if not paused + */ + public boolean isPaused(); + + /** + * Resume file transfer after having been paused. If successfully resumed, + * then returns true. If the associated IFileShare is not already paused, or + * has already completed then this method returns false. + * + * @return boolean true if transfer is successfully resumed, false otherwise + */ + public boolean resume(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRateControl.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRateControl.java new file mode 100644 index 0000000000..dfd6e5f312 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRateControl.java @@ -0,0 +1,51 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +/** + * Adapter for setting rate control on IFileTransferInfo instances that expose + * expose this adapter interface via + * {@link IFileTransfer#getAdapter(Class adapter)}. To use this interface, + * clients should do the following: + * + *
+ *   IFileTransfer fileTransfer;
+ *   IFileTransferRateControl rateController = (IFileTransferRateControl) fileTransfer.getAdapter(IFileTransferRateControl.class);
+ *   if (rateController !=null) {
+ *      ... use it
+ *   } else {
+ *      ... does not support rate control
+ *   }
+ * 
+ * + */ +public interface IFileTransferRateControl { + /** + * Set maximum download speed in bytes/second. Specifying a maximum download + * speed of 0 indicates that any exiting rate cap should be removed, and the + * transfer should proceed as fast as possible a + * + * @param maxDownloadSpeed + * in bytes/second + */ + public void setMaxDownloadSpeed(long maxDownloadSpeed); + + /** + * Set maximum upload speed in bytes/second. Specifying a maximum upload + * speed of 0 indicates that any exiting rate cap should be removed, and the + * transfer should proceed as fast as possible + * + * @param maxUploadSpeed + * in bytes/second + */ + public void setMaxUploadSpeed(long maxUploadSpeed); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRunnable.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRunnable.java new file mode 100644 index 0000000000..9770501ce2 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IFileTransferRunnable.java @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; + +/** + * Runnable for doing file transfer. Used by {@link FileTransferJob}s. + * + * @since 2.0 + */ +public interface IFileTransferRunnable { + + /** + * Synchronously perform the actual file transfer. + * + * @param monitor a progress montior. Will not be null. + * @return IStatus a status object indicating the ending status of the file transfer job. + */ + public IStatus performFileTransfer(IProgressMonitor monitor); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransfer.java new file mode 100644 index 0000000000..ee46d4dabf --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransfer.java @@ -0,0 +1,68 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import java.util.Date; +import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveStartEvent; + +/** + * Incoming file transfer request. Instance implementing this interface are + * provided via calling the + * {@link IIncomingFileTransferReceiveStartEvent#receive(java.io.File)} method. + * + */ +public interface IIncomingFileTransfer extends IFileTransfer { + /** + * Get number of bytes received so far. If provider does not support + * reporting the number of bytes received, will return -1. + * + * @return long number of bytes received. Returns -1 if provider does not + * support reporting of number of bytes received during transfer + */ + public long getBytesReceived(); + + /** + * Get listener assigned to this incoming file transfer. May be null if no listener + * has been provided. + * + * @return listener the IFileTransferListener provided for this incoming file transfer. + */ + public IFileTransferListener getListener(); + + /** + * Get file range specification for this incoming file transfer instance. Will return + * null if the retrieval is of the entire file. + * + * @return file range specification for this incoming file transfer instance. Returns + * null if the retrieval is of the entire file. + */ + public IFileRangeSpecification getFileRangeSpecification(); + + /** + * Obtains the name of the remote file if possible. The name will typically but not + * necessarily be the same as the leaf part of the path to the remote file. + * + * @return The name of the remote file or null if no such name can be determined. + * + * @since 2.0 + */ + public String getRemoteFileName(); + + /** + * Obtains the timestamp that reflects the time when the remote file was last + * modified if possible. + * @return The time the remote file was last modified or null if that + * information was not available. + * @since 2.0 + */ + public Date getRemoteLastModified(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransferRequestListener.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransferRequestListener.java new file mode 100644 index 0000000000..72439428f5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IIncomingFileTransferRequestListener.java @@ -0,0 +1,32 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import org.eclipse.ecf.filetransfer.events.IFileTransferRequestEvent; + +/** + * Listener for incoming file transfer requests. Instances implementing this + * interface are registered via the + * {@link ISendFileTransferContainerAdapter#addListener(IIncomingFileTransferRequestListener)} + * + * @see ISendFileTransferContainerAdapter#addListener(IIncomingFileTransferRequestListener) + */ +public interface IIncomingFileTransferRequestListener { + /** + * Handle file transfer requests when received asynchronously from remotes. + * + * @param event + * the {@link IFileTransferRequestEvent} that represents the file + * transfer request. Will not be should not be null. + */ + public void handleFileTransferRequest(IFileTransferRequestEvent event); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IOutgoingFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IOutgoingFileTransfer.java new file mode 100644 index 0000000000..3595a575ea --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IOutgoingFileTransfer.java @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +/** + * Outgoing file transfer. + * + */ +public interface IOutgoingFileTransfer extends IFileTransfer { + /** + * Get the number of bytes sent for this outgoing file transfer. Returns 0 + * if transfer has not be started, and -1 if underlying provider does not + * support reporting number of bytes sent during transfer. + * + * @return number of bytes sent. Returns 0 if the outgoing file transfer has + * not been started, and -1 if provider does not support reporting + * of number of bytes received during transfer + */ + public long getBytesSent(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFile.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFile.java new file mode 100644 index 0000000000..9f949d7300 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFile.java @@ -0,0 +1,37 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Remote file representation. + */ +public interface IRemoteFile extends IAdaptable { + + /** + * Get remote file info associated with this remote file. + * @return file info. Will not be null. + */ + public IRemoteFileInfo getInfo(); + + /** + * Get the remote file id associated with this file. + * @return the file id associated with this file. Will not be + * null. + */ + public IFileID getID(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileAttributes.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileAttributes.java new file mode 100644 index 0000000000..1981f0514d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileAttributes.java @@ -0,0 +1,52 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import java.util.Iterator; + +/** + * Remote file attributes. These attributes represent characteristics of remote files (e.g. read only, writeable, executable, archive, etc.). + */ +public interface IRemoteFileAttributes { + + public static String READ_ATTRIBUTE = "read"; //$NON-NLS-1$ + public static String WRITE_ATTRIBUTE = "write"; //$NON-NLS-1$ + public static String EXEC_ATTRIBUTE = "exec"; //$NON-NLS-1$ + public static String ARCHIVE_ATTRIBUTE = "archive"; //$NON-NLS-1$ + public static String HIDDEN_ATTRIBUTE = "hidden"; //$NON-NLS-1$ + public static String SYMLINK_ATTRIBUTE = "symlink"; //$NON-NLS-1$ + public static String SYMLINK_TARGET_ATTRIBUTE = "symlinktarget"; //$NON-NLS-1$ + + /** + * Get file attribute with given key. Returns null if attribute not in + * this map of attributes. + * @param key to use to find the given attribute. Must not be null. + * @return value of attribute. null if not found. + */ + public String getAttribute(String key); + + /** + * Get all of the attribute keys in this map of file attributes. + * + * @return Iterator of the attribute keys for this map. Will not return null. + */ + public Iterator getAttributeKeys(); + + /** + * Set a given attribute value in this remote file attributes. + * @param key the key to use for the attribute. Must not be null. + * @param value the value for the given key. Must not be null. + */ + public void setAttribute(String key, String value); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileInfo.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileInfo.java new file mode 100644 index 0000000000..1f489a9e3e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileInfo.java @@ -0,0 +1,95 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +/** + * Information about a remote file. Last modified day/time, length in bytes, + * whether the remote file is a directory, a name, and file attributes. + * @see IRemoteFile + */ +public interface IRemoteFileInfo { + + public static final int NO_LENGTH = -1; + + /** + * @deprecated + */ + public static final int NONE = NO_LENGTH; + + public static final int NO_LAST_MODIFIED = 0; + + /** + * Returns the last modified time for this file, or {@link #NO_LAST_MODIFIED } + * if the file does not exist or the last modified time could not be computed. + *

+ * The time is represented as the number of Universal Time (UT) + * milliseconds since the epoch (00:00:00 GMT, January 1, 1970). + *

+ * + * @return the last modified time for this file, or {@link #NO_LAST_MODIFIED } if file + * does not exist or last modified not known or could not be computed. + */ + public long getLastModified(); + + /** + * Returns the length of this file, or {@link #NO_LENGTH} + * if the file does not exist, is a directory, or the length could not be computed. + * + * @return the length of this file, or {@link #NO_LENGTH} + */ + public long getLength(); + + /** + * Returns whether this file is a directory, or false if this + * file does not exist. + * + * @return true if this file is a directory, and false + * otherwise. + */ + public boolean isDirectory(); + + /** + * Returns the name of this file. + * + * @return the name of this file. Will not return null. + */ + public String getName(); + + /** + * Get remote file attributes. + * @return IRemoteFileAttributes for this IRemoteFile. Will not return null. + */ + public IRemoteFileAttributes getAttributes(); + + /** + * Set the attributes for this remote file info. + * @param attributes the new attribute values to use. + */ + public void setAttributes(IRemoteFileAttributes attributes); + + /** + * Set the underlying name for this remote file info. + * + * @param name the new name to use. Must not be null. + */ + public void setName(String name); + + /** + * Set the last modified time for this remote file info. + * + * @param time the time to use. See {@link #getLastModified()} for meaning of time value. + */ + public void setLastModified(long time); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemBrowserContainerAdapter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemBrowserContainerAdapter.java new file mode 100644 index 0000000000..802c7d9084 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemBrowserContainerAdapter.java @@ -0,0 +1,75 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Remote file system browser adapter. This adapter can be retrieved from a container + * for exposing remote file system browsing capabilities. + */ +public interface IRemoteFileSystemBrowserContainerAdapter extends IAdaptable { + + /** + * Get the {@link Namespace} instance for creating IFileIDs that represent remote files or directories. + * + * @return Namespace for remote files or directories. Will not be null. + */ + public Namespace getBrowseNamespace(); + + /** + * Send a request for file or directory information for given directoryOrFileID. + * @param directoryOrFileID the IFileID representing/specifying the remote directory or file to access. + * @param listener the listener that will be notified asynchronously when a response to this request is received. Must not be + * null. + * @return IRemoteFileSystemRequest the request instance. + * @throws RemoteFileSystemException if browse request cannot be accomplished + */ + public IRemoteFileSystemRequest sendBrowseRequest(IFileID directoryOrFileID, IRemoteFileSystemListener listener) throws RemoteFileSystemException; + + /** + * Set connect context for authentication upon subsequent + * {@link #sendBrowseRequest(IFileID, IRemoteFileSystemListener)}. This + * method should be called with a non-null connectContext in order to allow + * authentication to occur during call to + * {@link #sendBrowseRequest(IFileID, IRemoteFileSystemListener)}. + * + * @param connectContext + * the connect context to use for authenticating during + * subsequent call to + * {@link #sendBrowseRequest(IFileID, IRemoteFileSystemListener)}. + * If null, then no authentication will be + * attempted. + */ + public void setConnectContextForAuthentication(IConnectContext connectContext); + + /** + * Set proxy for use upon subsequent + * {@link #sendBrowseRequest(IFileID, IRemoteFileSystemListener)}. This + * method should be called with a non-null proxy to allow the given proxy to + * be used in subsequent calls to + * {@link #sendBrowseRequest(IFileID, IRemoteFileSystemListener)}. + * + * @param proxy + * the proxy to use for subsequent calls to + * {@link #sendBrowseRequest(IFileID, IRemoteFileSystemListener)}. + * If null, then no proxy will be used. + */ + public void setProxy(Proxy proxy); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemListener.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemListener.java new file mode 100644 index 0000000000..305e758dcb --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemListener.java @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.ecf.filetransfer.events.IRemoteFileSystemEvent; + +/** + * Listener for handling events associated with remote file + * browsing activities. + *

+ * Note this method will be called asynchronously when notifications of remote + * changes are received by the provider implementation code. The provider is + * free to call the methods below with an arbitrary thread, so the + * implementation of these methods must be appropriately prepared. + *

+ * For example, if the code implementing any of these methods must interact with + * user interface code, then it should use code such as the following to execute + * on the SWT UI thread: + * + *

+ * 	Display.getDefault().asyncExec(new Runnable() {
+ * 		public void run() {
+ * 		... UI code here
+ * 		}
+ * 	});
+ * 
+ * + * Further, the code in the implementations of these methods should not block + * via I/O operations or blocking UI calls. + */ +public interface IRemoteFileSystemListener { + + /** + * Handle the remote file event. + * @param event the event to received to handle. Will not be null. + */ + public void handleRemoteFileEvent(IRemoteFileSystemEvent event); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemRequest.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemRequest.java new file mode 100644 index 0000000000..6a35269675 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRemoteFileSystemRequest.java @@ -0,0 +1,40 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Remote file request. + */ +public interface IRemoteFileSystemRequest extends IAdaptable { + + /** + * Cancel this request. + */ + public void cancel(); + + /** + * Get the listener associated with this request + * @return IRemoteFileSystemListener associated with this request. + */ + public IRemoteFileSystemListener getRemoteFileListener(); + + /** + * Get directoryID that represents the directory accessed. + * @return IFileID for remote directory or file. Will not return null. + */ + public IFileID getFileID(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferContainerAdapter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferContainerAdapter.java new file mode 100644 index 0000000000..eec9d8c914 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferContainerAdapter.java @@ -0,0 +1,218 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import java.util.Map; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.core.IContainer; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.events.*; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Entry point retrieval file transfer adapter. This adapter interface allows + * providers to expose file retrieval semantics to clients in a transport + * independent manner. To be used, a non-null adapter reference must be returned + * from a call to {@link IContainer#getAdapter(Class)}. Once a non-null + * reference is retrieved, then it may be used to send a retrieve request. + * Events will then be asynchronously delivered to the provided listener to + * complete file transfer. + *

+ * For example, to retrieve a remote file and store it in a local file: + * + *

+ * // Get IRetrieveFileTransferContainerAdapter adapter
+ * IRetrieveFileTransferContainerAdapter ftc = (IRetrieveFileTransferContainerAdapter) container
+ * 		.getAdapter(IRetrieveFileTransferContainerAdapter.class);
+ * if (ftc != null) {
+ * 	// Create listener for receiving/responding to asynchronous file transfer events
+ * 	IFileTransferListener listener = new IFileTransferListener() {
+ * 		public void handleTransferEvent(IFileTransferEvent event) {
+ * 			// If incoming receive start event, respond by specifying local file to save to
+ * 			if (event instanceof IIncomingFileTransferReceiveStartEvent) {
+ * 				IIncomingFileTransferReceiveStartEvent rse = (IIncomingFileTransferReceiveStartEvent) event;
+ * 				try {
+ * 					rse.receive(new File("composent.main.page.html"));
+ * 				} catch (IOException e) {
+ * 					// Handle exception appropriately 
+ * 				}
+ * 			}
+ * 		}
+ * 	};
+ * 	// Identify file to retrieve and create ID
+ * 	IFileID remoteFileID = FileIDFactory.getDefault().createID(
+ * 			ftc.getRetrieveNamespace(), "http://www.composent.com/index.html");
+ * 	// Actually make request to start retrieval.  The listener provided will then be notified asynchronously 
+ * 	// as file transfer events occur
+ * 	ftc.sendRetrieveRequest(remoteFileID, listener, null);
+ * }
+ * 
+ * + * Where the IFileTransferEvent subtypes for the receiver will be: + *
    + *
  • {@link IIncomingFileTransferReceiveStartEvent}
  • + *
  • {@link IIncomingFileTransferReceiveDataEvent}
  • + *
  • {@link IIncomingFileTransferReceiveDoneEvent}
  • + *
+ */ +public interface IRetrieveFileTransferContainerAdapter extends IAdaptable { + + /** + * Send request for transfer of a remote file to local file storage. This + * method is used to initiate a file retrieve for a remoteFileID (first + * parameter). File transfer events are asynchronously delivered a file + * transfer listener (second parameter). The given remoteFileID and + * transferListener must not be null. + *

+ * NOTE: if this method completes successfully, the given transferListener + * will be asynchronously notified via an IIncomingFileTransferReceiveDoneEvent + * (along with other possible events). All implementations are required to + * issue this event whether successful or failed. Listeners + * can consult {@link IIncomingFileTransferReceiveDoneEvent#getException()} to + * determine whether the transfer operation completed successfully. + *

+ * @param remoteFileID + * reference to the remote target file (e.g. + * http://www.eclipse.org/index.html) or a reference to a + * resource that specifies the location of a target file. + * Implementing providers will determine what protocol schemes + * are supported (e.g. ftp, http, torrent, file, etc) and the + * required format of the scheme-specific information. If a + * protocol is specified that is not supported, or the + * scheme-specific information is not well-formed, then an + * IncomingFileTransferException will be thrown. Typically, + * callers will create IFileID instances via calls such as: + * + *
+	 * IFileID remoteFileID = FileIDFactory.getDefault().createID(
+	 * 		ftc.getRetrieveNamespace(), "http://www.composent.com/index.html");
+	 * 
+ * + * Must not be null. + * @param transferListener + * a listener for file transfer events. Must not be null. Must not be null. See Note above. + * @param options + * a Map of options associated with sendRetrieveRequest. The + * particular name/value pairs will be unique to the individual + * providers. May be null. + * @throws IncomingFileTransferException + * if the provider is not connected or is not in the correct + * state for initiating file transfer + */ + public void sendRetrieveRequest(IFileID remoteFileID, IFileTransferListener transferListener, Map options) throws IncomingFileTransferException; + + /** + * Send request for transfer of a remote file to local file storage. This + * method is used to initiate a file retrieve for a remoteFileID (first + * parameter). File transfer events are asynchronously delivered a file + * transfer listener (third parameter). The given remoteFileID and + * transferListener must not be null. + *

+ * NOTE: if this method completes successfully, the given transferListener + * will be asynchronously notified via an IIncomingFileTransferReceiveDoneEvent + * (along with other possible events). All implementations are required to + * issue this event whether successful or failed. Listeners + * can consult {@link IIncomingFileTransferReceiveDoneEvent#getException()} to + * determine whether the transfer operation completed successfully. + *

+ * @param remoteFileID + * reference to the remote target file (e.g. + * http://www.eclipse.org/index.html) or a reference to a + * resource that specifies the location of a target file. + * Implementing providers will determine what protocol schemes + * are supported (e.g. ftp, http, torrent, file, etc) and the + * required format of the scheme-specific information. If a + * protocol is specified that is not supported, or the + * scheme-specific information is not well-formed, then an + * IncomingFileTransferException will be thrown. Typically, + * callers will create IFileID instances via calls such as: + * + *
+	 * IFileID remoteFileID = FileIDFactory.getDefault().createID(
+	 * 		ftc.getRetrieveNamespace(), "http://www.composent.com/index.html");
+	 * 
+ * + * Must not be null. + * @param rangeSpecification a range specification for retrieving a portion of the given + * remote file. If null the entire file will be retrieved (as per {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)}. + * If non-null the given file range will be used to retrieve the given file. For example, if the + * rangeSpecification has a start value of 1 and end value of 3, and the total length of the file is + * 5 bytes with content [a, b, c, d, e], a successful retrieve request would transfer bytes 'b', 'c', and 'd', but not 'a', and 'e'. + * @param transferListener + * a listener for file transfer events. Must not be null. See Note above. + * @param options + * a Map of options associated with sendRetrieveRequest. The + * particular name/value pairs will be unique to the individual + * providers. May be null. + * @throws IncomingFileTransferException + * if the provider is not connected or is not in the correct + * state for initiating file transfer + */ + public void sendRetrieveRequest(IFileID remoteFileID, IFileRangeSpecification rangeSpecification, IFileTransferListener transferListener, Map options) throws IncomingFileTransferException; + + /** + * Get namespace to be used for creation of remoteFileID for retrieve + * request. Result typically used as first parameter for + * {@link IDFactory#createID(Namespace, String)} to be used as first in + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)} + * + * @return Namespace to use for ID creation via + * {@link IDFactory#createID(Namespace, String)}. Will not be + * null. + */ + public Namespace getRetrieveNamespace(); + + /** + * Set connect context for authentication upon subsequent + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)}. This + * method should be called with a non-null connectContext in order to allow + * authentication to occur during call to + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)}. + * + * @param connectContext + * the connect context to use for authenticating during + * subsequent call to + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)}. + * If null, then no authentication will be + * attempted. + */ + public void setConnectContextForAuthentication(IConnectContext connectContext); + + /** + * Set proxy for use upon subsequent + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)}. This + * method should be called with proxy to allow the given proxy to + * be used in subsequent calls to + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)}. + *

+ * When proxy is null or has not been called providers must use + * the org.eclipse.core.net proxy API to obtain proxy information + * and proxy credentials if they support proxies of the type(s) supported by + * that API. The API is provided by an OSGi service of type + * org.eclipse.core.net.proxy.IProxyService. + *

+ * If no information is available via IProxyService + * providers may use other defaults. + *

+ * + * @param proxy + * the proxy to use for subsequent calls to + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)}. + * If null, then proxy information is obtained from + * IProxyService if available. Otherwise provider + * defined defaults may be used. + */ + public void setProxy(Proxy proxy); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferOptions.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferOptions.java new file mode 100644 index 0000000000..58eb2c5793 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IRetrieveFileTransferOptions.java @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (c) 2009 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import java.util.Map; + +/** + * @since 3.1 + * + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IRetrieveFileTransferOptions { + + /** + * This constant defines a key in options Map passed to {@link IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, IFileTransferListener, java.util.Map)}. + * Supporting providers will use this key to look for a value of type Map, and if found the String key/value pairs in the + * Map will be used as request headers. The expected type of the value associated with this key is of type {@link Map}. + * + */ + public static final String REQUEST_HEADERS = IRetrieveFileTransferOptions.class.getName() + ".requestHeaders"; //$NON-NLS-1$ + + /** + * This constant defines a key in options Map passed to {@link IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, IFileTransferListener, java.util.Map)}. + * Supporting providers will use this key to look for a value of type Integer or String, and if found this value + * will be used to determine the socket connection timeout for this request. The expected type of the value + * associated with this key is of type Integer, or String value of an Integer. + */ + public static final String CONNECT_TIMEOUT = IRetrieveFileTransferOptions.class.getName() + ".connectTimeout"; //$NON-NLS-1$ + + /** + * This constant defines a key in options Map passed to {@link IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, IFileTransferListener, java.util.Map)}. + * Supporting providers will use this key to look for a value of type Integer or String, and if found this value + * will be used to determine the socket read timeout for this request. The expected type of the value + * associated with this key is of type Integer, or String value of an Integer. + */ + public static final String READ_TIMEOUT = IRetrieveFileTransferOptions.class.getName() + ".readTimeout"; //$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferContainerAdapter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferContainerAdapter.java new file mode 100644 index 0000000000..4d97ccaa13 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferContainerAdapter.java @@ -0,0 +1,188 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import java.io.File; +import java.util.Map; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.core.IContainer; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.events.*; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Entry point outgoing file transfer container adapter. This adapter interface + * allows providers to expose file sending semantics to clients in a transport + * independent manner. To be used, a non-null adapter reference must be returned + * from a call to {@link IContainer#getAdapter(Class)}. Once a non-null + * reference is retrieved, then it may be used to request to send a file to a + * remote user. Events will then be asynchronously delivered to the provided + * listener to complete file transfer. + *

+ * To request and initiate sending a local file to a remote user: + * + *

+ *      // Get ISendFileTransferContainerAdapter adapter
+ *       ISendFileTransferContainerAdapter ftc = (ISendFileTransferContainerAdapter) container.getAdapter(ISendFileTransferContainerAdapter.class);
+ *       if (ftc != null) {
+ *         // Create listener for receiving/responding to asynchronous file transfer events
+ *     	     IFileTransferListener listener = new IFileTransferListener() {
+ *     		     public void handleTransferEvent(IFileTransferEvent event) {
+ *                   // If this event is a response to the transfer request, check if file transfer rejected
+ *                   if (event instanceof IOutgoingFileTransferResponseEvent) {
+ *                       IOutgoingFileTransferResponseEvent oftr = (IOutgoingFileTransferResponseEvent) event;
+ *                       if (!oftr.requestAccepted()) {
+ *                           // request rejected...tell user
+ *                       }
+ *                   }
+ *     		     }
+ *     	     };
+ *           // Specify the target file ID
+ *           // This following specifies the path:  ~/path/filename.ext
+ *           ID targetID = FileIDFactory.getDefault().createFileID(ftc.getOutgoingNamespace(),new URL("scp://user@host/path/filename.ext"));
+ *           // This following specifies the path:  /path/filename.ext
+ *           // ID targetID = FileIDFactory.getDefault().createFileID(ftc.getOutgoingNamespace(),new URL("scp://user@host//path/filename.ext"));
+ *           // Specify the local file to send
+ *           File localFileToSend = new File("filename");
+ *           // Actually send outgoing file request to remote user.  
+ *           ftc.sendOutgoingRequest(targetID, localFileToSend, listener, null);
+ *       }
+ * 
+ * + * For the sender the delivered events will be: + *
    + *
  • {@link IOutgoingFileTransferResponseEvent}
  • + *
  • {@link IOutgoingFileTransferSendDataEvent}
  • + *
  • {@link IOutgoingFileTransferSendDoneEvent}
  • + *
+ * and for the {@link IIncomingFileTransferRequestListener} events + * delivered will be: + *
    + *
  • {@link IFileTransferRequestEvent}
  • + *
  • {@link IIncomingFileTransferReceiveDataEvent}
  • + *
  • {@link IIncomingFileTransferReceiveDoneEvent}
  • + *
+ */ +public interface ISendFileTransferContainerAdapter extends IAdaptable { + /** + * Send request for outgoing file transfer. This method is used to initiate + * a file transfer to a targetReceiver (first parameter) of the + * localFileToSend (second parameter). File transfer events are + * asynchronously delivered to the file transferListener (third parameter) + * + * @param targetReceiver + * the ID of the remote to receive the file transfer request. + * Must not be should not be null. + * @param localFileToSend + * the {@link IFileTransferInfo} for the local file to send. Must + * not be should not be null. + * @param transferListener + * a {@link IFileTransferListener} for responding to file + * transfer events. Must not be should not be null.. + * If the target receiver responds then an + * {@link IOutgoingFileTransferResponseEvent} will be delivered + * to the listener + * @param options + * a Map of options associated with sendOutgoingRequest. The + * particular name/value pairs will be unique to the individual + * providers. May be should not be null.. + * @throws SendFileTransferException + * if the provider is not connected or is not in the correct + * state for initiating file transfer + */ + public void sendOutgoingRequest(IFileID targetReceiver, IFileTransferInfo localFileToSend, IFileTransferListener transferListener, Map options) throws SendFileTransferException; + + /** + * Send request for outgoing file transfer. This method is used to initiate + * a file transfer to a targetReceiver (first parameter) of the + * localFileToSend (second parameter). File transfer events are + * asynchronously delivered to the file transferListener (third parameter) + * + * @param targetReceiver + * the ID of the remote to receive the file transfer request. + * Must not be null. + * @param localFileToSend + * the {@link File} for the local file to send. Must not be + * null. + * @param transferListener + * a {@link IFileTransferListener} for responding to file + * transfer events. Must not be null. If the + * target receiver responds then an IOutgoingFileTransfer will be + * delivered to the listener + * @param options + * a Map of options associated with sendOutgoingRequest. The + * particular name/value pairs will be unique to the individual + * providers. May be null. + * @throws SendFileTransferException + * if the provider is not connected or is not in the correct + * state for initiating file transfer + */ + public void sendOutgoingRequest(IFileID targetReceiver, File localFileToSend, IFileTransferListener transferListener, Map options) throws SendFileTransferException; + + /** + * Add incoming file transfer listener. If the underlying provider supports + * receiving file transfer requests + * + * @param listener + * to receive incoming file transfer request events. Must not be + * null. + */ + public void addListener(IIncomingFileTransferRequestListener listener); + + /** + * Remove incoming file transfer listener + * + * @param listener + * the listener to remove. Must not be null. + * @return true if listener actually removed, false otherwise + */ + public boolean removeListener(IIncomingFileTransferRequestListener listener); + + /** + * Get namespace for outgoing file transfer. + * @return Namespace for outgoing IFileID instances. Will not return null. + */ + public Namespace getOutgoingNamespace(); + + /** + * Set connect context for authentication upon subsequent + * {@link #sendOutgoingRequest(IFileID, IFileTransferInfo, IFileTransferListener, Map)}. This + * method should be called with a non-null connectContext in order to allow + * authentication to occur during call to + * {@link #sendOutgoingRequest(IFileID, IFileTransferInfo, IFileTransferListener, Map)}. + * + * @param connectContext + * the connect context to use for authenticating during + * subsequent call to + * {@link #sendOutgoingRequest(IFileID, IFileTransferInfo, IFileTransferListener, Map)}. + * If null, then no authentication will be + * attempted. + */ + public void setConnectContextForAuthentication(IConnectContext connectContext); + + /** + * Set proxy for use upon subsequent + * {@link #sendOutgoingRequest(IFileID, IFileTransferInfo, IFileTransferListener, Map)}. This + * method should be called with a non-null proxy to allow the given proxy to + * be used in subsequent calls to + * {@link #sendOutgoingRequest(IFileID, IFileTransferInfo, IFileTransferListener, Map)}. + * + * @param proxy + * the proxy to use for subsequent calls to + * {@link #sendOutgoingRequest(IFileID, IFileTransferInfo, IFileTransferListener, Map)}. + * If null, then no proxy will be used. + */ + public void setProxy(Proxy proxy); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferOptions.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferOptions.java new file mode 100644 index 0000000000..09a4c4d39e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/ISendFileTransferOptions.java @@ -0,0 +1,22 @@ +/**************************************************************************** + * Copyright (c) 2009 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +/** + * @since 3.1 + * + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ISendFileTransferOptions { + // Nothing +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IncomingFileTransferException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IncomingFileTransferException.java new file mode 100644 index 0000000000..ff1beb1148 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/IncomingFileTransferException.java @@ -0,0 +1,117 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import java.util.Map; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * Exception thrown upon incoming file transfer problem + * + */ +public class IncomingFileTransferException extends ECFException { + + private static final long serialVersionUID = 2438441801862623371L; + + private int errorCode = -1; + private Map responseHeaders; + + public IncomingFileTransferException(IStatus status) { + super(status); + } + + public IncomingFileTransferException() { + // null constructor + } + + public IncomingFileTransferException(int errorCode) { + this(); + this.errorCode = errorCode; + } + + public IncomingFileTransferException(String message) { + super(message); + } + + public IncomingFileTransferException(String message, int errorCode) { + super(message); + this.errorCode = errorCode; + } + + public IncomingFileTransferException(Throwable cause) { + super(cause); + } + + public IncomingFileTransferException(Throwable cause, int errorCode) { + super(cause); + this.errorCode = errorCode; + } + + public IncomingFileTransferException(String message, Throwable cause) { + super(message, cause); + } + + public IncomingFileTransferException(String message, Throwable cause, int errorCode) { + super(message, cause); + this.errorCode = errorCode; + } + + /** + * @param message message + * @param cause cause + * @param errorCode errorCode + * @param responseHeaders responseHeaders + * @since 4.0 + */ + public IncomingFileTransferException(String message, Throwable cause, int errorCode, Map responseHeaders) { + super(message, cause); + this.errorCode = errorCode; + this.responseHeaders = responseHeaders; + } + + /** + * @param message message + * @param errorCode errorCode + * @param responseHeaders responseHeaders + * @since 4.0 + */ + public IncomingFileTransferException(String message, int errorCode, Map responseHeaders) { + super(message); + this.errorCode = errorCode; + this.responseHeaders = responseHeaders; + } + + /** + * @param cause cause + * @param errorCode errorCode + * @param responseHeaders responseHeaders + * @since 4.0 + */ + public IncomingFileTransferException(Throwable cause, int errorCode, Map responseHeaders) { + super(cause); + this.errorCode = errorCode; + this.responseHeaders = responseHeaders; + } + + public int getErrorCode() { + return errorCode; + } + + /** + * @since 4.0 + * @return Map response headers + */ + public Map getResponseHeaders() { + return responseHeaders; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/InvalidFileRangeSpecificationException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/InvalidFileRangeSpecificationException.java new file mode 100644 index 0000000000..bda248d97c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/InvalidFileRangeSpecificationException.java @@ -0,0 +1,76 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IStatus; + +/** + * + */ +public class InvalidFileRangeSpecificationException extends IncomingFileTransferException { + + private static final long serialVersionUID = 532923607480972210L; + + private IFileRangeSpecification rangeSpec = null; + + /** + * @param rangeSpec rangeSpec + */ + public InvalidFileRangeSpecificationException(IFileRangeSpecification rangeSpec) { + super(); + this.rangeSpec = rangeSpec; + } + + /** + * @param status status + * @param rangeSpec range spec + */ + public InvalidFileRangeSpecificationException(IStatus status, IFileRangeSpecification rangeSpec) { + super(status); + this.rangeSpec = rangeSpec; + } + + /** + * @param message message + * @param cause cause + * @param rangeSpec range spec + */ + public InvalidFileRangeSpecificationException(String message, Throwable cause, IFileRangeSpecification rangeSpec) { + super(message, cause); + this.rangeSpec = rangeSpec; + } + + /** + * @param message message + * @param rangeSpec range spec + */ + public InvalidFileRangeSpecificationException(String message, IFileRangeSpecification rangeSpec) { + super(message); + this.rangeSpec = rangeSpec; + } + + /** + * @param cause cause + * @param rangeSpec range spec + */ + public InvalidFileRangeSpecificationException(Throwable cause, IFileRangeSpecification rangeSpec) { + super(cause); + this.rangeSpec = rangeSpec; + } + + public IFileRangeSpecification getFileRangeSpecification() { + return this.rangeSpec; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/RemoteFileSystemException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/RemoteFileSystemException.java new file mode 100644 index 0000000000..b52d5b4ea0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/RemoteFileSystemException.java @@ -0,0 +1,62 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * + */ +public class RemoteFileSystemException extends ECFException { + + private static final long serialVersionUID = -2199951600347999396L; + + /** + * + */ + public RemoteFileSystemException() { + super(); + } + + /** + * @param status status + */ + public RemoteFileSystemException(IStatus status) { + super(status); + } + + /** + * @param message message + * @param cause cause + */ + public RemoteFileSystemException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param message message + */ + public RemoteFileSystemException(String message) { + super(message); + } + + /** + * @param cause cause + */ + public RemoteFileSystemException(Throwable cause) { + super(cause); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/SendFileTransferException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/SendFileTransferException.java new file mode 100644 index 0000000000..5e0534d348 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/SendFileTransferException.java @@ -0,0 +1,70 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * Outgoing file transfer exception + * + */ +public class SendFileTransferException extends ECFException { + + private static final long serialVersionUID = -3752377147967128446L; + + private int errorCode = -1; + + public SendFileTransferException(IStatus status) { + super(status); + } + + public SendFileTransferException() { + // null constructor + } + + public SendFileTransferException(int errorCode) { + this(); + this.errorCode = errorCode; + } + + public SendFileTransferException(String message) { + super(message); + } + + public SendFileTransferException(String message, int errorCode) { + super(message); + this.errorCode = errorCode; + } + + public SendFileTransferException(Throwable cause) { + super(cause); + } + + public SendFileTransferException(Throwable cause, int errorCode) { + super(cause); + this.errorCode = errorCode; + } + + public SendFileTransferException(String message, Throwable cause) { + super(message, cause); + } + + public SendFileTransferException(String message, Throwable cause, int errorCode) { + super(message, cause); + this.errorCode = errorCode; + } + + public int getErrorCode() { + return errorCode; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/UserCancelledException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/UserCancelledException.java new file mode 100644 index 0000000000..a5359052f7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/UserCancelledException.java @@ -0,0 +1,45 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc., Peter Nehrer, Boris Bokowski. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * Exception class for user cancellation + * + */ +public class UserCancelledException extends ECFException { + + private static final long serialVersionUID = -1147166028435325320L; + + public UserCancelledException() { + // null constructor + } + + public UserCancelledException(IStatus status) { + super(status); + } + + public UserCancelledException(String message) { + super(message); + } + + public UserCancelledException(Throwable cause) { + super(cause); + } + + public UserCancelledException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferConnectStartEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferConnectStartEvent.java new file mode 100644 index 0000000000..c931182f63 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferConnectStartEvent.java @@ -0,0 +1,95 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.ecf.filetransfer.*; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Event sent to {@link IFileTransferListener} associated with + * {@link IIncomingFileTransfer} or + * {@link IOutgoingFileTransferEvent} or + * {@link IRemoteFileSystemRequest} instances. + *

+ * The event is send before the first request is send to the server. + * It allows the caller to get a handle to the transfer so that it can be + * canceled. + * A transfer may have to send several requests to one (or more + * servers) until the retrieved or send data itself is send or received. + * The entire phase before this is referred here as connect phase. + *

+ *

+ * If {@link #connectUsingJob(FileTransferJob)} is called then the connect + * phase is performed in a job. If not the caller may implement their own thread + * in which it can cancel the request. The expectation is that the + * cancellation will react with little delay, typically in less than 1 second. + *

+ *

+ * Not all providers support this event. + *

+ * @since 3.0 + */ +public interface IFileTransferConnectStartEvent extends IAdaptable, IFileTransferEvent { + + IFileID getFileID(); + + /** + * Cancel file transfer. + */ + void cancel(); + + // IFileTransfer getFileTransfer(); + + /** + * Prepare custom connect job or get default connect job. + *

+ * As a result the connect job will be tied to the transfer. Only if the + * returned job is passed into + * {@link #connectUsingJob(FileTransferJob)} will it actually be scheduled to + * run. + *

+ * + * @param connectJob + * A subclass of {@link FileTransferJob} to use to run the + * connection process. If null, the provider will + * use create and prepare a default connect job. + * NOTE: the given job should *not* be + * scheduled/started prior to being provided as a parameter to + * this method. + * @return passed in job or default connect job if parameter connectJob was + * null. + */ + FileTransferJob prepareConnectJob(FileTransferJob connectJob); + + /** + * Connect using a job. + *

+ * The passed in connectJob must have been prepared using + * {@link #prepareConnectJob(FileTransferJob)}. + * The job may be scheduled after the caller returns from handling of + * the {@link IFileTransferConnectStartEvent}. As this is provider + * implementation specific it must not relied on. + *

+ * + * @param connectJob + * A subclass of {@link FileTransferJob} to use to run the + * connection process. Must not be null. + * NOTE: the given job should *not* be + * scheduled/started prior to being provided as a parameter to + * this method. + * + */ + void connectUsingJob(FileTransferJob connectJob); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferEvent.java new file mode 100644 index 0000000000..90aa6687ff --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferEvent.java @@ -0,0 +1,22 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.core.util.Event; + +/** + * Super interface for all file transfer events + * + */ +public interface IFileTransferEvent extends Event { + // no methods for interface +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferRequestEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferRequestEvent.java new file mode 100644 index 0000000000..65cca8b354 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IFileTransferRequestEvent.java @@ -0,0 +1,102 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import java.io.File; +import java.io.OutputStream; + +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.filetransfer.IFileTransferInfo; +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IIncomingFileTransfer; +import org.eclipse.ecf.filetransfer.IIncomingFileTransferRequestListener; +import org.eclipse.ecf.filetransfer.IncomingFileTransferException; + +/** + * Event to represent remote file transfer requests. Events implementing this + * interface are delivered to {@link IIncomingFileTransferRequestListener} + * + * @see IIncomingFileTransferRequestListener#handleFileTransferRequest(IFileTransferRequestEvent) + */ +public interface IFileTransferRequestEvent extends IFileTransferEvent { + /** + * Get ID of remote requester + * + * @return ID of remote requester. Will not be null. + */ + public ID getRequesterID(); + + /** + * Get file transfer info associated with this file transfer request even + * + * @return IFileTransfer info. Will not be null. + */ + public IFileTransferInfo getFileTransferInfo(); + + /** + * Accept the file transfer request. This method should be called if the + * receiver of the IFileTransferRequestEvent would like to accept the file + * transfer request. Will not return null. Once called + * successfully, then {@link #requestAccepted()} will return true, and + * further calls to {@link #accept(File)} or + * {@link #accept(OutputStream, IFileTransferListener)} will throw + * IncomingFileTransferExceptions. + * + * @param localFileToSave + * the file on the local file system to receive the remote file. + * Must not be null. + * @return IIncomingFileTransfer to receive file. Will not be + * null. + * @throws IncomingFileTransferException + * if accept message cannot be delivered back to requester + */ + public IIncomingFileTransfer accept(File localFileToSave) throws IncomingFileTransferException; + + /** + * Accept the file transfer request. This method should be called if the + * receiver of the IFileTransferRequestEvent would like to accept the file + * transfer request. Will not return null. Once called + * successfully, then {@link #requestAccepted()} will return true, and + * further calls to {@link #accept(File)} or + * {@link #accept(OutputStream, IFileTransferListener)} will throw + * IncomingFileTransferExceptions. + * + * @param outputStream + * the output stream to receive the accepted file contents. Must + * not be null. + * @param listener + * for file transfer events during file reception. May be + * null. + * @return IIncomingFileTransfer to receive file. Will not be + * null. + * @throws IncomingFileTransferException + * if accept message cannot be delivered back to requester + */ + public IIncomingFileTransfer accept(OutputStream outputStream, IFileTransferListener listener) throws IncomingFileTransferException; + + /** + * Reject the file transfer request. This method should be called if the + * receiver of the IFileTransferRequestEvent would like to reject the file + * transfer request + * + */ + public void reject(); + + /** + * If request was accepted from remote target (via successful call to + * {@link #accept(File)}this method will return true, if rejected or failed + * returns false. + * + * @return true if request was accepted, false if rejected or failed + */ + public boolean requestAccepted(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferEvent.java new file mode 100644 index 0000000000..d7a9fc8d2f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferEvent.java @@ -0,0 +1,28 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.IIncomingFileTransfer; + +/** + * Super interface for incoming file transfer events + * + */ +public interface IIncomingFileTransferEvent extends IFileTransferEvent { + /** + * Get {@link IIncomingFileTransfer} associated with this event + * + * @return IIncomingFileTransfer that is source of this event. Will not be + * null. + */ + public IIncomingFileTransfer getSource(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDataEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDataEvent.java new file mode 100644 index 0000000000..9361ebf491 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDataEvent.java @@ -0,0 +1,24 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IIncomingFileTransfer; + +/** + * Event sent to {@link IFileTransferListener} associated with + * {@link IIncomingFileTransfer} instances data are received + * + */ +public interface IIncomingFileTransferReceiveDataEvent extends IIncomingFileTransferEvent { + // no methods for interface +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDoneEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDoneEvent.java new file mode 100644 index 0000000000..8943b30bfb --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveDoneEvent.java @@ -0,0 +1,39 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.UserCancelledException; + +/** + * Event sent to IFileTransferListeners when an incoming file transfer is + * completed. + * + */ +public interface IIncomingFileTransferReceiveDoneEvent extends IIncomingFileTransferEvent { + + /** + * Get any exception associated with this file transfer. If the file + * transfer completed successfully, this method will return + * null. If the file transfer completed unsuccessfully (some + * exception occurred), then this method will return a non-null + * Exception instance that occurred. + *

+ * If the the file transfer was canceled by the user, then the exception + * returned will be an instance of {@link UserCancelledException}. + * + * @return Exception associated with this file transfer. null + * if transfer completed successfully, non-null if transfer + * completed with some exception. + */ + public Exception getException(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceivePausedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceivePausedEvent.java new file mode 100644 index 0000000000..b6eae4088d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceivePausedEvent.java @@ -0,0 +1,21 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +/** + * Event sent to IFileTransferListeners when an incoming file transfer is + * paused. + * + */ +public interface IIncomingFileTransferReceivePausedEvent extends IIncomingFileTransferEvent { + // no methods +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveResumedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveResumedEvent.java new file mode 100644 index 0000000000..56b9c3220d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveResumedEvent.java @@ -0,0 +1,155 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * Cloudsmith, Inc. - additional API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import java.io.*; +import java.util.Map; +import org.eclipse.ecf.filetransfer.*; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Event sent to {@link IFileTransferListener} associated with + * {@link IIncomingFileTransfer} instances when file transfer is resumed. + * + */ +public interface IIncomingFileTransferReceiveResumedEvent extends IIncomingFileTransferEvent { + + /** + * Get IFileID for incoming file + * + * @return IFileID for this file transfer event. Will not be + * null. + */ + public IFileID getFileID(); + + /** + * Get incoming file transfer object by specifying a local File instance to + * save the received contents to. + * + * @param localFileToSave + * the file on the local file system to receive and save the + * remote file. Must not be null. + * @param append + * if true, and data received is appended to the + * given localFileToSave. If false, data are written + * to the beginning of the given localFileToSave, and any + * existing contents are overwritten. + * @return IIncomingFileTransfer the incoming file transfer object. Will not + * be null. + * @throws IOException + * if localFileToSave cannot be opened for writing. + * @since 2.0 + */ + public IIncomingFileTransfer receive(File localFileToSave, boolean append) throws IOException; + + /** + * Just like {@link #receive(File,boolean)} but this method also give the + * caller a chance to provide a factory that creates the job that will + * perform the actual file transfer. The intended use for this is when the + * user of the framework needs more elaborate control over such jobs such as + * waiting for a group of parallel file transfers to complete. Such + * functionality can for instance exploit the Eclipse runtime concept of Job + * families. + * + * @param localFileToSave + * the file on the local file system to receive and save the + * remote file. Must not be null. + * @param append + * if true, and data received is appended to the + * given localFileToSave. If false, data are written + * to the beginning of the given localFileToSave, and any + * existing contents are overwritten. + * @param fileTransferJob + * A subclass of {@link FileTransferJob} to use to run the actual + * transfer. If null, provider will create default + * implementation. NOTE: the given job should *not* be + * scheduled/started prior to being provided as parameter to this + * method. + * @return IIncomingFileTransfer the incoming file transfer object. NOTE: + * the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the + * stream provided is buffered, then + * {@link BufferedOutputStream#flush()} should be called to + * guarantee that the data received is actually written to the given + * OutputStream. + * @throws IOException + * if streamToStore cannot be opened for writing. + * @since 2.0 + */ + public IIncomingFileTransfer receive(File localFileToSave, FileTransferJob fileTransferJob, boolean append) throws IOException; + + /** + * Get incoming file transfer by specifying an OutputStream instance to save + * the received contents to. NOTE: the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the stream + * provided is buffered, then {@link BufferedOutputStream#flush()} should be + * called to guaranteed that the data received is actually written to the + * given OutputStream. + * + * @param streamToStore + * the output stream to store the incoming file. Must not be + * null. + * @return IIncomingFileTransfer the incoming file transfer object. NOTE: + * the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the + * stream provided is buffered, then + * {@link BufferedOutputStream#flush()} should be called to + * guarantee that the data received is actually written to the given + * OutputStream. + * @throws IOException + * if streamToStore cannot be opened for writing + */ + public IIncomingFileTransfer receive(OutputStream streamToStore) throws IOException; + + /** + * Just like {@link #receive(OutputStream)} but this method also give the + * caller a chance to provide a factory that creates the job that will + * perform the actual file transfer. The intended use for this is when the + * user of the framework needs more elaborate control over such jobs such as + * waiting for a group of parallel file transfers to complete. Such + * functionality can for instance exploit the Eclipse runtime concept of Job + * families. + * + * @param streamToStore + * the output stream to store the incoming file. Must not be + * null. + * @param fileTransferJob + * A subclass of {@link FileTransferJob} to use to run the actual + * transfer. If null, provider will create default + * implementation. NOTE: the given job should *not* be + * scheduled/started prior to being provided as a parameter to + * this method. + * @return IIncomingFileTransfer the incoming file transfer object. NOTE: + * the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the + * stream provided is buffered, then + * {@link BufferedOutputStream#flush()} should be called to + * guarantee that the data received is actually written to the given + * OutputStream. + * @throws IOException + * if streamToStore cannot be opened for writing + */ + public IIncomingFileTransfer receive(OutputStream streamToStore, FileTransferJob fileTransferJob) throws IOException; + + /** + * Cancel incoming file transfer + */ + public void cancel(); + + /** + * Get response headers. + * @return Map of response headers. null if no headers available. + * @since 4.0 + */ + public Map getResponseHeaders(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveStartEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveStartEvent.java new file mode 100644 index 0000000000..94d8543857 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IIncomingFileTransferReceiveStartEvent.java @@ -0,0 +1,143 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * Cloudsmith, Inc. - additional API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import java.io.*; +import java.util.Map; +import org.eclipse.ecf.filetransfer.*; +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * Event sent to {@link IFileTransferListener} associated with + * {@link IIncomingFileTransfer} instances + * + */ +public interface IIncomingFileTransferReceiveStartEvent extends IIncomingFileTransferEvent { + + /** + * Get IFileID for incoming file + * + * @return IFileID for this file transfer event. Will not be + * null. + */ + public IFileID getFileID(); + + /** + * Get incoming file transfer object by specifying a local File instance to + * save the received contents to. + * + * @param localFileToSave + * the file on the local file system to receive and save the + * remote file. Must not be null. If the file + * already exists, its content will be overwritten by any data + * received. + * @return IIncomingFileTransfer the incoming file transfer object. Will not + * be null. + * @throws IOException + * if localFileToSave cannot be opened for writing + */ + public IIncomingFileTransfer receive(File localFileToSave) throws IOException; + + /** + * Just like {@link #receive(File)} but this method also give the caller + * a chance to provide a factory that creates the job that will perform the + * actual file transfer. The intended use for this is when the user of the + * framework needs more elaborate control over such jobs such as waiting for a + * group of parallel file transfers to complete. Such functionality can for + * instance exploit the Eclipse runtime concept of Job families. + * + * @param localFileToSave + * the file on the local file system to receive and save the + * remote file. Must not be null. If the file + * already exists, its content will be overwritten by any data + * received. + * @param fileTransferJob A subclass of {@link FileTransferJob} to use to run the actual transfer. If + * null, provider will create default implementation. NOTE: the given job should + * *not* be scheduled/started prior to being provided as a parameter to this method. + * @return IIncomingFileTransfer the incoming file transfer object. NOTE: + * the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the + * stream provided is buffered, then + * {@link BufferedOutputStream#flush()} should be called to + * guaranteed that the data received is actually written to the + * given OutputStream. + * @throws IOException + * if streamToStore cannot be opened for writing + * + * @since 2.0 + */ + public IIncomingFileTransfer receive(File localFileToSave, FileTransferJob fileTransferJob) throws IOException; + + /** + * Get incoming file transfer by specifying an OutputStream instance to save + * the received contents to. NOTE: the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the stream + * provided is buffered, then {@link BufferedOutputStream#flush()} should be + * called to guaranteed that the data received is actually written to the + * given OutputStream. + * + * @param streamToStore + * the output stream to store the incoming file. Must not be + * null. + * @return IIncomingFileTransfer the incoming file transfer object. NOTE: + * the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the + * stream provided is buffered, then + * {@link BufferedOutputStream#flush()} should be called to + * guaranteed that the data received is actually written to the + * given OutputStream. + * @throws IOException + * if streamToStore cannot be opened for writing + */ + public IIncomingFileTransfer receive(OutputStream streamToStore) throws IOException; + + /** + * Just like {@link #receive(OutputStream)} but this method also give the caller + * a chance to provide a factory that creates the job that will perform the + * actual file transfer. The intended use for this is when the user of the + * framework needs more elaborate control over such jobs such as waiting for a + * group of parallel file transfers to complete. Such functionality can for + * instance exploit the Eclipse runtime concept of Job families. + * + * @param streamToStore + * the output stream to store the incoming file. Must not be + * null. + * @param fileTransferJob A subclass of {@link FileTransferJob} to use to run the actual transfer. If + * null, provider will create default implementation. NOTE: the given job should + * *not* be scheduled/started prior to being provided as a parameter to this method. + * @return IIncomingFileTransfer the incoming file transfer object. NOTE: + * the caller is responsible for calling + * {@link OutputStream#close()} on the OutputStream provided. If the + * stream provided is buffered, then + * {@link BufferedOutputStream#flush()} should be called to + * guaranteed that the data received is actually written to the + * given OutputStream. + * @throws IOException + * if streamToStore cannot be opened for writing + * + * @since 2.0 + */ + public IIncomingFileTransfer receive(OutputStream streamToStore, FileTransferJob fileTransferJob) throws IOException; + + /** + * Cancel incoming file transfer + */ + public void cancel(); + + /** + * Get response headers. + * @return Map of response headers. null if no headers available. + * @since 4.0 + */ + public Map getResponseHeaders(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferEvent.java new file mode 100644 index 0000000000..6fc9de3d67 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferEvent.java @@ -0,0 +1,28 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.IOutgoingFileTransfer; + +/** + * Super interface for outgoing file transfer events + * + */ +public interface IOutgoingFileTransferEvent extends IFileTransferEvent { + /** + * Get {@link IOutgoingFileTransfer} source associated with this event + * + * @return IOutgoingFileTransfer that is source of this event. Will not be + * null. + */ + public IOutgoingFileTransfer getSource(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferResponseEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferResponseEvent.java new file mode 100644 index 0000000000..6d2ee807e9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferResponseEvent.java @@ -0,0 +1,40 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * Cloudsmith, Inc. - additional API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.*; + +/** + * Asynchronous event sent to {@link IFileTransferListener} associated with + * {@link IOutgoingFileTransfer} instances when a response is received from the + * remote target (or provider times out). + * + */ +public interface IOutgoingFileTransferResponseEvent extends IOutgoingFileTransferEvent { + /** + * If request was accepted from remote target this method will return true, + * if rejected or failed returns false. + * + * @return true if request was accepted, false if rejected or failed + */ + public boolean requestAccepted(); + + /** + * Set the {@link FileTransferJob} to use for the actual file transfer. This method only + * has effect if the {@link #requestAccepted()} returns true. + * @param job the job to use. If null, or this method is not called, then + * a default FileTransferJob is used. NOTE: the given job should + * *not* be scheduled/started prior to being provided as a parameter to this method. + */ + public void setFileTransferJob(FileTransferJob job); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDataEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDataEvent.java new file mode 100644 index 0000000000..534da60a0b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDataEvent.java @@ -0,0 +1,24 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IOutgoingFileTransfer; + +/** + * Event sent to {@link IFileTransferListener} associated with + * {@link IOutgoingFileTransfer} instances when some data are received + * + */ +public interface IOutgoingFileTransferSendDataEvent extends IOutgoingFileTransferEvent { + // no methods for interface +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDoneEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDoneEvent.java new file mode 100644 index 0000000000..0c5aff4547 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendDoneEvent.java @@ -0,0 +1,25 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IOutgoingFileTransfer; + +/** + * Event sent to {@link IFileTransferListener} associated with + * {@link IOutgoingFileTransfer} instances when the file transfer is complete + * + */ +public interface IOutgoingFileTransferSendDoneEvent extends IOutgoingFileTransferEvent { + // no methods for interface + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendPausedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendPausedEvent.java new file mode 100644 index 0000000000..8db1714723 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendPausedEvent.java @@ -0,0 +1,21 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events; + +/** + * + */ +public interface IOutgoingFileTransferSendPausedEvent extends IOutgoingFileTransferEvent { + // no methods for interface +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendResumedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendResumedEvent.java new file mode 100644 index 0000000000..8f426aff38 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IOutgoingFileTransferSendResumedEvent.java @@ -0,0 +1,22 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events; + +/** + * + */ +public interface IOutgoingFileTransferSendResumedEvent extends IOutgoingFileTransferEvent { + // no methods for interface + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemBrowseEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemBrowseEvent.java new file mode 100644 index 0000000000..8c0a695dc4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemBrowseEvent.java @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright (c) 2007, 2009 Composent, Inc., IBM and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * Henrich Kraemer - bug 263613, [transport] Update site contacting / downloading is not cancelable + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.IRemoteFile; + +/** + * Event that indicates that a directory list is available via {@link #getRemoteFiles()}. + *

+ * This event is fired even if the browse failed or has been canceled. In this case + * the cause is provided via {@link #getException()}. + *

+ */ +public interface IRemoteFileSystemBrowseEvent extends IRemoteFileSystemEvent { + + /** + * Get the list of files associated with this browse event. If the original + * file ID available via {@link IRemoteFileSystemEvent#getFileID()} is a regular + * file, the array will be of length 1. If a directory, will be of length n. + * Is null if the associated IRemoteFileSystemRequest failed or was canceled. + * The cause will be available in {@link #getException()}. + * @return IRemoteFile[] the array of remote files for the given browse. If the original + * file ID available via {@link IRemoteFileSystemEvent#getFileID()} is a regular + * file, the array will be of length 1. If a directory, will be of length n. + * May be null. + */ + public IRemoteFile[] getRemoteFiles(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemEvent.java new file mode 100644 index 0000000000..9200089c46 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/IRemoteFileSystemEvent.java @@ -0,0 +1,27 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events; + +import org.eclipse.ecf.filetransfer.identity.IFileID; + +/** + * + */ +public interface IRemoteFileSystemEvent { + + public Exception getException(); + + public IFileID getFileID(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketClosedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketClosedEvent.java new file mode 100644 index 0000000000..9553ee4ffc --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketClosedEvent.java @@ -0,0 +1,37 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM Corporation and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events.socket; + + +/** + * Event issued after a socket has been closed. + *

+ * The associated source returned by {@link #getSource()} is + * the same as for the prior {@link ISocketCreatedEvent} and + * {@link ISocketConnectedEvent} with the same + * {@link #getFactorySocket()}. It may not reflect the source + * currently using or most recently using the socket. + *

+ + *

+ * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the ECF team. + *

+ * + * @since 3.0 + */ +public interface ISocketClosedEvent extends ISocketEvent { + // no additional info needed. +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketConnectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketConnectedEvent.java new file mode 100644 index 0000000000..8d0e0f0177 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketConnectedEvent.java @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM Corporation and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events.socket; + +import java.net.Socket; + +/** + * Event issued after a socket successfully connected. + *

+ * Can be used to wrap a socket by calling {@link #setSocket(Socket)}. + *

+ *

+ * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the ECF team. + *

+ * + * @since 3.0 + */ +public interface ISocketConnectedEvent extends ISocketEvent { + /** + * Sets a socket to be used by the app. + *

+ * If this method is not called {@link #getFactorySocket()} and + * {@link #getSocket()} will be the same. + * Otherwise {@link #getSocket()} will return the passed in socket. + *

+ * @param socket socket + */ + void setSocket(Socket socket); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketCreatedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketCreatedEvent.java new file mode 100644 index 0000000000..451660584e --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketCreatedEvent.java @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM Corporation and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events.socket; + +/** + * Event which makes a socket available after it has been + * created but before it is connected. + * + *

+ * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the ECF team. + *

+ * + * @since 3.0 + */ +public interface ISocketCreatedEvent extends ISocketEvent { + // empty +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEvent.java new file mode 100644 index 0000000000..20f0806cda --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEvent.java @@ -0,0 +1,58 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM Corporation and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.events.socket; + +import java.net.Socket; +import org.eclipse.ecf.core.util.Event; + +/** + * Socket events are emitted by a {@link ISocketEventSource} and + * are delivered to a {@link ISocketListener}. + *

+ * Beware that the associated source may not be instance currently + * using the socket. For example a socket may be put into a + * connection pool after it is used. It is then typically reused + * by another source. + * When a socket is closed this is attributed to the source which + * created it, not which currently or most recently used it. + *

+ *

This limits the usefulness of these events to cases + * where the caller can make broader assumptions for example + * because it wants to close or monitor all sockets in the + * entire application. + * The events are also useful for implementing unit tests. + *

+ *

+ * The {@link ISocketConnectedEvent} allows an + * {@link ISocketListener} to wrap the socket. + *

+ * + *

+ * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the ECF team. + *

+ * + * @since 3.0 + */ +public abstract interface ISocketEvent extends Event { + // IFileTransfer or IRemoteFileSystemRequest + ISocketEventSource getSource(); + + boolean isSameFactorySocket(ISocketEvent socketEvent); + + Socket getFactorySocket(); + + Socket getSocket(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEventSource.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEventSource.java new file mode 100644 index 0000000000..6da114d9ad --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketEventSource.java @@ -0,0 +1,25 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events.socket; + +import org.eclipse.core.runtime.IAdaptable; + +// IFileTransfer or IRemoteFileSystemRequest, other? +public interface ISocketEventSource extends IAdaptable { + void addListener(ISocketListener listener); + + void removeListener(ISocketListener listener); + + void fireEvent(ISocketEvent event); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketListener.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketListener.java new file mode 100644 index 0000000000..efcc1725d2 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socket/ISocketListener.java @@ -0,0 +1,18 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events.socket; + +public interface ISocketListener { + public void handleSocketEvent(ISocketEvent event); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socketfactory/INonconnectedSocketFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socketfactory/INonconnectedSocketFactory.java new file mode 100644 index 0000000000..0aea069950 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/events/socketfactory/INonconnectedSocketFactory.java @@ -0,0 +1,22 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.events.socketfactory; + +import java.io.IOException; +import java.net.Socket; + +public interface INonconnectedSocketFactory { + Socket createSocket() throws IOException; + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileCreateException.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileCreateException.java new file mode 100644 index 0000000000..f0e767195d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileCreateException.java @@ -0,0 +1,46 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.identity; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.ecf.core.util.ECFException; + +/** + * Exception class for creation of {@link IFileID} instances via + * {@link FileIDFactory} + * + */ +public class FileCreateException extends ECFException { + + private static final long serialVersionUID = -4242692047102300537L; + + public FileCreateException(IStatus status) { + super(status); + } + + public FileCreateException() { + super(); + } + + public FileCreateException(String message) { + super(message); + } + + public FileCreateException(Throwable cause) { + super(cause); + } + + public FileCreateException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileIDFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileIDFactory.java new file mode 100644 index 0000000000..959b78345b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/FileIDFactory.java @@ -0,0 +1,129 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.identity; + +import java.net.URI; +import java.net.URL; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.util.Trace; +import org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter; +import org.eclipse.ecf.internal.filetransfer.Activator; +import org.eclipse.ecf.internal.filetransfer.FileTransferDebugOptions; + +/** + * Factory class entry point for creating IFileID instances. + * + */ +public class FileIDFactory implements IFileIDFactory { + + protected static FileIDFactory instance = null; + + static { + instance = new FileIDFactory(); + } + + /** + * Get singleton instance + * + * @return FileIDFactory singleton instance. Will not be null. + * @since 5.0 + */ + public static FileIDFactory getDefault() { + return instance; + } + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param remoteFile + * the remote filename to use. Must not be null. + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + */ + public IFileID createFileID(Namespace namespace, URL remoteFile) throws FileCreateException { + return createFileID(namespace, new Object[] {remoteFile}); + } + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param remoteFile + * the remote filename to use. Must not be null. + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + */ + public IFileID createFileID(Namespace namespace, String remoteFile) throws FileCreateException { + return createFileID(namespace, new Object[] {remoteFile}); + } + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param remoteFile + * the remote resource identifier to use. Must not be null. + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + * @since 5.0 + */ + public IFileID createFileID(Namespace namespace, URI remoteFile) throws FileCreateException { + return createFileID(namespace, new Object[] {remoteFile}); + } + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param arguments + * Object [] of arguments to use to create file ID. These + * arguments will be passed to the + * {@link Namespace#createInstance(Object[])} method of the + * appropriate Namespace setup by the provider + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + */ + public IFileID createFileID(Namespace namespace, Object[] arguments) throws FileCreateException { + Trace.entering(Activator.PLUGIN_ID, FileTransferDebugOptions.METHODS_ENTERING, this.getClass(), "createFileID", new Object[] {namespace, arguments}); //$NON-NLS-1$ + try { + IFileID result = (IFileID) IDFactory.getDefault().createID(namespace, arguments); + Trace.exiting(Activator.PLUGIN_ID, FileTransferDebugOptions.METHODS_EXITING, this.getClass(), "createFileID", result); //$NON-NLS-1$ + return result; + } catch (Exception e) { + Trace.throwing(Activator.PLUGIN_ID, FileTransferDebugOptions.EXCEPTIONS_THROWING, FileIDFactory.class, "createFileID", e); //$NON-NLS-1$ + throw new FileCreateException("Exception in createFileID", e); //$NON-NLS-1$ + } + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileID.java new file mode 100644 index 0000000000..16eb5ffcfa --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileID.java @@ -0,0 +1,49 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.identity; + +import java.net.*; +import org.eclipse.ecf.core.identity.ID; + +/** + * ID for a remote file. + * + */ +public interface IFileID extends ID { + + /** + * Get the file name from this IFileID. This will return just the filename + * portion of a more complex file ID, e.g. index.html from IFileID created + * with value "http://www.composent.com/index.html" + * + * @return String just the file name and extension (if any) for this given + * IFileID. Will not be null. + */ + public String getFilename(); + + /** + * Get the url associated with the file identified by this IFileID. + * + * @return URL associated with this IFileID. Will not be null. + * @exception MalformedURLException thrown if URL cannot be created for this IFileID + */ + public URL getURL() throws MalformedURLException; + + /** + * Get the URI associated with the file identified by this IFileID. + * + * @return URI associated with this IFileID. Will not be null. + * @throws URISyntaxException thrown if URI cannot be created for this IFileID. + * @since 5.0 + */ + public URI getURI() throws URISyntaxException; +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileIDFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileIDFactory.java new file mode 100644 index 0000000000..240e68e4f4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/identity/IFileIDFactory.java @@ -0,0 +1,92 @@ +/**************************************************************************** + * Copyright (c) 2010 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.filetransfer.identity; + +import java.net.URI; +import java.net.URL; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter; + +/** + * @since 5.0 + */ +public interface IFileIDFactory { + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param remoteFile + * the remote filename to use. Must not be null. + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + */ + public IFileID createFileID(Namespace namespace, URL remoteFile) throws FileCreateException; + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param remoteFile + * the remote filename to use. Must not be null. + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + */ + public IFileID createFileID(Namespace namespace, String remoteFile) throws FileCreateException; + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param remoteFile + * the remote resource identifier to use. Must not be null. + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + * @since 5.0 + */ + public IFileID createFileID(Namespace namespace, URI remoteFile) throws FileCreateException; + + /** + * Create an IFileID from a Namespace and a String. + * + * @param namespace + * the namespace to use to create the IFileID. Can use + * {@link IRetrieveFileTransferContainerAdapter#getRetrieveNamespace()}. + * Must not be null. + * @param arguments + * Object [] of arguments to use to create file ID. These + * arguments will be passed to the + * {@link Namespace#createInstance(Object[])} method of the + * appropriate Namespace setup by the provider + * @return IFileID instance. Will not return null. + * @throws FileCreateException + * thrown if some problem creating IFileID from given namespace + * and filename + */ + public IFileID createFileID(Namespace namespace, Object[] arguments) throws FileCreateException; +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowser.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowser.java new file mode 100644 index 0000000000..ffa3ddbcfe --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowser.java @@ -0,0 +1,23 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.service; + +import org.eclipse.ecf.filetransfer.IRemoteFileSystemBrowserContainerAdapter; + +/** + * Remote file system browser service interface. See {@link IRemoteFileSystemBrowserContainerAdapter} + */ +public interface IRemoteFileSystemBrowser extends IRemoteFileSystemBrowserContainerAdapter { + // Methods in super interface +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowserFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowserFactory.java new file mode 100644 index 0000000000..edfa47c216 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRemoteFileSystemBrowserFactory.java @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.service; + +/** + * Remote file browser factory. This service interface is used by clients to + * create a new IRemoteFileSystemBrowser instance. + */ +public interface IRemoteFileSystemBrowserFactory { + + /** + * Get new instance of IRemoteFileSystemBrowser. + * + * @return IRemoteFileSystemBrowser for initiating a retrieval of a remote file. + */ + public IRemoteFileSystemBrowser newInstance(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransfer.java new file mode 100644 index 0000000000..a0f7cd418c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransfer.java @@ -0,0 +1,21 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.service; + +import org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter; + +public interface IRetrieveFileTransfer extends IRetrieveFileTransferContainerAdapter { + // no methods for interface + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransferFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransferFactory.java new file mode 100644 index 0000000000..50c0b6648d --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/IRetrieveFileTransferFactory.java @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.service; + +/** + * Retrieve file transfer factory. This service interface is used by clients to + * create a new IRetrieveFileTransfer instance. + */ +public interface IRetrieveFileTransferFactory { + + /** + * Get new instance of IRetrieveFileTransfer. + * + * @return IRetrieveFileTransfer for initiating a retrieval of a remote file. + */ + public IRetrieveFileTransfer newInstance(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransfer.java new file mode 100644 index 0000000000..b9cd2cb3bf --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransfer.java @@ -0,0 +1,21 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.service; + +import org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter; + +public interface ISendFileTransfer extends ISendFileTransferContainerAdapter { + // no methods for interface + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransferFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransferFactory.java new file mode 100644 index 0000000000..e5b510848c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/filetransfer/service/ISendFileTransferFactory.java @@ -0,0 +1,30 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.filetransfer.service; + +/** + * Send file transfer factory. This service interface is used by clients to + * create a new ISendFileTransfer instance, used to send file to remote + * clients. + */ +public interface ISendFileTransferFactory { + + /** + * Get new instance of ISendFileTransfer. + * + * @return ISendFileTransfer for initiating send of a local file. + */ + public ISendFileTransfer newInstance(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFDebugOptions.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFDebugOptions.java new file mode 100644 index 0000000000..6ae8fc32bb --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFDebugOptions.java @@ -0,0 +1,27 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.core; + +public interface ECFDebugOptions { + + public static final String DEBUG = ECFPlugin.PLUGIN_ID + "/debug"; //$NON-NLS-1$ + + public static final String EXCEPTIONS_CATCHING = DEBUG + "/exceptions/catching"; //$NON-NLS-1$ + + public static final String EXCEPTIONS_THROWING = DEBUG + "/exceptions/throwing"; //$NON-NLS-1$ + + public static final String METHODS_ENTERING = DEBUG + "/methods/entering"; //$NON-NLS-1$ + + public static final String METHODS_EXITING = DEBUG + "/methods/exiting"; //$NON-NLS-1$ + + public static final String BUNDLECLASSRESOLVER = DEBUG + "/bundleclassresolver"; //$NON-NLS-1$ +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFPlugin.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFPlugin.java new file mode 100644 index 0000000000..dbd24f72ab --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/ECFPlugin.java @@ -0,0 +1,583 @@ +/**************************************************************************** + * Copyright (c) 2004, 2020 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.core; + +import java.util.*; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.core.*; +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.core.provider.IContainerInstantiator; +import org.eclipse.ecf.core.security.ECFSSLContextFactory; +import org.eclipse.ecf.core.security.SSLContextFactory; +import org.eclipse.ecf.core.start.ECFStartJob; +import org.eclipse.ecf.core.start.IECFStart; +import org.eclipse.ecf.core.util.*; +import org.eclipse.ecf.internal.core.identity.Activator; +import org.osgi.framework.*; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +public class ECFPlugin implements BundleActivator { + + public static final String PLUGIN_ID = "org.eclipse.ecf"; //$NON-NLS-1$ + + private static final String ECFNAMESPACE = PLUGIN_ID; + + private static final String CONTAINER_FACTORY_NAME = "containerFactory"; //$NON-NLS-1$ + + private static final String CONTAINER_FACTORY_EPOINT = ECFNAMESPACE + "." + CONTAINER_FACTORY_NAME; //$NON-NLS-1$ + + private static final String STARTUP_NAME = "start"; //$NON-NLS-1$ + + public static final String START_EPOINT = ECFNAMESPACE + "." + STARTUP_NAME; //$NON-NLS-1$ + + public static final String PLUGIN_RESOURCE_BUNDLE = ECFNAMESPACE + ".ECFPluginResources"; //$NON-NLS-1$ + + public static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ + + public static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$ + + public static final String DESCRIPTION_ATTRIBUTE = "description"; //$NON-NLS-1$ + + public static final String VALUE_ATTRIBUTE = "value"; //$NON-NLS-1$ + + public static final String SERVER_ATTRIBUTE = "server"; //$NON-NLS-1$ + + public static final String HIDDEN_ATTRIBUTE = "hidden"; //$NON-NLS-1$ + + public static final String ASYNCH_ATTRIBUTE = "asynchronous"; //$NON-NLS-1$ + + public static final String CONTAINER_NAME = "container"; //$NON-NLS-1$ + + public static final String CONTAINER_EPOINT = ECFNAMESPACE + "." + CONTAINER_NAME; //$NON-NLS-1$ + + public static final String FACTORY_ATTRIBUTE = "factoryName"; //$NON-NLS-1$ + + public static final String ID_ATTRIBUTE = "containerId"; //$NON-NLS-1$ + + public static final String PARAMETER_ELEMENT = "parameter"; //$NON-NLS-1$ + + public static final String PARAMETER_NAME = "name"; //$NON-NLS-1$ + + public static final String PARAMETER_VALUE = "value"; //$NON-NLS-1$ + + // The shared instance. + private static ECFPlugin plugin; + + BundleContext context = null; + + private Map disposables = new HashMap(1); + + // This is Object rather than IExtensionRegistryManager to avoid loading + // IRegistryChangeListener class (optional) + Object registryManager = null; + + private ServiceRegistration containerFactoryServiceRegistration; + + private ServiceRegistration containerManagerServiceRegistration; + + private ServiceTracker logServiceTracker = null; + + private LogService logService = null; + + private AdapterManagerTracker adapterManagerTracker = null; + + private BundleActivator ecfTrustManager; + + private ServiceRegistration sslContextFactoryRegistration; + + private ECFSSLContextFactory ecfSSLContextFactory; + + /** + * Returns the shared instance. + * @return ECFPlugin + */ + public synchronized static ECFPlugin getDefault() { + if (plugin == null) + plugin = new ECFPlugin(); + return plugin; + } + + public BundleContext getContext() { + return context; + } + + public ECFPlugin() { + // null constructor + } + + void disposeContainersForDescription(ContainerTypeDescription description) { + String descriptionName = description.getName(); + IContainerManager cm = (IContainerManager) ContainerFactory.getDefault(); + List tbd = new ArrayList(); + for (IContainer c : cm.getAllContainers()) { + ID cID = c.getID(); + ContainerTypeDescription ctd = cm.getContainerTypeDescription(cID); + if (ctd != null && ctd.getName().equals(descriptionName)) { + IContainer container = cm.removeContainer(cID); + if (container != null) + tbd.add(container); + } + } + for (IContainer c : tbd) { + try { + c.dispose(); + } catch (Throwable t) { + // Log exception + ECFPlugin.getDefault().log(new Status(IStatus.ERROR, ECFPlugin.getDefault().getBundle().getSymbolicName(), IStatus.ERROR, "container dispose error", t)); //$NON-NLS-1$ + Trace.catching(ECFPlugin.PLUGIN_ID, ECFDebugOptions.EXCEPTIONS_CATCHING, ContainerFactory.class, "disposeContainers", t); //$NON-NLS-1$ + } + } + } + + public void start(BundleContext ctxt) throws Exception { + plugin = this; + this.context = ctxt; + + // initialize the default ssl socket factory + try { + Class ecfSocketFactoryClass = Class.forName("org.eclipse.ecf.internal.ssl.ECFTrustManager"); //$NON-NLS-1$ + ecfTrustManager = (BundleActivator) ecfSocketFactoryClass.getDeclaredConstructor().newInstance(); + ecfTrustManager.start(ctxt); + } catch (ClassNotFoundException e) { + // will occur if fragment is not installed or not on proper execution environment + } catch (Throwable t) { + log(new Status(IStatus.ERROR, PLUGIN_ID, "Unexpected Error in ECFPlugin.start", t)); //$NON-NLS-1$ + } + + // initialize from ContainerTypeDescription services + if (containerTypeDescriptionTracker == null) { + containerTypeDescriptionTracker = new ServiceTracker(this.context, ContainerTypeDescription.class.getName(), new ServiceTrackerCustomizer() { + public Object addingService(ServiceReference reference) { + ContainerTypeDescription ctd = (ContainerTypeDescription) context.getService(reference); + if (ctd != null && ctd.getName() != null) + ContainerFactory.getDefault().addDescription(ctd); + return ctd; + } + + public void modifiedService(ServiceReference reference, Object service) { + // nothing + } + + public void removedService(ServiceReference reference, Object service) { + ContainerTypeDescription ctd = (ContainerTypeDescription) service; + disposeContainersForDescription(ctd); + IContainerFactory cf = ContainerFactory.getDefault(); + cf.removeDescription((ContainerTypeDescription) service); + } + }); + containerTypeDescriptionTracker.open(); + } + + SafeRunner.run(new ExtensionRegistryRunnable(this.context) { + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + if (registry != null) { + registryManager = new IRegistryChangeListener() { + public void registryChanged(IRegistryChangeEvent event) { + final IExtensionDelta factoryDeltas[] = event.getExtensionDeltas(ECFNAMESPACE, CONTAINER_FACTORY_NAME); + for (int i = 0; i < factoryDeltas.length; i++) { + switch (factoryDeltas[i].getKind()) { + case IExtensionDelta.ADDED : + addContainerFactoryExtensions(factoryDeltas[i].getExtension().getConfigurationElements()); + break; + case IExtensionDelta.REMOVED : + removeContainerFactoryExtensions(factoryDeltas[i].getExtension().getConfigurationElements()); + break; + } + } + final IExtensionDelta containerDeltas[] = event.getExtensionDeltas(ECFNAMESPACE, CONTAINER_NAME); + for (int i = 0; i < containerDeltas.length; i++) { + switch (containerDeltas[i].getKind()) { + case IExtensionDelta.ADDED : + addContainerExtensions(containerDeltas[i].getExtension().getConfigurationElements()); + break; + case IExtensionDelta.REMOVED : + removeContainerExtensions(containerDeltas[i].getExtension().getConfigurationElements()); + break; + } + } + } + }; + registry.addRegistryChangeListener((IRegistryChangeListener) registryManager); + } + } + }); + + // defer extension execution until first consumer calls + final ServiceFactory sf = new ServiceFactory() { + public Object getService(Bundle bundle, ServiceRegistration registration) { + return ContainerFactory.getDefault(); + } + + public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) { + // NOP + } + }; + + containerFactoryServiceRegistration = ctxt.registerService(IContainerFactory.class.getName(), sf, null); + containerManagerServiceRegistration = ctxt.registerService(IContainerManager.class.getName(), sf, null); + + // Register SSLContextFactory + String defaultProtocol = System.getProperty("org.eclipse.ecf.core.security.sslcontextfactory.defaultProtocol"); //$NON-NLS-1$ + String defaultProvider = System.getProperty("org.eclipse.ecf.core.security.sslcontextfactory.defaultProvider"); //$NON-NLS-1$ + + ecfSSLContextFactory = new ECFSSLContextFactory(ctxt, defaultProtocol, defaultProvider); + sslContextFactoryRegistration = ctxt.registerService(SSLContextFactory.class, ecfSSLContextFactory, null); + + SafeRunner.run(new ExtensionRegistryRunnable(this.context) { + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + if (registry != null) { + final IExtensionPoint extensionPoint = registry.getExtensionPoint(START_EPOINT); + if (extensionPoint == null) + return; + IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements(); + final String method = "runStartExtensions"; //$NON-NLS-1$ + // For each configuration element + for (int m = 0; m < configurationElements.length; m++) { + final IConfigurationElement member = configurationElements[m]; + try { + // The only required attribute is "class" + boolean sync = (member.getAttribute(ASYNCH_ATTRIBUTE) == null); + IECFStart clazz = (IECFStart) member.createExecutableExtension(CLASS_ATTRIBUTE); + // Create job to do start, and schedule + if (sync) { + IStatus result = null; + try { + result = clazz.run(new NullProgressMonitor()); + } catch (final Throwable e) { + logException(method, "startup extension error", e); //$NON-NLS-1$ + } + if (result != null && !result.isOK()) + logException(result, result.getMessage(), result.getException()); + } else { + final ECFStartJob job = new ECFStartJob(clazz.getClass().getName(), clazz); + job.schedule(); + } + } catch (final CoreException e) { + logException(e.getStatus(), method, e); + } catch (final Exception e) { + logException(method, "Unknown start exception", e); //$NON-NLS-1$ + } + } + } + } + }); + + SafeRunner.run(new ExtensionRegistryRunnable(this.context) { + protected void runWithoutRegistry() throws Exception { + ECFPlugin.this.context.registerService(ContainerTypeDescription.class, new ContainerTypeDescription(BaseContainer.Instantiator.NAME, new BaseContainer.Instantiator()), null); + } + }); + } + + private ServiceTracker containerTypeDescriptionTracker; + + public void initializeExtensions() { + SafeRunner.run(new ExtensionRegistryRunnable(this.context) { + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + if (registry != null) { + IExtensionPoint extensionPoint = registry.getExtensionPoint(CONTAINER_FACTORY_EPOINT); + if (extensionPoint == null) + return; + addContainerFactoryExtensions(extensionPoint.getConfigurationElements()); + extensionPoint = registry.getExtensionPoint(CONTAINER_EPOINT); + if (extensionPoint == null) + return; + addContainerExtensions(extensionPoint.getConfigurationElements()); + } + } + }); + } + + public void stop(BundleContext ctxt) throws Exception { + fireDisposables(); + this.disposables = null; + SafeRunner.run(new ExtensionRegistryRunnable(ctxt) { + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + if (registry != null) + registry.removeRegistryChangeListener((IRegistryChangeListener) registryManager); + } + }); + this.registryManager = null; + if (containerTypeDescriptionTracker != null) { + containerTypeDescriptionTracker.close(); + containerTypeDescriptionTracker = null; + } + if (ecfTrustManager != null) { + ecfTrustManager.stop(ctxt); + ecfTrustManager = null; + } + if (logServiceTracker != null) { + logServiceTracker.close(); + logServiceTracker = null; + logService = null; + } + if (containerFactoryServiceRegistration != null) { + containerFactoryServiceRegistration.unregister(); + containerFactoryServiceRegistration = null; + } + if (containerManagerServiceRegistration != null) { + containerManagerServiceRegistration.unregister(); + containerManagerServiceRegistration = null; + } + if (sslContextFactoryRegistration != null) { + sslContextFactoryRegistration.unregister(); + sslContextFactoryRegistration = null; + if (ecfSSLContextFactory != null) { + ecfSSLContextFactory.close(); + ecfSSLContextFactory = null; + } + } + if (adapterManagerTracker != null) { + adapterManagerTracker.close(); + adapterManagerTracker = null; + } + this.context = null; + } + + public void addDisposable(IDisposable disposable) { + disposables.put(disposable, null); + } + + public void removeDisposable(IDisposable disposable) { + disposables.remove(disposable); + } + + protected void fireDisposables() { + for (final Iterator i = disposables.keySet().iterator(); i.hasNext();) { + final IDisposable d = (IDisposable) i.next(); + if (d != null) + d.dispose(); + } + } + + public Bundle getBundle() { + if (context == null) + return null; + return context.getBundle(); + } + + private LogService systemLogService; + + protected LogService getLogService() { + if (context == null) { + if (systemLogService == null) + systemLogService = new SystemLogService(PLUGIN_ID); + return systemLogService; + } + if (logServiceTracker == null) { + logServiceTracker = new ServiceTracker(this.context, LogService.class.getName(), null); + logServiceTracker.open(); + } + logService = (LogService) logServiceTracker.getService(); + if (logService == null) + logService = new SystemLogService(PLUGIN_ID); + return logService; + } + + public void log(IStatus status) { + if (logService == null) + logService = getLogService(); + if (logService != null) + logService.log(LogHelper.getLogCode(status), LogHelper.getLogMessage(status), status.getException()); + } + + protected void logException(String method, String message, Throwable exception) { + log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, message, exception)); + Trace.catching(PLUGIN_ID, ECFDebugOptions.EXCEPTIONS_CATCHING, ECFPlugin.class, method, exception); + } + + protected void logException(IStatus status, String methodName, Throwable exception) { + log(status); + Trace.catching(status.getPlugin(), ECFDebugOptions.EXCEPTIONS_CATCHING, ECFPlugin.class, methodName, exception); + } + + /** + * Remove extensions for container factory extension point + * + * @param members + * the members to remove + */ + protected void removeContainerFactoryExtensions(IConfigurationElement[] members) { + // For each configuration element + for (int m = 0; m < members.length; m++) { + final IConfigurationElement member = members[m]; + String name = null; + try { + // Get name and get version, if available + name = member.getAttribute(NAME_ATTRIBUTE); + if (name == null) + name = member.getAttribute(CLASS_ATTRIBUTE); + final IContainerFactory factory = ContainerFactory.getDefault(); + final ContainerTypeDescription cd = factory.getDescriptionByName(name); + if (cd == null || !factory.containsDescription(cd)) + continue; + // remove + factory.removeDescription(cd); + trace("removeContainerFactoryExtensions", "Removed ContainerTypeDescription=" + cd); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (final Exception e) { + logException("removeContainerFactoryExtensions", "Unexpected exception", e); //$NON-NLS-1$//$NON-NLS-2$ + } + } + } + + private void trace(String method, String message) { + Trace.trace(PLUGIN_ID, ECFDebugOptions.DEBUG, "TRACING " + ECFPlugin.class.getName() + "#" + method + " " + message); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + } + + void removeContainerExtensions(IConfigurationElement[] members) { + // For each configuration element + for (int m = 0; m < members.length; m++) { + final IConfigurationElement member = members[m]; + // The only required attribute is "factoryName" + String factoryName = member.getAttribute(FACTORY_ATTRIBUTE); + // Skip over if factory name is invalid + if (factoryName == null || "".equals(factoryName)) //$NON-NLS-1$ + continue; + IContainerManager manager = (IContainerManager) ContainerFactory.getDefault(); + IContainer[] containers = manager.getAllContainers(); + if (containers == null) + continue; + for (int i = 0; i < containers.length; i++) { + ContainerTypeDescription containerTypeDescription = manager.getContainerTypeDescription(containers[i].getID()); + if (containerTypeDescription != null && containerTypeDescription.getName().equals(factoryName)) { + // Remove from manager + IContainer removedContainer = manager.removeContainer(containers[i]); + if (removedContainer != null) { + try { + containers[i].dispose(); + } catch (Exception e) { + logException("removeContainerException", "Unexpected exception disposing container id=" + containers[i].getID(), e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + } + } + } + + /** + * Add container factory extension point extensions + * + * @param members + * to add + */ + protected void addContainerFactoryExtensions(IConfigurationElement[] members) { + final IContainerFactory factory = ContainerFactory.getDefault(); + // For each configuration element + for (int m = 0; m < members.length; m++) { + final IConfigurationElement member = members[m]; + Object exten = null; + String name = null; + try { + // Get value of containerFactory name attribute + name = member.getAttribute(NAME_ATTRIBUTE); + if (name != null) { + ContainerTypeDescription ctd = factory.getDescriptionByName(name); + // If we've got one already by this name, then we skip this new one + if (ctd != null) { + // log with warning + log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Factory already has container type description with name=" + name + ". Ignoring extension from " + member.getContributor().getName())); //$NON-NLS-1$ //$NON-NLS-2$ + // and continue + continue; + } + } + // The only required attribute is "class" + exten = member.createExecutableExtension(CLASS_ATTRIBUTE); + final String clazz = exten.getClass().getName(); + + if (name == null) + name = clazz; + + // Get description, if present + String description = member.getAttribute(DESCRIPTION_ATTRIBUTE); + if (description == null) + description = ""; //$NON-NLS-1$ + + String s = member.getAttribute(SERVER_ATTRIBUTE); + final boolean server = (s == null) ? false : Boolean.valueOf(s).booleanValue(); + s = member.getAttribute(HIDDEN_ATTRIBUTE); + final boolean hidden = (s == null) ? false : Boolean.valueOf(s).booleanValue(); + + // Now make description instance + final ContainerTypeDescription scd = new ContainerTypeDescription(name, (IContainerInstantiator) exten, description, server, hidden); + + if (factory.containsDescription(scd)) { + log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, "Factory already has container type description=" + scd + ". Ignoring extension from " + member.getContributor().getName())); //$NON-NLS-1$ //$NON-NLS-2$ + continue; + } + // Now add the description and we're ready to go. + factory.addDescription(scd); + trace("addContainerFactoryDescription", "added ContainerTypeDescription=" + scd); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (final CoreException e) { + logException(e.getStatus(), "addContainerFactoryExtension", e); //$NON-NLS-1$ + } catch (final Exception e) { + logException("addContainerFactoryExtension", "Unexpected error", e); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + + void addContainerExtensions(IConfigurationElement[] members) { + // For each configuration element + for (int m = 0; m < members.length; m++) { + final IConfigurationElement member = members[m]; + String factory = null; + String id = null; + try { + // The only required attribute is "factoryName" + factory = member.getAttribute(FACTORY_ATTRIBUTE); + // Skip over if factory name is invalid + if (factory == null || "".equals(factory)) //$NON-NLS-1$ + continue; + // get id attribute + id = member.getAttribute(ID_ATTRIBUTE); + id = (id == null || "".equals(id)) ? null : id; //$NON-NLS-1$ + Map parameters = getParametersForContainer(member); + ContainerFactory.getDefault().createContainer(factory, id, parameters); + trace("addContainerExtensions", "Created container with id=" + id); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (final CoreException e) { + logException(e.getStatus(), "addContainerExtensions", e); //$NON-NLS-1$ + } catch (final Exception e) { + logException("addContainerExtensions", "Exception creating container with id=" + id, null); //$NON-NLS-1$//$NON-NLS-2$ + } + } + } + + Map getParametersForContainer(IConfigurationElement member) { + IConfigurationElement[] elements = member.getChildren(PARAMETER_ELEMENT); + if (elements == null) + return null; + Map results = null; + for (int i = 0; i < elements.length; i++) { + String name = elements[i].getAttribute(PARAMETER_NAME); + String value = elements[i].getAttribute(PARAMETER_VALUE); + if (name != null && !"".equals(name) && value != null && !"".equals(value)) { //$NON-NLS-1$ //$NON-NLS-2$ + if (results == null) + results = new Properties(); + results.put(name, value); + } + } + return results; + } + + public IAdapterManager getAdapterManager() { + if (context == null) + return null; + // First, try to get the adapter manager via + if (adapterManagerTracker == null) { + adapterManagerTracker = new AdapterManagerTracker(this.context); + adapterManagerTracker.open(); + } + return adapterManagerTracker.getAdapterManager(); + } + +} \ No newline at end of file diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/IDisposable.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/IDisposable.java new file mode 100644 index 0000000000..54a4c2062f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/IDisposable.java @@ -0,0 +1,16 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.core; + +public interface IDisposable { + public void dispose(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/identity/Activator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/identity/Activator.java new file mode 100644 index 0000000000..6214f9f8cd --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/core/identity/Activator.java @@ -0,0 +1,315 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.core.identity; + +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.core.identity.*; +import org.eclipse.ecf.core.util.*; +import org.eclipse.osgi.service.debug.DebugOptions; +import org.osgi.framework.*; +import org.osgi.service.log.LogService; +import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator implements BundleActivator { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.ecf.identity"; //$NON-NLS-1$ + + private static final String NAMESPACE_NAME = "namespace"; //$NON-NLS-1$ + + private static final String NAMESPACE_EPOINT = PLUGIN_ID + "." //$NON-NLS-1$ + + NAMESPACE_NAME; + + private static final String NAME_ATTRIBUTE = "name"; //$NON-NLS-1$ + + private static final String CLASS_ATTRIBUTE = "class"; //$NON-NLS-1$ + + private static final int FACTORY_NAME_COLLISION_ERRORCODE = 200; + + private static final String DESCRIPTION_ATTRIBUTE = "description"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + private BundleContext context; + + @SuppressWarnings("rawtypes") + private ServiceRegistration idFactoryServiceRegistration; + + @SuppressWarnings("rawtypes") + private ServiceTracker debugOptionsTracker; + + @SuppressWarnings("rawtypes") + private ServiceTracker logServiceTracker; + + private LogService logService; + + private AdapterManagerTracker adapterManagerTracker; + + @SuppressWarnings("rawtypes") + private ServiceTracker namespacesTracker; + + // This is object rather than typed to avoid referencing the + // IRegistryChangedListener class directly + private Object registryManager; + + public synchronized IAdapterManager getAdapterManager() { + if (this.context == null) + return null; + // First, try to get the adapter manager via + if (adapterManagerTracker == null) { + adapterManagerTracker = new AdapterManagerTracker(this.context); + adapterManagerTracker.open(); + } + return adapterManagerTracker.getAdapterManager(); + } + + /** + * The constructor + */ + public Activator() { + // public null constructor + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public synchronized DebugOptions getDebugOptions() { + if (context == null) + return null; + if (debugOptionsTracker == null) { + debugOptionsTracker = new ServiceTracker(context, DebugOptions.class.getName(), null); + debugOptionsTracker.open(); + } + return (DebugOptions) debugOptionsTracker.getService(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void start(BundleContext ctxt) throws Exception { + plugin = this; + this.context = ctxt; + BundleStarter.startDependents(this.context, new String[] { "org.eclipse.equinox.common", + "org.eclipse.core.jobs", "org.eclipse.equinox.concurrent" }, Bundle.STARTING | Bundle.RESOLVED); + + // Register IIDFactory service + idFactoryServiceRegistration = context.registerService(IIDFactory.class.getName(), IDFactory.getDefault(), + null); + + namespacesTracker = new ServiceTracker(context, Namespace.class.getName(), new ServiceTrackerCustomizer() { + + public Object addingService(ServiceReference reference) { + Namespace ns = (Namespace) context.getService(reference); + if (ns != null && ns.getName() != null) + IDFactory.addNamespace0(ns); + return ns; + } + + public void modifiedService(ServiceReference reference, Object service) { + } + + public void removedService(ServiceReference reference, Object service) { + IDFactory.removeNamespace0((Namespace) service); + } + }); + namespacesTracker.open(); + + SafeRunner.run(new ExtensionRegistryRunnable(ctxt) { + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + if (registry != null) { + registryManager = new IRegistryChangeListener() { + public void registryChanged(IRegistryChangeEvent event) { + final IExtensionDelta delta[] = event.getExtensionDeltas(PLUGIN_ID, NAMESPACE_NAME); + for (IExtensionDelta d : delta) { + switch (d.getKind()) { + case IExtensionDelta.ADDED: + addNamespaceExtensions(d.getExtension().getConfigurationElements()); + break; + case IExtensionDelta.REMOVED: + IConfigurationElement[] members = d.getExtension().getConfigurationElements(); + for (IConfigurationElement member : members) { + String name = null; + try { + name = member.getAttribute(NAME_ATTRIBUTE); + if (name == null) { + name = member.getAttribute(CLASS_ATTRIBUTE); + } + if (name == null) + continue; + final IIDFactory factory = IDFactory.getDefault(); + final Namespace n = factory.getNamespaceByName(name); + if (n == null || !factory.containsNamespace(n)) { + continue; + } + // remove + factory.removeNamespace(n); + } catch (final Exception e) { + getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, + IStatus.ERROR, "Exception removing namespace", e)); //$NON-NLS-1$ + } + } + break; + } + } + } + }; + registry.addRegistryChangeListener((IRegistryChangeListener) registryManager); + } + } + }); + } + + public BundleContext getBundleContext() { + return context; + } + + Bundle getBundle() { + if (context == null) + return null; + return context.getBundle(); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + synchronized LogService getLogService() { + if (context == null) { + if (logService == null) + logService = new SystemLogService(PLUGIN_ID); + return logService; + } + if (logServiceTracker == null) { + logServiceTracker = new ServiceTracker(this.context, LogService.class.getName(), null); + logServiceTracker.open(); + } + logService = (LogService) logServiceTracker.getService(); + if (logService == null) + logService = new SystemLogService(PLUGIN_ID); + return logService; + } + + public void log(IStatus status) { + if (logService == null) + logService = getLogService(); + + if (logService != null) + logService.log(LogHelper.getLogCode(status), LogHelper.getLogMessage(status), status.getException()); + } + + /** + * Add identity namespace extension point extensions + * + * @param members + * the members to add + */ + void addNamespaceExtensions(IConfigurationElement[] members) { + final String bundleName = getDefault().getBundle().getSymbolicName(); + for (IConfigurationElement member : members) { + // Get the label of the extender plugin and the ID of the + // extension. + final IExtension extension = member.getDeclaringExtension(); + String nsName = null; + try { + final Namespace ns = (Namespace) member.createExecutableExtension(CLASS_ATTRIBUTE); + final String clazz = ns.getClass().getName(); + nsName = member.getAttribute(NAME_ATTRIBUTE); + if (nsName == null) { + nsName = clazz; + } + final String nsDescription = member.getAttribute(DESCRIPTION_ATTRIBUTE); + ns.initialize(nsName, nsDescription); + // Check to see if we have a namespace name collision + if (!IDFactory.containsNamespace0(ns)) { + // Now add to known namespaces + IDFactory.addNamespace0(ns); + } + } catch (final CoreException e) { + getDefault().log(e.getStatus()); + } catch (final Exception e) { + getDefault().log(new Status(IStatus.ERROR, bundleName, FACTORY_NAME_COLLISION_ERRORCODE, "name=" //$NON-NLS-1$ + + nsName + ";extension point id=" //$NON-NLS-1$ + + extension.getExtensionPointUniqueIdentifier(), null)); + } + } + } + + /** + * Setup identity namespace extension point + * + */ + public void setupNamespaceExtensionPoint() { + SafeRunner.run(new ExtensionRegistryRunnable(context) { + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + if (registry != null) { + final IExtensionPoint extensionPoint = registry.getExtensionPoint(NAMESPACE_EPOINT); + if (extensionPoint == null) + return; + addNamespaceExtensions(extensionPoint.getConfigurationElements()); + } + } + }); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext ctxt) throws Exception { + SafeRunner.run(new ExtensionRegistryRunnable(ctxt) { + protected void runWithRegistry(IExtensionRegistry registry) throws Exception { + if (registry != null) + registry.removeRegistryChangeListener((IRegistryChangeListener) registryManager); + } + }); + if (namespacesTracker != null) { + namespacesTracker.close(); + namespacesTracker = null; + } + registryManager = null; + if (logServiceTracker != null) { + logServiceTracker.close(); + logServiceTracker = null; + logService = null; + } + if (debugOptionsTracker != null) { + debugOptionsTracker.close(); + debugOptionsTracker = null; + } + if (idFactoryServiceRegistration != null) { + idFactoryServiceRegistration.unregister(); + idFactoryServiceRegistration = null; + } + if (adapterManagerTracker != null) { + adapterManagerTracker.close(); + adapterManagerTracker = null; + } + context = null; + plugin = null; + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public synchronized static Activator getDefault() { + if (plugin == null) + plugin = new Activator(); + return plugin; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/Activator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/Activator.java new file mode 100644 index 0000000000..d76a3f97f9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/Activator.java @@ -0,0 +1,133 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.filetransfer; + +import java.util.Hashtable; +import org.eclipse.core.runtime.*; +import org.eclipse.ecf.core.util.LogHelper; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.service.log.LogService; +import org.osgi.service.url.URLConstants; +import org.osgi.service.url.URLStreamHandlerService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator implements BundleActivator { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.ecf.filetransfer"; //$NON-NLS-1$ + + private static final String URLCONNECTION_FACTORY_EPOINT = PLUGIN_ID + "." //$NON-NLS-1$ + + "urlStreamHandlerService"; //$NON-NLS-1$ + + private static final String PROTOCOL_ATTRIBUTE = "protocol"; //$NON-NLS-1$ + + private ServiceTracker extensionRegistryTracker = null; + + // The shared instance + private static Activator plugin; + + private BundleContext context = null; + + private ServiceTracker logServiceTracker = null; + + /** + * The constructor + */ + public Activator() { + // null constructor + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext ctxt) throws Exception { + this.context = ctxt; + plugin = this; + setupProtocolHandlers(ctxt); + } + + protected LogService getLogService() { + if (logServiceTracker == null) { + logServiceTracker = new ServiceTracker(this.context, LogService.class.getName(), null); + logServiceTracker.open(); + } + return (LogService) logServiceTracker.getService(); + } + + public void log(IStatus status) { + LogService logService = getLogService(); + if (logService != null) { + logService.log(LogHelper.getLogCode(status), LogHelper.getLogMessage(status), status.getException()); + } + } + + public IExtensionRegistry getExtensionRegistry() { + if (extensionRegistryTracker == null) { + this.extensionRegistryTracker = new ServiceTracker(context, IExtensionRegistry.class.getName(), null); + this.extensionRegistryTracker.open(); + } + return (IExtensionRegistry) extensionRegistryTracker.getService(); + } + + private void setupProtocolHandlers(BundleContext context) { + IExtensionRegistry reg = getExtensionRegistry(); + if (reg != null) { + IExtensionPoint extensionPoint = reg.getExtensionPoint(URLCONNECTION_FACTORY_EPOINT); + if (extensionPoint == null) { + return; + } + IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements(); + + for (IConfigurationElement configurationElement : configurationElements) { + String protocol = configurationElement.getAttribute(PROTOCOL_ATTRIBUTE); + if (protocol != null) { + Hashtable properties = new Hashtable(); + properties.put(URLConstants.URL_HANDLER_PROTOCOL, new String[] {protocol}); + context.registerService(URLStreamHandlerService.class.getName(), new ProxyURLStreamHandlerService(configurationElement), properties); + } + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext ctxt) throws Exception { + if (extensionRegistryTracker != null) { + extensionRegistryTracker.close(); + extensionRegistryTracker = null; + } + plugin = null; + this.context = null; + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public synchronized static Activator getDefault() { + if (plugin == null) { + plugin = new Activator(); + } + return plugin; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/FileTransferDebugOptions.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/FileTransferDebugOptions.java new file mode 100644 index 0000000000..5ce1a228a6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/FileTransferDebugOptions.java @@ -0,0 +1,26 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.filetransfer; + +public interface FileTransferDebugOptions { + + public static final String DEBUG = Activator.PLUGIN_ID + "/debug"; //$NON-NLS-1$ + + public static final String EXCEPTIONS_THROWING = DEBUG + "/exceptions/throwing"; //$NON-NLS-1$ + + public static final String EXCEPTIONS_CATCHING = DEBUG + "/exceptions/catching"; //$NON-NLS-1$ + + public static final String METHODS_ENTERING = DEBUG + "/methods/entering"; //$NON-NLS-1$ + + public static final String METHODS_EXITING = DEBUG + "/methods/exiting"; //$NON-NLS-1$ + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/ProxyURLStreamHandlerService.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/ProxyURLStreamHandlerService.java new file mode 100644 index 0000000000..e04a2ce4e4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/filetransfer/ProxyURLStreamHandlerService.java @@ -0,0 +1,89 @@ +/**************************************************************************** + * Copyright (c) 2023 Christoph Läubrich + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Christoph Läubrich - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.filetransfer; + +import java.io.IOException; +import java.net.*; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.osgi.service.url.URLStreamHandlerService; +import org.osgi.service.url.URLStreamHandlerSetter; + +public class ProxyURLStreamHandlerService implements URLStreamHandlerService { + + private static final String SERVICE_CLASS_ATTRIBUTE = "serviceClass"; //$NON-NLS-1$ + + private final IConfigurationElement configurationElement; + + private URLStreamHandlerService delegate; + + public ProxyURLStreamHandlerService(IConfigurationElement configurationElement) { + this.configurationElement = configurationElement; + } + + @Override + public URLConnection openConnection(URL u) throws IOException { + return getDelegate().openConnection(u); + } + + @Override + public void parseURL(URLStreamHandlerSetter realHandler, URL u, String spec, int start, int limit) { + getDelegate().parseURL(realHandler, u, spec, start, limit); + } + + @Override + public String toExternalForm(URL u) { + return getDelegate().toExternalForm(u); + } + + @Override + public boolean equals(URL u1, URL u2) { + return getDelegate().equals(u1, u2); + } + + @Override + public int getDefaultPort() { + return getDelegate().getDefaultPort(); + } + + @Override + public InetAddress getHostAddress(URL u) { + return getDelegate().getHostAddress(u); + } + + @Override + public int hashCode(URL u) { + return getDelegate().hashCode(u); + } + + @Override + public boolean hostsEqual(URL u1, URL u2) { + return getDelegate().hostsEqual(u1, u2); + } + + @Override + public boolean sameFile(URL u1, URL u2) { + return getDelegate().sameFile(u1, u2); + } + + synchronized URLStreamHandlerService getDelegate() { + if (delegate == null) { + try { + delegate = (URLStreamHandlerService) configurationElement.createExecutableExtension(SERVICE_CLASS_ATTRIBUTE); + } catch (CoreException e) { + throw new IllegalStateException("can't create executable extension", e); //$NON-NLS-1$ + } + } + return delegate; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Activator.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Activator.java new file mode 100644 index 0000000000..3c4212234a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Activator.java @@ -0,0 +1,923 @@ +/**************************************************************************** + * Copyright (c) 2006, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.provider.filetransfer; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import org.eclipse.core.net.proxy.IProxyService; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtensionDelta; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IRegistryChangeEvent; +import org.eclipse.core.runtime.IRegistryChangeListener; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.ecf.core.util.LogHelper; +import org.eclipse.ecf.core.util.PlatformHelper; +import org.eclipse.ecf.filetransfer.service.IRemoteFileSystemBrowser; +import org.eclipse.ecf.filetransfer.service.IRemoteFileSystemBrowserFactory; +import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransfer; +import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransferFactory; +import org.eclipse.ecf.filetransfer.service.ISendFileTransfer; +import org.eclipse.ecf.filetransfer.service.ISendFileTransferFactory; +import org.eclipse.ecf.provider.filetransfer.IFileTransferProtocolToFactoryMapper; +import org.eclipse.ecf.provider.filetransfer.retrieve.MultiProtocolRetrieveAdapter; +import org.eclipse.osgi.util.NLS; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.service.log.LogService; +import org.osgi.service.url.AbstractURLStreamHandlerService; +import org.osgi.service.url.URLConstants; +import org.osgi.service.url.URLStreamHandlerService; +import org.osgi.util.tracker.ServiceTracker; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator implements BundleActivator, IFileTransferProtocolToFactoryMapper { + + // This is the name of a system property 'org.eclipse.ecf.provider.filetransfer.excludeContributors' + // that allows people to defeat the priority system for the browse, send, and retrieve factory contributions. + // If a plugin (symbolic id) is given in this property (multiples separated by comma), then + // that plugin's contributions will *not* be added to the browse, send, and retrieve protocol factories + public static final String PLUGIN_EXCLUDED_SYS_PROP_NAME = Activator.PLUGIN_ID + ".excludeContributors"; //$NON-NLS-1$ + + private static final String CLASS_ATTR = "class"; //$NON-NLS-1$ + private static final String PRIORITY_ATTR = "priority"; //$NON-NLS-1$ + private static final int DEFAULT_PRIORITY = 100; + private static final String PROTOCOL_ATTR = "protocol"; //$NON-NLS-1$ + private static final String URI_ATTR = "uri"; //$NON-NLS-1$ + private static final String[] jvmSchemes = new String[] {Messages.FileTransferNamespace_Http_Protocol, Messages.FileTransferNamespace_Ftp_Protocol, Messages.FileTransferNamespace_File_Protocol, Messages.FileTransferNamespace_Jar_Protocol, Messages.FileTransferNamespace_Https_Protocol, Messages.FileTransferNamespace_Mailto_Protocol, Messages.FileTransferNamespace_Gopher_Protocol}; + + private static final String URL_HANDLER_PROTOCOL_NAME = "url.handler.protocol"; //$NON-NLS-1$ + + private static final String URLSTREAM_HANDLER_SERVICE_NAME = "org.osgi.service.url.URLStreamHandlerService"; //$NON-NLS-1$ + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.ecf.provider.filetransfer"; //$NON-NLS-1$ + + private static final String RETRIEVE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME = "retrieveFileTransferProtocolFactory"; //$NON-NLS-1$ + + private static final String RETRIEVE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT = PLUGIN_ID + "." //$NON-NLS-1$ + + RETRIEVE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME; + + private static final String SEND_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME = "sendFileTransferProtocolFactory"; //$NON-NLS-1$ + + private static final String SEND_FILETRANSFER_PROTOCOL_FACTORY_EPOINT = PLUGIN_ID + "." //$NON-NLS-1$ + + SEND_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME; + + private static final String BROWSE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME = "browseFileTransferProtocolFactory"; //$NON-NLS-1$ + + private static final String BROWSE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT = PLUGIN_ID + "." //$NON-NLS-1$ + + BROWSE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME; + + // The shared instance + private static Activator plugin; + + private BundleContext context = null; + + private ServiceRegistration fileTransferServiceRegistration; + + private ServiceTracker logServiceTracker = null; + private ServiceTracker extensionRegistryTracker = null; + + private Map retrieveFileTransferProtocolMap; + + private Map sendFileTransferProtocolMap; + + private Map browseFileTransferProtocolMap; + + private ServiceTracker adapterManagerTracker = null; + + private ServiceTracker proxyServiceTracker = null; + + private IURLConnectionModifier urlConnectionModifier = null; + + private String[] excludedPlugins = null; + + private ServiceRegistration protocolMapperRegistration; + + private IRegistryChangeListener registryChangeListener = new IRegistryChangeListener() { + + public void registryChanged(IRegistryChangeEvent event) { + final IExtensionDelta retrieveDelta[] = event.getExtensionDeltas(PLUGIN_ID, RETRIEVE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME); + for (IExtensionDelta r : retrieveDelta) { + switch (r.getKind()) { + case IExtensionDelta.ADDED : + addRetrieveExtensions(r.getExtension().getConfigurationElements()); + break; + case IExtensionDelta.REMOVED : + removeRetrieveExtensions(r.getExtension().getConfigurationElements()); + break; + } + } + final IExtensionDelta sendDelta[] = event.getExtensionDeltas(PLUGIN_ID, SEND_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME); + for (IExtensionDelta s : sendDelta) { + switch (s.getKind()) { + case IExtensionDelta.ADDED : + addSendExtensions(s.getExtension().getConfigurationElements()); + break; + case IExtensionDelta.REMOVED : + removeSendExtensions(s.getExtension().getConfigurationElements()); + break; + } + } + final IExtensionDelta browseDelta[] = event.getExtensionDeltas(PLUGIN_ID, BROWSE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT_NAME); + for (IExtensionDelta b : browseDelta) { + switch (b.getKind()) { + case IExtensionDelta.ADDED : + addBrowseExtensions(b.getExtension().getConfigurationElements()); + break; + case IExtensionDelta.REMOVED : + removeBrowseExtensions(b.getExtension().getConfigurationElements()); + break; + } + } + } + + }; + + private String[] parseExcludedPlugins() { + String prop = System.getProperty(PLUGIN_EXCLUDED_SYS_PROP_NAME); + if (prop == null) + return new String[0]; + StringTokenizer tok = new StringTokenizer(prop, ","); //$NON-NLS-1$ + int count = tok.countTokens(); + String[] results = new String[count]; + for (int i = 0; i < count; i++) { + results[i] = tok.nextToken(); + } + return results; + } + + /** + * The constructor + */ + public Activator() { + // + } + + protected LogService getLogService() { + synchronized (this) { + if (this.context == null) + return null; + if (logServiceTracker == null) { + logServiceTracker = new ServiceTracker(this.context, LogService.class.getName(), null); + logServiceTracker.open(); + } + return (LogService) logServiceTracker.getService(); + } + } + + public IProxyService getProxyService() { + try { + if (proxyServiceTracker == null) { + proxyServiceTracker = new ServiceTracker(this.context, IProxyService.class.getName(), null); + proxyServiceTracker.open(); + } + return (IProxyService) proxyServiceTracker.getService(); + } catch (Exception e) { + logNoProxyWarning(e); + } catch (NoClassDefFoundError e) { + logNoProxyWarning(e); + } + return null; + } + + static boolean proxyWarningGiven = false; + + public static void logNoProxyWarning(Throwable e) { + Activator a = getDefault(); + if (a != null) { + if (!proxyWarningGiven) { + a.log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, "Warning: Platform proxy API not available", null)); //$NON-NLS-1$ + proxyWarningGiven = true; + } + } + } + + public void log(IStatus status) { + if (this.context == null) + return; + final LogService logService = getLogService(); + if (logService != null) { + logService.log(LogHelper.getLogCode(status), LogHelper.getLogMessage(status), status.getException()); + } + } + + public Bundle getBundle() { + if (context == null) + return null; + return context.getBundle(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext ctxt) throws Exception { + plugin = this; + this.context = ctxt; + this.retrieveFileTransferProtocolMap = new HashMap(3); + this.sendFileTransferProtocolMap = new HashMap(3); + this.browseFileTransferProtocolMap = new HashMap(3); + + // initialize the default url connection modifier for ssl + try { + Class urlConnectionModifierClass = Class.forName("org.eclipse.ecf.internal.provider.filetransfer.ssl.ECFURLConnectionModifier"); //$NON-NLS-1$ + urlConnectionModifier = (IURLConnectionModifier) urlConnectionModifierClass.newInstance(); + urlConnectionModifier.init(ctxt); + } catch (ClassNotFoundException e) { + // will occur if fragment is not installed or not on proper execution environment + } catch (Throwable t) { + log(new Status(IStatus.ERROR, getDefault().getBundle().getSymbolicName(), "Unexpected Error in Activator.start", t)); //$NON-NLS-1$ + } + + fileTransferServiceRegistration = ctxt.registerService(IRetrieveFileTransferFactory.class.getName(), new IRetrieveFileTransferFactory() { + public IRetrieveFileTransfer newInstance() { + return new MultiProtocolRetrieveAdapter(); + } + }, null); + this.extensionRegistryTracker = new ServiceTracker(ctxt, IExtensionRegistry.class.getName(), null); + this.extensionRegistryTracker.open(); + final IExtensionRegistry registry = getExtensionRegistry(); + if (registry != null) { + registry.addRegistryChangeListener(registryChangeListener); + } + // Can't be lazy about this, as schemes need to be registered with + // platform + loadProtocolHandlers(); + // Finally, register this object as a IFileTransferProtocolToFactoryMapper service + protocolMapperRegistration = context.registerService(IFileTransferProtocolToFactoryMapper.class.getName(), this, null); + } + + public boolean reinitialize() { + try { + loadProtocolHandlers(); + return true; + } catch (Exception e) { + return false; + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext ctxt) throws Exception { + final IExtensionRegistry registry = getExtensionRegistry(); + if (registry != null) { + registry.removeRegistryChangeListener(registryChangeListener); + } + + if (urlConnectionModifier != null) { + urlConnectionModifier.dispose(); + urlConnectionModifier = null; + } + if (extensionRegistryTracker != null) { + extensionRegistryTracker.close(); + extensionRegistryTracker = null; + } + if (fileTransferServiceRegistration != null) { + fileTransferServiceRegistration.unregister(); + fileTransferServiceRegistration = null; + } + if (adapterManagerTracker != null) { + adapterManagerTracker.close(); + adapterManagerTracker = null; + } + if (proxyServiceTracker != null) { + proxyServiceTracker.close(); + proxyServiceTracker = null; + } + if (this.retrieveFileTransferProtocolMap != null) { + this.retrieveFileTransferProtocolMap.clear(); + this.retrieveFileTransferProtocolMap = null; + } + if (this.sendFileTransferProtocolMap != null) { + this.sendFileTransferProtocolMap.clear(); + this.sendFileTransferProtocolMap = null; + } + if (this.browseFileTransferProtocolMap != null) { + this.browseFileTransferProtocolMap.clear(); + this.browseFileTransferProtocolMap = null; + } + if (this.protocolMapperRegistration != null) { + this.protocolMapperRegistration.unregister(); + this.protocolMapperRegistration = null; + } + + synchronized (this) { + this.context = null; + } + plugin = null; + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public synchronized static Activator getDefault() { + if (plugin == null) { + plugin = new Activator(); + } + return plugin; + } + + public String[] getPlatformSupportedSchemes() { + final ServiceTracker handlers = new ServiceTracker(context, URLSTREAM_HANDLER_SERVICE_NAME, null); + handlers.open(); + final ServiceReference[] refs = handlers.getServiceReferences(); + final Set protocols = new HashSet(); + if (refs != null) + for (ServiceReference ref : refs) { + final Object protocol = ref.getProperty(URL_HANDLER_PROTOCOL_NAME); + if (protocol instanceof String) { + protocols.add(protocol); + } else if (protocol instanceof String[]) { + final String[] ps = (String[]) protocol; + protocols.addAll(Arrays.asList(ps)); + } + } + handlers.close(); + protocols.addAll(Arrays.asList(jvmSchemes)); + return (String[]) protocols.toArray(new String[] {}); + } + + public IExtensionRegistry getExtensionRegistry() { + if (extensionRegistryTracker == null) { + this.extensionRegistryTracker = new ServiceTracker(context, IExtensionRegistry.class.getName(), null); + this.extensionRegistryTracker.open(); + } + return (IExtensionRegistry) extensionRegistryTracker.getService(); + } + + static class ProtocolFactory implements Comparable { + Object factory; + int priority = 0; + String id; + + public ProtocolFactory(Object factory, int priority, String id) { + this.factory = factory; + this.priority = priority; + this.id = id; + } + + public Object getFactory() { + return factory; + } + + public String getID() { + return id; + } + + public int getPriority() { + return priority; + } + + /* (non-Javadoc) + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Object another) { + if (!(another instanceof ProtocolFactory)) + return -1; + ProtocolFactory other = (ProtocolFactory) another; + if (this.priority == other.priority) + return 0; + return (this.priority < other.priority) ? -1 : 1; + } + } + + private int getPriority(IConfigurationElement configElement, String warning, String protocol) { + // Get priority for new entry, if optional priority attribute specified + final String priorityString = configElement.getAttribute(PRIORITY_ATTR); + int priority = DEFAULT_PRIORITY; + if (priorityString != null) { + try { + priority = Integer.parseInt(priorityString); + // Make sure that any negative values are reset to 0 (highest priority) + priority = (priority < 0) ? 0 : priority; + } catch (NumberFormatException e) { + // Give warning + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for {1} from {2} has invalid priority {3}. Priority will be set to {4}", new Object[] {warning, protocol, configElement.getDeclaringExtension().getContributor().getName(), priorityString, String.valueOf(DEFAULT_PRIORITY)}), null)); //$NON-NLS-1$ + } + } + return priority; + } + + boolean pluginExcluded(String pluginId) { + if (excludedPlugins == null) { + excludedPlugins = parseExcludedPlugins(); + } + List l = Arrays.asList(excludedPlugins); + return l.contains(pluginId); + } + + void addRetrieveExtensions(IConfigurationElement[] configElements) { + for (IConfigurationElement configElement : configElements) { + final String protocol = configElement.getAttribute(PROTOCOL_ATTR); + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return; + String uriStr = configElement.getAttribute(URI_ATTR); + boolean uri = (uriStr == null) ? false : Boolean.valueOf(uriStr).booleanValue(); + String CONTRIBUTION_WARNING = "File retrieve contribution"; //$NON-NLS-1$ + try { + String pluginId = configElement.getDeclaringExtension().getContributor().getName(); + // Only add the factories if the contributor plugin has not been excluded + if (!pluginExcluded(pluginId)) { + // First create factory clazz + final IRetrieveFileTransferFactory retrieveFactory = (IRetrieveFileTransferFactory) configElement.createExecutableExtension(CLASS_ATTR); + // Get priority for new entry, if optional priority attribute specified + int priority = getPriority(configElement, CONTRIBUTION_WARNING, protocol); + String contributorName = configElement.getDeclaringExtension().getContributor().getName(); + // Now add new ProtocolFactory + setRetrieveFileTransferFactory(protocol, contributorName, retrieveFactory, priority, uri); + } else { + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, "Plugin " + pluginId + " excluded from contributing retrieve factory", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + } catch (final CoreException e) { + Activator.getDefault().log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, NLS.bind("Error loading from {0} extension point", RETRIEVE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT), e)); //$NON-NLS-1$ + } + } + } + + void removeRetrieveExtensions(IConfigurationElement[] configElements) { + for (IConfigurationElement configElement : configElements) { + final String protocol = configElement.getAttribute(PROTOCOL_ATTR); + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return; + String id = getRetrieveFileTransferFactoryId(protocol); + if (id != null) + removeRetrieveFileTransferFactory(id); + } + } + + void addSendExtensions(IConfigurationElement[] configElements) { + for (IConfigurationElement configElement : configElements) { + final String protocol = configElement.getAttribute(PROTOCOL_ATTR); + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return; + String uriStr = configElement.getAttribute(URI_ATTR); + boolean uri = (uriStr == null) ? false : Boolean.valueOf(uriStr).booleanValue(); + String CONTRIBUTION_WARNING = "File send contribution"; //$NON-NLS-1$ + try { + String pluginId = configElement.getDeclaringExtension().getContributor().getName(); + // Only add the factories if the contributor plugin has not been excluded + if (!pluginExcluded(pluginId)) { + // First create factory clazz + final ISendFileTransferFactory clazz = (ISendFileTransferFactory) configElement.createExecutableExtension(CLASS_ATTR); + // Get priority for new entry, if optional priority attribute specified + int priority = getPriority(configElement, CONTRIBUTION_WARNING, protocol); + setSendFileTransferFactory(protocol, pluginId, clazz, priority, uri); + } else { + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, "Plugin " + pluginId + " excluded from contributing send factory", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + } catch (final CoreException e) { + Activator.getDefault().log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, NLS.bind("Error loading from {0} extension point", SEND_FILETRANSFER_PROTOCOL_FACTORY_EPOINT), e)); //$NON-NLS-1$ + } + } + } + + void removeSendExtensions(IConfigurationElement[] configElements) { + for (IConfigurationElement configElement : configElements) { + final String protocol = configElement.getAttribute(PROTOCOL_ATTR); + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return; + String id = getSendFileTransferFactoryId(protocol); + if (id != null) + removeSendFileTransferFactory(id); + } + } + + void addBrowseExtensions(IConfigurationElement[] configElements) { + for (IConfigurationElement configElement : configElements) { + final String protocol = configElement.getAttribute(PROTOCOL_ATTR); + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return; + String uriStr = configElement.getAttribute(URI_ATTR); + boolean uri = (uriStr == null) ? false : Boolean.valueOf(uriStr).booleanValue(); + String CONTRIBUTION_WARNING = "File browse contribution"; //$NON-NLS-1$ + try { + String pluginId = configElement.getDeclaringExtension().getContributor().getName(); + // Only add the factories if the contributor plugin has not been excluded + if (!pluginExcluded(pluginId)) { + // First create factory clazz + final IRemoteFileSystemBrowserFactory clazz = (IRemoteFileSystemBrowserFactory) configElement.createExecutableExtension(CLASS_ATTR); + // Get priority for new entry, if optional priority attribute specified + int priority = getPriority(configElement, CONTRIBUTION_WARNING, protocol); + setBrowseFileTransferFactory(protocol, pluginId, clazz, priority, uri); + } else { + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, "Plugin " + pluginId + " excluded from contributing browse factory", null)); //$NON-NLS-1$ //$NON-NLS-2$ + } + } catch (final CoreException e) { + Activator.getDefault().log(new Status(IStatus.ERROR, PLUGIN_ID, IStatus.ERROR, NLS.bind("Error loading from {0} extension point", BROWSE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT), e)); //$NON-NLS-1$ + } + } + } + + void removeBrowseExtensions(IConfigurationElement[] configElements) { + for (IConfigurationElement configElement : configElements) { + final String protocol = configElement.getAttribute(PROTOCOL_ATTR); + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return; + String id = getBrowseFileTransferFactoryId(protocol); + if (id != null) + removeBrowseFileTransferFactory(id); + } + } + + private void loadProtocolHandlers() { + final IExtensionRegistry reg = getExtensionRegistry(); + if (reg != null) { + final IExtensionPoint retrieveExtensionPoint = reg.getExtensionPoint(RETRIEVE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT); + if (retrieveExtensionPoint != null) + addRetrieveExtensions(retrieveExtensionPoint.getConfigurationElements()); + // Now do it with send + final IExtensionPoint sendExtensionPoint = reg.getExtensionPoint(SEND_FILETRANSFER_PROTOCOL_FACTORY_EPOINT); + if (sendExtensionPoint != null) + addSendExtensions(sendExtensionPoint.getConfigurationElements()); + // Now for browse + final IExtensionPoint browseExtensionPoint = reg.getExtensionPoint(BROWSE_FILETRANSFER_PROTOCOL_FACTORY_EPOINT); + if (browseExtensionPoint != null) + addBrowseExtensions(browseExtensionPoint.getConfigurationElements()); + } + } + + private boolean isSchemeRegistered(String protocol, String[] schemes) { + for (String scheme : schemes) { + if (protocol.equals(scheme)) { + return true; + } + } + return false; + } + + class DummyURLStreamHandlerService extends AbstractURLStreamHandlerService { + + /* + * (non-Javadoc) + * + * @see org.osgi.service.url.AbstractURLStreamHandlerService#openConnection(java.net.URL) + */ + public URLConnection openConnection(URL u) throws IOException { + throw new IOException(NLS.bind("URLConnection cannot be created for {0}", u.toExternalForm())); //$NON-NLS-1$ + } + + } + + private final DummyURLStreamHandlerService dummyService = new DummyURLStreamHandlerService(); + + private void registerScheme(String protocol) { + final Hashtable properties = new Hashtable(); + properties.put(URLConstants.URL_HANDLER_PROTOCOL, new String[] {protocol}); + context.registerService(URLStreamHandlerService.class.getName(), dummyService, properties); + } + + public IRetrieveFileTransfer getFileTransfer(String protocol) { + ProtocolFactory protocolFactory = null; + synchronized (retrieveFileTransferProtocolMap) { + protocolFactory = (ProtocolFactory) retrieveFileTransferProtocolMap.get(protocol); + } + if (protocolFactory == null) + return null; + final IRetrieveFileTransferFactory factory = (IRetrieveFileTransferFactory) protocolFactory.getFactory(); + if (factory != null) + return factory.newInstance(); + return null; + } + + public ISendFileTransfer getSendFileTransfer(String protocol) { + ProtocolFactory protocolFactory = null; + synchronized (sendFileTransferProtocolMap) { + protocolFactory = (ProtocolFactory) sendFileTransferProtocolMap.get(protocol); + } + if (protocolFactory == null) + return null; + final ISendFileTransferFactory factory = (ISendFileTransferFactory) protocolFactory.getFactory(); + if (factory != null) + return factory.newInstance(); + return null; + } + + public IRemoteFileSystemBrowser getBrowseFileTransfer(String protocol) { + ProtocolFactory protocolFactory = null; + synchronized (browseFileTransferProtocolMap) { + protocolFactory = (ProtocolFactory) browseFileTransferProtocolMap.get(protocol); + } + if (protocolFactory == null) + return null; + final IRemoteFileSystemBrowserFactory factory = (IRemoteFileSystemBrowserFactory) protocolFactory.getFactory(); + if (factory != null) + return factory.newInstance(); + return null; + } + + public IAdapterManager getAdapterManager() { + // First, try to get the adapter manager via + if (adapterManagerTracker == null) { + adapterManagerTracker = new ServiceTracker(this.context, IAdapterManager.class.getName(), null); + adapterManagerTracker.open(); + } + IAdapterManager adapterManager = (IAdapterManager) adapterManagerTracker.getService(); + // Then, if the service isn't there, try to get from Platform class via + // PlatformHelper class + if (adapterManager == null) + adapterManager = PlatformHelper.getPlatformAdapterManager(); + return adapterManager; + } + + public IURLConnectionModifier getURLConnectionModifier() { + return urlConnectionModifier; + } + + public boolean setRetrieveFileTransferFactory(String protocol, String id, IRetrieveFileTransferFactory factory, int priority) { + return setRetrieveFileTransferFactory(protocol, id, factory, priority, false); + } + + public boolean setRetrieveFileTransferFactory(String protocol, String id, IRetrieveFileTransferFactory factory, int priority, boolean uri) { + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return false; + if (id == null) + return false; + if (factory == null) + return false; + if (!pluginExcluded(id)) { + // Now create new ProtocolFactory + ProtocolFactory newProtocolFactory = new ProtocolFactory(factory, priority, id); + synchronized (retrieveFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) retrieveFileTransferProtocolMap.get(protocol); + // If found, choose between them based upon comparing their priority + if (oldProtocolFactory != null) { + // Now, compare priorities and pick winner + String CONTRIBUTION_WARNING = "File retrieve contribution"; //$NON-NLS-1$ + int result = oldProtocolFactory.compareTo(newProtocolFactory); + if (result < 0) { + // Existing one has higher priority, so we provide warning and return (leaving existing one as the handler) + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be ignored. Existing protocol factory has higher priority.", new Object[] {CONTRIBUTION_WARNING, protocol, id}), null)); //$NON-NLS-1$ + return false; + } else if (result == 0) { + // Warn that we are using new one because they have the same priority. + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be used in preference to existing handler. Both have same priority={3}.", new Object[] {CONTRIBUTION_WARNING, protocol, id, Integer.valueOf(priority)}), null)); //$NON-NLS-1$ + } else if (result > 0) { + // Warn that we are using new one because it has higher priority. + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be used in preference to existing handler. New handler has higher priority={3}<{4}.", new Object[] {CONTRIBUTION_WARNING, protocol, id, Integer.valueOf(priority), Integer.valueOf(oldProtocolFactory.priority)}), null)); //$NON-NLS-1$ + } + } + // If !uri, then check/register protocol as URLStreamHandlerService + if (!uri) { + String[] existingSchemes = getPlatformSupportedSchemes(); + if (!isSchemeRegistered(protocol, existingSchemes)) + registerScheme(protocol); + } + // Finally, put protocol factory in map with protocol as key + retrieveFileTransferProtocolMap.put(protocol, newProtocolFactory); + return true; + } + } + return false; + } + + public String getRetrieveFileTransferFactoryId(String protocol) { + if (protocol == null) + return null; + synchronized (retrieveFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) retrieveFileTransferProtocolMap.get(protocol); + if (oldProtocolFactory == null) + return null; + return oldProtocolFactory.getID(); + } + } + + public int getRetrieveFileTransferPriority(String protocol) { + if (protocol == null) + return -1; + synchronized (retrieveFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) retrieveFileTransferProtocolMap.get(protocol); + if (oldProtocolFactory == null) + return -1; + return oldProtocolFactory.getPriority(); + } + } + + public boolean removeRetrieveFileTransferFactory(String id) { + if (id == null) + return false; + boolean removed = false; + synchronized (retrieveFileTransferProtocolMap) { + for (Iterator i = retrieveFileTransferProtocolMap.keySet().iterator(); i.hasNext();) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) retrieveFileTransferProtocolMap.get(i.next()); + if (oldProtocolFactory == null) + continue; + if (id.equals(oldProtocolFactory.getID())) { + i.remove(); + removed = true; + } + } + return removed; + } + } + + public boolean setBrowseFileTransferFactory(String protocol, String id, IRemoteFileSystemBrowserFactory factory, int priority) { + return setBrowseFileTransferFactory(protocol, id, factory, priority, false); + } + + public boolean setBrowseFileTransferFactory(String protocol, String id, IRemoteFileSystemBrowserFactory factory, int priority, boolean uri) { + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return false; + if (id == null) + return false; + if (factory == null) + return false; + if (!pluginExcluded(id)) { + // Now create new ProtocolFactory + ProtocolFactory newProtocolFactory = new ProtocolFactory(factory, priority, id); + synchronized (browseFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) browseFileTransferProtocolMap.get(protocol); + // If found, choose between them based upon comparing their priority + if (oldProtocolFactory != null) { + // Now, compare priorities and pick winner + String CONTRIBUTION_WARNING = "File browse contribution"; //$NON-NLS-1$ + int result = oldProtocolFactory.compareTo(newProtocolFactory); + if (result < 0) { + // Existing one has higher priority, so we provide warning and return (leaving existing one as the handler) + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be ignored. Existing protocol factory has higher priority.", new Object[] {CONTRIBUTION_WARNING, protocol, id}), null)); //$NON-NLS-1$ + return false; + } else if (result == 0) { + // Warn that we are using new one because they have the same priority. + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be used in preference to existing handler. Both have same priority={3}.", new Object[] {CONTRIBUTION_WARNING, protocol, id, Integer.valueOf(priority)}), null)); //$NON-NLS-1$ + } else if (result > 0) { + // Warn that we are using new one because it has higher priority. + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be used in preference to existing handler. New handler has higher priority={3}<{4}.", new Object[] {CONTRIBUTION_WARNING, protocol, id, Integer.valueOf(priority), Integer.valueOf(oldProtocolFactory.priority)}), null)); //$NON-NLS-1$ + } + } + // If !uri, then check/register protocol as URLStreamHandlerService + if (!uri) { + String[] existingSchemes = getPlatformSupportedSchemes(); + if (!isSchemeRegistered(protocol, existingSchemes)) + registerScheme(protocol); + } + // Finally, put protocol factory in map with protocol as key + browseFileTransferProtocolMap.put(protocol, newProtocolFactory); + return true; + } + } + return false; + } + + public String getBrowseFileTransferFactoryId(String protocol) { + if (protocol == null) + return null; + synchronized (browseFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) browseFileTransferProtocolMap.get(protocol); + if (oldProtocolFactory == null) + return null; + return oldProtocolFactory.getID(); + } + } + + public int getBrowseFileTransferPriority(String protocol) { + if (protocol == null) + return -1; + synchronized (browseFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) browseFileTransferProtocolMap.get(protocol); + if (oldProtocolFactory == null) + return -1; + return oldProtocolFactory.getPriority(); + } + } + + public boolean removeBrowseFileTransferFactory(String id) { + if (id == null) + return false; + boolean removed = false; + synchronized (browseFileTransferProtocolMap) { + for (Iterator i = browseFileTransferProtocolMap.keySet().iterator(); i.hasNext();) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) browseFileTransferProtocolMap.get(i.next()); + if (oldProtocolFactory == null) + continue; + if (id.equals(oldProtocolFactory.getID())) { + i.remove(); + removed = true; + } + } + return removed; + } + } + + public boolean setSendFileTransferFactory(String protocol, String id, ISendFileTransferFactory factory, int priority) { + return setSendFileTransferFactory(protocol, id, factory, priority, false); + } + + public boolean setSendFileTransferFactory(String protocol, String id, ISendFileTransferFactory factory, int priority, boolean uri) { + if (protocol == null || "".equals(protocol)) //$NON-NLS-1$ + return false; + if (id == null) + return false; + if (factory == null) + return false; + if (!pluginExcluded(id)) { + // Now create new ProtocolFactory + ProtocolFactory newProtocolFactory = new ProtocolFactory(factory, priority, id); + synchronized (sendFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) sendFileTransferProtocolMap.get(protocol); + // If found, choose between them based upon comparing their priority + if (oldProtocolFactory != null) { + // Now, compare priorities and pick winner + String CONTRIBUTION_WARNING = "File send contribution"; //$NON-NLS-1$ + int result = oldProtocolFactory.compareTo(newProtocolFactory); + if (result < 0) { + // Existing one has higher priority, so we provide warning and return (leaving existing one as the handler) + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be ignored. Existing protocol factory has higher priority.", new Object[] {CONTRIBUTION_WARNING, protocol, id}), null)); //$NON-NLS-1$ + return false; + } else if (result == 0) { + // Warn that we are using new one because they have the same priority. + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be used in preference to existing handler. Both have same priority={3}.", new Object[] {CONTRIBUTION_WARNING, protocol, id, Integer.valueOf(priority)}), null)); //$NON-NLS-1$ + } else if (result > 0) { + // Warn that we are using new one because it has higher priority. + Activator.getDefault().log(new Status(IStatus.WARNING, PLUGIN_ID, IStatus.WARNING, NLS.bind("{0} for protocol {1} from {2} will be used in preference to existing handler. New handler has higher priority={3}<{4}.", new Object[] {CONTRIBUTION_WARNING, protocol, id, Integer.valueOf(priority), Integer.valueOf(oldProtocolFactory.priority)}), null)); //$NON-NLS-1$ + } + } + // If !uri, then check/register protocol as URLStreamHandlerService + if (!uri) { + String[] existingSchemes = getPlatformSupportedSchemes(); + if (!isSchemeRegistered(protocol, existingSchemes)) + registerScheme(protocol); + } + // Finally, put protocol factory in map with protocol as key + sendFileTransferProtocolMap.put(protocol, newProtocolFactory); + return true; + } + } + return false; + } + + public String getSendFileTransferFactoryId(String protocol) { + if (protocol == null) + return null; + synchronized (sendFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) sendFileTransferProtocolMap.get(protocol); + if (oldProtocolFactory == null) + return null; + return oldProtocolFactory.getID(); + } + } + + public int getSendFileTransferPriority(String protocol) { + if (protocol == null) + return -1; + synchronized (sendFileTransferProtocolMap) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) sendFileTransferProtocolMap.get(protocol); + if (oldProtocolFactory == null) + return -1; + return oldProtocolFactory.getPriority(); + } + } + + public boolean removeSendFileTransferFactory(String id) { + if (id == null) + return false; + boolean removed = false; + synchronized (sendFileTransferProtocolMap) { + for (Iterator i = sendFileTransferProtocolMap.keySet().iterator(); i.hasNext();) { + ProtocolFactory oldProtocolFactory = (ProtocolFactory) sendFileTransferProtocolMap.get(i.next()); + if (oldProtocolFactory == null) + continue; + if (id.equals(oldProtocolFactory.getID())) { + i.remove(); + removed = true; + } + } + return removed; + } + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/DebugOptions.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/DebugOptions.java new file mode 100644 index 0000000000..bc571cfbac --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/DebugOptions.java @@ -0,0 +1,26 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.internal.provider.filetransfer; + +public interface DebugOptions { + + public static final String DEBUG = Activator.PLUGIN_ID + "/debug"; //$NON-NLS-1$ + + public static final String EXCEPTIONS_CATCHING = DEBUG + "/exceptions/catching"; //$NON-NLS-1$ + + public static final String EXCEPTIONS_THROWING = DEBUG + "/exceptions/throwing"; //$NON-NLS-1$ + + public static final String METHODS_ENTERING = DEBUG + "/methods/entering"; //$NON-NLS-1$ + + public static final String METHODS_EXITING = DEBUG + "/methods/exiting"; //$NON-NLS-1$ + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/IURLConnectionModifier.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/IURLConnectionModifier.java new file mode 100644 index 0000000000..326d122b8b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/IURLConnectionModifier.java @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.internal.provider.filetransfer; + +import java.net.URLConnection; +import org.osgi.framework.BundleContext; + +/** + * + */ +public interface IURLConnectionModifier { + + public void init(BundleContext context); + + public void setSocketFactoryForConnection(URLConnection urlConnection); + + public void dispose(); +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Messages.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Messages.java new file mode 100644 index 0000000000..695c191cb4 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/Messages.java @@ -0,0 +1,81 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.internal.provider.filetransfer; + +import org.eclipse.osgi.util.NLS; + +/** + * + */ +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.ecf.internal.provider.filetransfer.messages"; //$NON-NLS-1$ + public static String AbstractOutgoingFileTransfer_EXCEPTION_FILE_TRANSFER_INFO_NOT_NULL; + public static String AbstractOutgoingFileTransfer_EXCEPTION_IN_FINALLY; + public static String AbstractRetrieveFileTransfer_TransferRateFormat; + public static String AbstractRetrieveFileTransfer_MalformedURLException; + public static String AbstractRetrieveFileTransfer_Progress_Data; + public static String AbstractRetrieveFileTransfer_EXCEPTION_IN_FINALLY; + public static String AbstractRetrieveFileTransfer_Exception_User_Cancelled; + public static String AbstractRetrieveFileTransfer_InfoTransferRate; + public static String AbstractRetrieveFileTransfer_RemoteFileID_Not_Null; + public static String AbstractRetrieveFileTransfer_SizeUnitBytes; + public static String AbstractRetrieveFileTransfer_SizeUnitGB; + public static String AbstractRetrieveFileTransfer_SizeUnitKB; + public static String AbstractRetrieveFileTransfer_SizeUnitMB; + public static String AbstractRetrieveFileTransfer_Status_Transfer_Completed_OK; + public static String AbstractRetrieveFileTransfer_Status_Transfer_Exception; + public static String AbstractRetrieveFileTransfer_TransferListener_Not_Null; + public static String AbstractOutgoingFileTransfer_MalformedURLException; + public static String AbstractOutgoingFileTransfer_Progress_Data; + public static String AbstractOutgoingFileTransfer_Exception_User_Cancelled; + public static String AbstractOutgoingFileTransfer_RemoteFileID_Not_Null; + public static String AbstractOutgoingFileTransfer_Status_Transfer_Completed_OK; + public static String AbstractOutgoingFileTransfer_Status_Transfer_Exception; + public static String AbstractOutgoingFileTransfer_TransferListener_Not_Null; + public static String UrlConnectionRetrieveFileTransfer_RESUME_START_ERROR; + public static String UrlConnectionRetrieveFileTransfer_INVALID_SERVER_RESPONSE_TO_PARTIAL_RANGE_REQUEST; + public static String UrlConnectionRetrieveFileTransfer_RESUME_ERROR_END_POSITION_LESS_THAN_START; + public static String UrlConnectionRetrieveFileTransfer_CONNECT_EXCEPTION_NOT_CONNECTED; + public static String UrlConnectionRetrieveFileTransfer_EXCEPTION_FILE_MODIFIED_SINCE_LAST_ACCESS; + public static String UrlConnectionRetrieveFileTransfer_EXCEPTION_COULD_NOT_CONNECT; + public static String UrlConnectionRetrieveFileTransfer_EXCEPTION_INVALID_SERVER_RESPONSE; + public static String UrlConnectionRetrieveFileTransfer_RESUME_START_POSITION_LESS_THAN_ZERO; + public static String UrlConnectionRetrieveFileTransfer_UnsupportedCallbackException; + public static String UrlConnectionRetrieveFileTransfer_USERNAME_PROMPT; + public static String UrlConnectionOutgoingFileTransfer_EXCEPTION_COULD_NOT_CONNECT; + public static String FileSystemBrowser_EXCEPTION_DIRECTORY_DOES_NOT_EXIST; + public static String FileTransferNamespace_Exception_Create_Instance; + public static String FileTransferNamespace_Exception_Create_Instance_Failed; + public static String FileTransferNamespace_File_Protocol; + public static String FileTransferNamespace_Ftp_Protocol; + public static String FileTransferNamespace_Http_Protocol; + public static String FileTransferNamespace_Https_Protocol; + public static String FileTransferNamespace_Jar_Protocol; + public static String FileTransferNamespace_Mailto_Protocol; + public static String FileTransferNamespace_Gopher_Protocol; + public static String FileTransferNamespace_Namespace_Protocol; + public static String FileTransferID_Exception_Url_Not_Null; + public static String LocalFileOutgoingFileTransfer_EXCEPTION_OPENING_FOR_INPUT; + public static String LocalFileOutgoingFileTransfer_EXCEPTION_OPENING_FOR_OUTPUT; + public static String MultiProtocolOutgoingAdapter_EXCEPTION_NO_PROTOCOL_HANDER; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + // + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/messages.properties b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/messages.properties new file mode 100644 index 0000000000..8e1f3c7636 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/internal/provider/filetransfer/messages.properties @@ -0,0 +1,59 @@ +############################################################################ +# Copyright (c) 2006, 2007 Composent, Inc. and others. +# +# This program and the accompanying materials are made +# available under the terms of the Eclipse Public License 2.0 +# which is available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################ + +AbstractOutgoingFileTransfer_EXCEPTION_FILE_TRANSFER_INFO_NOT_NULL=File transfer info cannot be null. +AbstractOutgoingFileTransfer_EXCEPTION_IN_FINALLY=Exception in send done event handler. +AbstractRetrieveFileTransfer_TransferRateFormat=0.00 {0} +AbstractRetrieveFileTransfer_Progress_Data=\ - data +AbstractRetrieveFileTransfer_EXCEPTION_IN_FINALLY=Exception in receive done/paused event handler. +AbstractRetrieveFileTransfer_Exception_User_Cancelled=Cancelled by user +AbstractRetrieveFileTransfer_InfoTransferRate=({0}/s) +AbstractRetrieveFileTransfer_Status_Transfer_Completed_OK=Transfer Completed OK +UrlConnectionRetrieveFileTransfer_CONNECT_EXCEPTION_NOT_CONNECTED=not connected +UrlConnectionRetrieveFileTransfer_EXCEPTION_FILE_MODIFIED_SINCE_LAST_ACCESS=file modified since last access +UrlConnectionRetrieveFileTransfer_EXCEPTION_COULD_NOT_CONNECT=Exception connecting to {0}. +UrlConnectionRetrieveFileTransfer_EXCEPTION_INVALID_SERVER_RESPONSE=invalid server response +UrlConnectionRetrieveFileTransfer_INVALID_SERVER_RESPONSE_TO_PARTIAL_RANGE_REQUEST=invalid server response to partial range request +UrlConnectionRetrieveFileTransfer_RESUME_ERROR_END_POSITION_LESS_THAN_START=end position cannot be less than or equal to start position +UrlConnectionRetrieveFileTransfer_RESUME_START_ERROR=resume start error +UrlConnectionRetrieveFileTransfer_RESUME_START_POSITION_LESS_THAN_ZERO=start position cannot be less then 0 +UrlConnectionRetrieveFileTransfer_UnsupportedCallbackException=Password not provided from callback. +UrlConnectionRetrieveFileTransfer_USERNAME_PROMPT=Username: +UrlConnectionOutgoingFileTransfer_EXCEPTION_COULD_NOT_CONNECT=Exception connecting to {0}. +AbstractRetrieveFileTransfer_Status_Transfer_Exception=Transfer Exception +AbstractRetrieveFileTransfer_RemoteFileID_Not_Null=remoteFileID cannot be null +AbstractRetrieveFileTransfer_TransferListener_Not_Null=transferListener cannot be null +AbstractOutgoingFileTransfer_Progress_Data=\ - data +AbstractOutgoingFileTransfer_Exception_User_Cancelled=Canceled by user +AbstractOutgoingFileTransfer_Status_Transfer_Completed_OK=Transfer Completed OK +AbstractOutgoingFileTransfer_Status_Transfer_Exception=Transfer Exception +AbstractOutgoingFileTransfer_RemoteFileID_Not_Null=remoteFileID cannot be null +AbstractOutgoingFileTransfer_TransferListener_Not_Null=transferListener cannot be null +AbstractOutgoingFileTransfer_MalformedURLException=Invalid URL +AbstractRetrieveFileTransfer_MalformedURLException=Exception creating URL for {0} +AbstractRetrieveFileTransfer_SizeUnitBytes=bytes +AbstractRetrieveFileTransfer_SizeUnitGB=GB +AbstractRetrieveFileTransfer_SizeUnitKB=KB +AbstractRetrieveFileTransfer_SizeUnitMB=MB +FileSystemBrowser_EXCEPTION_DIRECTORY_DOES_NOT_EXIST=Directory {0} does not exist. +FileTransferNamespace_Namespace_Protocol=ecf.provider.filetransfer +FileTransferNamespace_Http_Protocol=http +FileTransferNamespace_Ftp_Protocol=ftp +FileTransferNamespace_File_Protocol=file +FileTransferNamespace_Jar_Protocol=jar +FileTransferNamespace_Https_Protocol=https +FileTransferNamespace_Mailto_Protocol=mailto +FileTransferNamespace_Gopher_Protocol=mailto +FileTransferNamespace_Exception_Create_Instance=Exception in createInstance +FileTransferNamespace_Exception_Create_Instance_Failed=arguments not correct to create instance of FileTransferNamespace +FileTransferID_Exception_Url_Not_Null=FileTransferID URL cannot be null +LocalFileOutgoingFileTransfer_EXCEPTION_OPENING_FOR_INPUT=Exception opening file {0} for input. +LocalFileOutgoingFileTransfer_EXCEPTION_OPENING_FOR_OUTPUT=Exception opening {0} for output. +MultiProtocolOutgoingAdapter_EXCEPTION_NO_PROTOCOL_HANDER=No protocol handler for {0} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/IFileTransferProtocolToFactoryMapper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/IFileTransferProtocolToFactoryMapper.java new file mode 100644 index 0000000000..6d6cd2ed40 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/IFileTransferProtocolToFactoryMapper.java @@ -0,0 +1,230 @@ +/**************************************************************************** + * Copyright (c) 2009 EclipseSource and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * EclipseSource - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer; + +import org.eclipse.ecf.filetransfer.service.IRemoteFileSystemBrowserFactory; +import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransferFactory; +import org.eclipse.ecf.filetransfer.service.ISendFileTransferFactory; + +/** + * + * @since 3.0.1 + * + */ +public interface IFileTransferProtocolToFactoryMapper { + + /** + *

+ * For the given protocol, set the given factory to be used for retrieve file transfer. If successful, subsequent retrieve + * requests for the given protocol will use the given factory.

+ *

For this method to be successful the protocol has to be + * non-null, the id has to be non-null and unique (should probably be set to the bundle symbolic name of the bundle calling this + * method), the factory must be non-null, and the priority must be higher (a *smaller number*) than any existing factory for the + * given protocol. The default priority is 100, and the highest priority is 0. + *

+ * @param protocol the protocol (e.g. http/https) to map the factory to. + * @param id a unique id for the factory (should be bundle symbolic name of bundle calling method) + * @param factory the factory to associate with the given protocol + * @param priority priority (highest = 0) to use for this factory relative to any existing factories. + * @return true if the given factory was set for this protocol, false if not + */ + public boolean setRetrieveFileTransferFactory(String protocol, String id, IRetrieveFileTransferFactory factory, int priority); + + /** + *

+ * For the given protocol, set the given factory to be used for retrieve file transfer. If successful, subsequent retrieve + * requests for the given protocol will use the given factory.

+ *

For this method to be successful the protocol has to be + * non-null, the id has to be non-null and unique (should probably be set to the bundle symbolic name of the bundle calling this + * method), the factory must be non-null, and the priority must be higher (a *smaller number*) than any existing factory for the + * given protocol. The default priority is 100, and the highest priority is 0. + *

+ * @param protocol the protocol (e.g. http/https) to map the factory to. + * @param id a unique id for the factory (should be bundle symbolic name of bundle calling method) + * @param factory the factory to associate with the given protocol + * @param priority priority (highest = 0) to use for this factory relative to any existing factories. + * @param uri if true the factory is added as a URI rather than a URL, meaning that no URLStreamHandler is + * registered for the given protocol. This is in contrast to the {@link #setRetrieveFileTransferFactory(String, String, IRetrieveFileTransferFactory, int)}, + * which automatically registers an URLStreamHandler for the given protocol. If false, URLs will be used and an URLStreamHandler will be registered for the + * given protocol factory. NOTE: If this flag is true, providers that attempt to access IFileID.getURL() may be unable to do so, since the + * URI may not be successfully parsed as a URL. + * + * @return true if the given factory was set for this protocol, false if not + */ + public boolean setRetrieveFileTransferFactory(String protocol, String id, IRetrieveFileTransferFactory factory, int priority, boolean uri); + + /** + * Get the factory id of the active factory for the given protocol. If the given protocol does not have an + * active factory, returns null. + * + * @param protocol the protocol to get the id for (e.g. http/https) + * + * @return id of the factory associated with the given protocol + */ + public String getRetrieveFileTransferFactoryId(String protocol); + + /** + * Get the priority of the active factory for the given protocol. If the given protocol does not have an active factory, returns -1. + * + * @param protocol the protocol to get the priority for (e.g. http/https) + * + * @return int priority for the given protocol + */ + public int getRetrieveFileTransferPriority(String protocol); + + /** + * Remove the factory with the given id. + * @param id the id of the factory to remove. + * @return true if a factory was removed. false otherwise. + */ + public boolean removeRetrieveFileTransferFactory(String id); + + /** + *

+ * For the given protocol, set the given factory to be used for retrieve file transfer. If successful, subsequent retrieve + * requests for the given protocol will use the given factory.

+ *

For this method to be successful the protocol has to be + * non-null, the id has to be non-null and unique (should probably be set to the bundle symbolic name of the bundle calling this + * method), the factory must be non-null, and the priority must be higher (a *smaller number*) than any existing factory for the + * given protocol. The default priority is 100, and the highest priority is 0. + *

+ * @param protocol the protocol (e.g. http/https) to map the factory to. + * @param id a unique id for the factory (should be bundle symbolic name of bundle calling method) + * @param factory the factory to associate with the given protocol + * @param priority priority (highest = 0) to use for this factory relative to any existing factories. + * @return true if the given factory was set for this protocol, false if not + */ + public boolean setBrowseFileTransferFactory(String protocol, String id, IRemoteFileSystemBrowserFactory factory, int priority); + + /** + *

+ * For the given protocol, set the given factory to be used for retrieve file transfer. If successful, subsequent retrieve + * requests for the given protocol will use the given factory.

+ *

For this method to be successful the protocol has to be + * non-null, the id has to be non-null and unique (should probably be set to the bundle symbolic name of the bundle calling this + * method), the factory must be non-null, and the priority must be higher (a *smaller number*) than any existing factory for the + * given protocol. The default priority is 100, and the highest priority is 0. + *

+ * @param protocol the protocol (e.g. http/https) to map the factory to. + * @param id a unique id for the factory (should be bundle symbolic name of bundle calling method) + * @param factory the factory to associate with the given protocol + * @param priority priority (highest = 0) to use for this factory relative to any existing factories. + * @param uri if true the factory is added as a URI rather than a URL, meaning that no URLStreamHandler is + * registered for the given protocol. This is in contrast to the {@link #setRetrieveFileTransferFactory(String, String, IRetrieveFileTransferFactory, int)}, + * which automatically registers an URLStreamHandler for the given protocol. If false, URLs will be used and an URLStreamHandler will be registered for the + * given protocol factory. NOTE: If this flag is true, providers that attempt to access IFileID.getURL() may be unable to do so, since the + * URI may not be successfully parsed as a URL. + * + * @return true if the given factory was set for this protocol, false if not + */ + public boolean setBrowseFileTransferFactory(String protocol, String id, IRemoteFileSystemBrowserFactory factory, int priority, boolean uri); + + /** + * Get the factory id of the active factory for the given protocol. If the given protocol does not have an + * active factory, returns null. + * + * @param protocol the protocol to get the id for (e.g. http/https) + * + * @return id of the factory associated with the given protocol + */ + public String getBrowseFileTransferFactoryId(String protocol); + + /** + * Get the priority of the active factory for the given protocol. If the given protocol does not have an active factory, returns -1. + * + * @param protocol the protocol to get the priority for (e.g. http/https) + * + * @return int priority for the given protocol + */ + public int getBrowseFileTransferPriority(String protocol); + + /** + * Remove the factory with the given id. + * @param id the id of the factory to remove. + * @return true if a factory was removed. false otherwise. + */ + public boolean removeBrowseFileTransferFactory(String id); + + /** + *

+ * For the given protocol, set the given factory to be used for retrieve file transfer. If successful, subsequent retrieve + * requests for the given protocol will use the given factory.

+ *

For this method to be successful the protocol has to be + * non-null, the id has to be non-null and unique (should probably be set to the bundle symbolic name of the bundle calling this + * method), the factory must be non-null, and the priority must be higher (a *smaller number*) than any existing factory for the + * given protocol. The default priority is 100, and the highest priority is 0. + *

+ * @param protocol the protocol (e.g. http/https) to map the factory to. + * @param id a unique id for the factory (should be bundle symbolic name of bundle calling method) + * @param factory the factory to associate with the given protocol + * @param priority priority (highest = 0) to use for this factory relative to any existing factories. + * @return true if the given factory was set for this protocol, false if not + */ + public boolean setSendFileTransferFactory(String protocol, String id, ISendFileTransferFactory factory, int priority); + + /** + *

+ * For the given protocol, set the given factory to be used for retrieve file transfer. If successful, subsequent retrieve + * requests for the given protocol will use the given factory.

+ *

For this method to be successful the protocol has to be + * non-null, the id has to be non-null and unique (should probably be set to the bundle symbolic name of the bundle calling this + * method), the factory must be non-null, and the priority must be higher (a *smaller number*) than any existing factory for the + * given protocol. The default priority is 100, and the highest priority is 0. + *

+ * @param protocol the protocol (e.g. http/https) to map the factory to. + * @param id a unique id for the factory (should be bundle symbolic name of bundle calling method) + * @param factory the factory to associate with the given protocol + * @param priority priority (highest = 0) to use for this factory relative to any existing factories. + * @param uri if true the factory is added as a URI rather than a URL, meaning that no URLStreamHandler is + * registered for the given protocol. This is in contrast to the {@link #setRetrieveFileTransferFactory(String, String, IRetrieveFileTransferFactory, int)}, + * which automatically registers an URLStreamHandler for the given protocol. If false, URLs will be used and an URLStreamHandler will be registered for the + * given protocol factory. NOTE: If this flag is true, providers that attempt to access IFileID.getURL() may be unable to do so, since the + * URI may not be successfully parsed as a URL. + * + * @return true if the given factory was set for this protocol, false if not + */ + public boolean setSendFileTransferFactory(String protocol, String id, ISendFileTransferFactory factory, int priority, boolean uri); + + /** + * Get the factory id of the active factory for the given protocol. If the given protocol does not have an + * active factory, returns null. + * + * @param protocol the protocol to get the id for (e.g. http/https) + * + * @return id of the factory associated with the given protocol + */ + public String getSendFileTransferFactoryId(String protocol); + + /** + * Get the priority of the active factory for the given protocol. If the given protocol does not have an active factory, returns -1. + * + * @param protocol the protocol to get the priority for (e.g. http/https) + * + * @return int priority for the given protocol + */ + public int getSendFileTransferPriority(String protocol); + + /** + * Remove the factory with the given id. + * @param id the id of the factory to remove. + * @return true if a factory was removed. false otherwise. + */ + public boolean removeSendFileTransferFactory(String id); + + /** + * Reinitialized protocol to factory mapping defined via extension registry/extension points. + * @return true if reinitialization succeeds, false if not + */ + public boolean reinitialize(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/AbstractFileSystemBrowser.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/AbstractFileSystemBrowser.java new file mode 100644 index 0000000000..2dfe8de688 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/AbstractFileSystemBrowser.java @@ -0,0 +1,267 @@ +/**************************************************************************** + * Copyright (c) 2007, 2010 Composent, Inc., IBM and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * Henrich Kraemer - bug 263613, [transport] Update site contacting / downloading is not cancelable + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.IRemoteFile; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemListener; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemRequest; +import org.eclipse.ecf.filetransfer.UserCancelledException; +import org.eclipse.ecf.filetransfer.events.IRemoteFileSystemBrowseEvent; +import org.eclipse.ecf.filetransfer.events.IRemoteFileSystemEvent; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.util.ProxySetupHelper; + +/** + * Abstract class for browsing an efs file system. + */ +public abstract class AbstractFileSystemBrowser { + + protected IFileID fileID = null; + protected IRemoteFileSystemListener listener = null; + + private Exception exception = null; + protected IRemoteFile[] remoteFiles = null; + + protected Proxy proxy; + protected URL directoryOrFile; + + protected IConnectContext connectContext; + + protected DirectoryJob job = null; + + Object lock = new Object(); + + protected class DirectoryJob extends Job { + + private IRemoteFileSystemRequest request; + + public DirectoryJob() { + super(fileID.getName()); + } + + protected IStatus run(IProgressMonitor monitor) { + try { + if (monitor.isCanceled()) + throw newUserCancelledException(); + runRequest(); + } catch (Exception e) { + AbstractFileSystemBrowser.this.setException(e); + } finally { + listener.handleRemoteFileEvent(createRemoteFileEvent()); + cleanUp(); + } + return Status.OK_STATUS; + } + + public void setRequest(IRemoteFileSystemRequest request) { + this.request = request; + } + + public IRemoteFileSystemRequest getRequest() { + return request; + } + + protected void canceling() { + request.cancel(); + } + + } + + protected void cancel() { + synchronized (lock) { + if (job != null) { + job.cancel(); + } + } + + } + + protected void cleanUp() { + synchronized (lock) { + job = null; + } + } + + /** + * Run the actual request. This method is called within the job created to actually get the + * directory or file information. + * @throws Exception if some problem with making the request or receiving response to the request. + */ + protected abstract void runRequest() throws Exception; + + public AbstractFileSystemBrowser(IFileID directoryOrFileID, IRemoteFileSystemListener listener, URL url, IConnectContext connectContext, Proxy proxy) { + Assert.isNotNull(directoryOrFileID); + this.fileID = directoryOrFileID; + Assert.isNotNull(listener); + this.listener = listener; + this.directoryOrFile = url; + this.connectContext = connectContext; + this.proxy = proxy; + } + + public abstract class RemoteFileSystemRequest implements IRemoteFileSystemRequest { + public void cancel() { + synchronized (lock) { + if (job != null) + job.cancel(); + } + } + + public IFileID getFileID() { + return fileID; + } + + public IRemoteFileSystemListener getRemoteFileListener() { + return listener; + } + + } + + public IRemoteFileSystemRequest sendBrowseRequest() { + job = new DirectoryJob(); + + IRemoteFileSystemRequest request = createRemoteFileSystemRequest(); + job.setRequest(request); + if (Job.getJobManager().isSuspended()) { + job.run(new NullProgressMonitor()); + } else { + job.schedule(); + } + return request; + } + + protected IRemoteFileSystemRequest createRemoteFileSystemRequest() { + return new RemoteFileSystemRequest() { + public T getAdapter(Class adapter) { + if (adapter == null) { + return null; + } + if (adapter.isInstance(this)) { + return adapter.cast(this); + } + return null; + } + + }; + } + + /** + * @return file system directory event + */ + protected IRemoteFileSystemEvent createRemoteFileEvent() { + return new IRemoteFileSystemBrowseEvent() { + + public IFileID getFileID() { + return fileID; + } + + public Exception getException() { + return exception; + } + + public String toString() { + StringBuilder buf = new StringBuilder("RemoteFileSystemBrowseEvent["); //$NON-NLS-1$ + buf.append("fileID=").append(fileID).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + List list = (remoteFiles != null) ? Arrays.asList(remoteFiles) : null; + buf.append("files=").append(list).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + return buf.toString(); + } + + public IRemoteFile[] getRemoteFiles() { + return remoteFiles; + } + }; + } + + protected abstract void setupProxy(Proxy proxy); + + /** + * Select a single proxy from a set of proxies available for the given host. This implementation + * selects in the following manner: 1) If proxies provided is null or array of 0 length, null + * is returned. If only one proxy is available (array of length 1) then the entry is returned. + * If proxies provided is length greater than 1, then if the type of a proxy in the array matches the given + * protocol (e.g. http, https), then the first matching proxy is returned. If the protocol does + * not match any of the proxies, then the *first* proxy (i.e. proxies[0]) is returned. Subclasses may + * override if desired. + * + * @param protocol the target protocol (e.g. http, https, scp, etc). Will not be null. + * @param proxies the proxies to select from. May be null or array of length 0. + * @return proxy data selected from the proxies provided. + */ + protected IProxyData selectProxyFromProxies(String protocol, IProxyData[] proxies) { + try { + return ProxySetupHelper.selectProxyFromProxies(protocol, proxies); + } catch (NoClassDefFoundError e) { + // If the proxy API is not available a NoClassDefFoundError will be thrown here. + // If that happens then we just want to continue on. + Activator.logNoProxyWarning(e); + return null; + } + } + + protected void setupProxies() { + // If it's been set directly (via ECF API) then this overrides platform settings + if (proxy == null) { + try { + proxy = ProxySetupHelper.getProxy(directoryOrFile.toExternalForm()); + } catch (NoClassDefFoundError e) { + // If the proxy API is not available a NoClassDefFoundError will be thrown here. + // If that happens then we just want to continue on. + Activator.logNoProxyWarning(e); + } + } + if (proxy != null) + setupProxy(proxy); + } + + protected synchronized void setException(Exception exception) { + this.exception = exception; + } + + protected synchronized Exception getException() { + return this.exception; + } + + protected synchronized boolean isCanceled() { + return exception instanceof UserCancelledException; + } + + protected synchronized void setCanceled(Exception e) { + if (e instanceof UserCancelledException) { + exception = e; + } else { + exception = newUserCancelledException(); + } + } + + protected UserCancelledException newUserCancelledException() { + return new UserCancelledException(Messages.AbstractRetrieveFileTransfer_Exception_User_Cancelled); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalFileSystemBrowser.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalFileSystemBrowser.java new file mode 100644 index 0000000000..3b8cfaf872 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalFileSystemBrowser.java @@ -0,0 +1,65 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.io.File; +import java.net.MalformedURLException; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemListener; +import org.eclipse.ecf.filetransfer.RemoteFileSystemException; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.osgi.util.NLS; + +/** + * A class for asynchronously browsing a {@link java.io.File}-based filesystem. + */ +public class LocalFileSystemBrowser extends AbstractFileSystemBrowser { + + protected File local; + + /** + * @param listener listener + * @param directoryID2 remote directory + * @throws RemoteFileSystemException if some problem + */ + public LocalFileSystemBrowser(IFileID directoryID2, IRemoteFileSystemListener listener) throws RemoteFileSystemException { + super(directoryID2, listener, null, null, null); + try { + local = new File(directoryID2.getURL().getPath()); + } catch (MalformedURLException e) { + throw new RemoteFileSystemException(e); + } + if (!local.exists()) + throw new RemoteFileSystemException(NLS.bind(Messages.FileSystemBrowser_EXCEPTION_DIRECTORY_DOES_NOT_EXIST, local)); + } + + protected void runRequest() throws Exception { + if (local.isDirectory()) { + File[] files = local.listFiles(); + remoteFiles = new LocalRemoteFile[files.length]; + for (int i = 0; i < files.length; i++) { + remoteFiles[i] = new LocalRemoteFile(files[i]); + } + } else { + remoteFiles = new LocalRemoteFile[1]; + remoteFiles[0] = new LocalRemoteFile(local); + } + } + + protected void setupProxy(Proxy proxy) { + // nothing + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFile.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFile.java new file mode 100644 index 0000000000..7d64236305 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFile.java @@ -0,0 +1,120 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.io.File; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.filetransfer.IRemoteFile; +import org.eclipse.ecf.filetransfer.IRemoteFileAttributes; +import org.eclipse.ecf.filetransfer.IRemoteFileInfo; +import org.eclipse.ecf.filetransfer.identity.FileIDFactory; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; + +/** + * Local representation of an {@link IRemoteFile}. + */ +public class LocalRemoteFile implements IRemoteFile { + + File file = null; + + IRemoteFileInfo info; + + /** + * @param file the file + */ + public LocalRemoteFile(File file) { + this.file = file; + Assert.isNotNull(file); + this.info = new IRemoteFileInfo() { + + IRemoteFileAttributes attributes = new LocalRemoteFileAttributes(LocalRemoteFile.this.file); + + public IRemoteFileAttributes getAttributes() { + return attributes; + } + + public long getLastModified() { + return LocalRemoteFile.this.file.lastModified(); + } + + public long getLength() { + return LocalRemoteFile.this.file.length(); + } + + public String getName() { + return LocalRemoteFile.this.file.getName(); + } + + public boolean isDirectory() { + return LocalRemoteFile.this.file.isDirectory(); + } + + public void setAttributes(IRemoteFileAttributes attributes) { + // can't set attributes + } + + public void setLastModified(long time) { + // can't set post hoc + } + + public void setName(String name) { + // Can't modify post hoc + } + }; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFile#getID() + */ + public IFileID getID() { + try { + return FileIDFactory.getDefault().createFileID(IDFactory.getDefault().getNamespaceByName(FileTransferNamespace.PROTOCOL), file.toURL()); + } catch (Exception e) { + // Should never happen + return null; + } + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFile#getInfo() + */ + public IRemoteFileInfo getInfo() { + return info; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + if (adapterManager == null) + return null; + return (T) adapterManager.loadAdapter(this, adapter.getName()); + } + + public String toString() { + StringBuilder buf = new StringBuilder("LocalRemoteFile["); //$NON-NLS-1$ + buf.append("id=").append(getID()).append(";"); //$NON-NLS-1$//$NON-NLS-2$ + buf.append("name=").append(getInfo().getName()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("isDir=").append(getInfo().isDirectory()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("length=").append(getInfo().getLength()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("lastMod=").append(getInfo().getLastModified()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("attr=").append(getInfo().getAttributes()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + return buf.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFileAttributes.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFileAttributes.java new file mode 100644 index 0000000000..4fb2aeb82f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/LocalRemoteFileAttributes.java @@ -0,0 +1,86 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import org.eclipse.ecf.filetransfer.IRemoteFileAttributes; + +/** + * File attributes for {@link LocalRemoteFile} instances. + */ +public class LocalRemoteFileAttributes implements IRemoteFileAttributes { + + File file = null; + + static String[] fileAttributes = {IRemoteFileAttributes.READ_ATTRIBUTE, IRemoteFileAttributes.WRITE_ATTRIBUTE, IRemoteFileAttributes.HIDDEN_ATTRIBUTE, IRemoteFileAttributes.EXEC_ATTRIBUTE, IRemoteFileAttributes.ARCHIVE_ATTRIBUTE}; + static List attributeKeys = new ArrayList(Arrays.asList(fileAttributes)); + + public LocalRemoteFileAttributes(File file) { + this.file = file; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileAttributes#getAttribute(java.lang.String) + */ + public String getAttribute(String key) { + if (key == null) + return null; + if (key.equals(IRemoteFileAttributes.READ_ATTRIBUTE)) { + if (file.canRead()) + return Boolean.TRUE.toString(); + } else if (key.equals(IRemoteFileAttributes.WRITE_ATTRIBUTE)) { + if (file.canWrite()) + return Boolean.TRUE.toString(); + } else if (key.equals(IRemoteFileAttributes.HIDDEN_ATTRIBUTE)) { + if (file.isHidden()) + return Boolean.TRUE.toString(); + } else if (key.equals(IRemoteFileAttributes.EXEC_ATTRIBUTE)) { + return Boolean.TRUE.toString(); + } else if (key.equals(IRemoteFileAttributes.ARCHIVE_ATTRIBUTE)) { + return Boolean.TRUE.toString(); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileAttributes#getAttributeKeys() + */ + public Iterator getAttributeKeys() { + return attributeKeys.iterator(); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileAttributes#setAttribute(java.lang.String, java.lang.String) + */ + public void setAttribute(String key, String value) { + // not supported + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuilder buf = new StringBuilder("LocalRemoteFileAttributes["); //$NON-NLS-1$ + for (Iterator i = getAttributeKeys(); i.hasNext();) { + String key = (String) i.next(); + buf.append(key).append("=").append(getAttribute(key)); //$NON-NLS-1$ + buf.append(i.hasNext() ? ";" : "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } + return buf.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapter.java new file mode 100644 index 0000000000..3cef08611a --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapter.java @@ -0,0 +1,112 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.net.MalformedURLException; +import java.net.URL; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemBrowserContainerAdapter; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemListener; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemRequest; +import org.eclipse.ecf.filetransfer.RemoteFileSystemException; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.filetransfer.service.IRemoteFileSystemBrowser; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; + +/** + * Multi protocol handler for remote file system browser. + */ +public class MultiProtocolFileSystemBrowserAdapter implements IRemoteFileSystemBrowser { + + IConnectContext connectContext = null; + Proxy proxy = null; + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setConnectContextForAuthentication(org.eclipse.ecf.core.security.IConnectContext) + */ + public void setConnectContextForAuthentication(IConnectContext connectContext) { + this.connectContext = connectContext; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setProxy(org.eclipse.ecf.core.util.Proxy) + */ + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileSystemBrowserContainerAdapter#getDirectoryNamespace() + */ + public Namespace getBrowseNamespace() { + return IDFactory.getDefault().getNamespaceByName(FileTransferNamespace.PROTOCOL); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileSystemBrowserContainerAdapter#sendDirectoryRequest(org.eclipse.ecf.filetransfer.identity.IFileID, org.eclipse.ecf.filetransfer.IRemoteFileSystemListener) + */ + public IRemoteFileSystemRequest sendBrowseRequest(IFileID directoryOrFileID, IRemoteFileSystemListener listener) throws RemoteFileSystemException { + Assert.isNotNull(directoryOrFileID); + Assert.isNotNull(listener); + URL url; + try { + url = directoryOrFileID.getURL(); + } catch (final MalformedURLException e) { + throw new RemoteFileSystemException(Messages.AbstractRetrieveFileTransfer_MalformedURLException); + } + + IRemoteFileSystemBrowserContainerAdapter fileSystemBrowser = null; + fileSystemBrowser = Activator.getDefault().getBrowseFileTransfer(url.getProtocol()); + + if (fileSystemBrowser == null) { + if (url.getProtocol().equalsIgnoreCase("file")) { //$NON-NLS-1$ + LocalFileSystemBrowser fsb = new LocalFileSystemBrowser(directoryOrFileID, listener); + return fsb.sendBrowseRequest(); + } + URLFileSystemBrowser ufsb = new URLFileSystemBrowser(directoryOrFileID, listener, url, connectContext, proxy); + return ufsb.sendBrowseRequest(); + } + + // Set connect context + fileSystemBrowser.setConnectContextForAuthentication(connectContext); + // Set Proxy + fileSystemBrowser.setProxy(proxy); + + return fileSystemBrowser.sendBrowseRequest(directoryOrFileID, listener); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + if (adapter == null) + return null; + final IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + if (adapterManager == null) + return null; + return (T) adapterManager.loadAdapter(this, adapter.getName()); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapterFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapterFactory.java new file mode 100644 index 0000000000..50a6da5ac1 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/MultiProtocolFileSystemBrowserAdapterFactory.java @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import org.eclipse.ecf.core.AbstractContainerAdapterFactory; +import org.eclipse.ecf.core.IContainer; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemBrowserContainerAdapter; + +/** + * Adapter factory for handling multiple protocols. + */ +public class MultiProtocolFileSystemBrowserAdapterFactory extends AbstractContainerAdapterFactory { + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.sharedobject.AbstractSharedObjectContainerAdapterFactory#getAdapterList() + */ + public Class[] getAdapterList() { + return new Class[] {IRemoteFileSystemBrowserContainerAdapter.class}; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.AbstractContainerAdapterFactory#getContainerAdapter(org.eclipse.ecf.core.IContainer, + * java.lang.Class) + */ + protected Object getContainerAdapter(IContainer container, Class adapterType) { + if (adapterType.equals(IRemoteFileSystemBrowserContainerAdapter.class)) { + return new MultiProtocolFileSystemBrowserAdapter(); + } + return null; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLFileSystemBrowser.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLFileSystemBrowser.java new file mode 100644 index 0000000000..24507b5909 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLFileSystemBrowser.java @@ -0,0 +1,209 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.Authenticator; +import java.net.HttpURLConnection; +import java.net.PasswordAuthentication; +import java.net.URL; +import java.net.URLConnection; +import org.eclipse.ecf.core.security.Callback; +import org.eclipse.ecf.core.security.CallbackHandler; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.security.NameCallback; +import org.eclipse.ecf.core.security.ObjectCallback; +import org.eclipse.ecf.core.security.UnsupportedCallbackException; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.BrowseFileTransferException; +import org.eclipse.ecf.filetransfer.IRemoteFile; +import org.eclipse.ecf.filetransfer.IRemoteFileSystemListener; +import org.eclipse.ecf.filetransfer.IncomingFileTransferException; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.IURLConnectionModifier; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.util.JREProxyHelper; +import org.eclipse.osgi.util.NLS; + +/** + * + */ +public class URLFileSystemBrowser extends AbstractFileSystemBrowser { + + private static final String USERNAME_PREFIX = Messages.UrlConnectionRetrieveFileTransfer_USERNAME_PROMPT; + + private static final String JRE_CONNECT_TIMEOUT_PROPERTY = "sun.net.client.defaultConnectTimeout"; //$NON-NLS-1$ + + // 10/26/2009: Added being able to set with system property with name org.eclipse.ecf.provider.filetransfer.browse.connectTimeout + // for https://bugs.eclipse.org/bugs/show_bug.cgi?id=292995 + private static final String DEFAULT_CONNECT_TIMEOUT = System.getProperty("org.eclipse.ecf.provider.filetransfer.browse.connectTimeout", "30000"); //$NON-NLS-1$ //$NON-NLS-2$ + + private static final String JRE_READ_TIMEOUT_PROPERTY = "sun.net.client.defaultReadTimeout"; //$NON-NLS-1$ + + // 10/26/2009: Added being able to set with system property with name org.eclipse.ecf.provider.filetransfer.browse.readTimeout + // for https://bugs.eclipse.org/bugs/show_bug.cgi?id=292995 + private static final String DEFAULT_READ_TIMEOUT = System.getProperty("org.eclipse.ecf.provider.filetransfer.browse.readTimeout", "30000"); //$NON-NLS-1$ //$NON-NLS-2$ + + private JREProxyHelper proxyHelper = null; + + protected String username = null; + + protected String password = null; + + /** + * @param directoryOrFileID directory or file id + * @param listener listener + * @param directoryOrFileURL directory or file url + * @param connectContext connect context + * @param proxy proxy + */ + public URLFileSystemBrowser(IFileID directoryOrFileID, IRemoteFileSystemListener listener, URL directoryOrFileURL, IConnectContext connectContext, Proxy proxy) { + super(directoryOrFileID, listener, directoryOrFileURL, connectContext, proxy); + proxyHelper = new JREProxyHelper(); + } + + private void setupTimeouts() { + String existingTimeout = System.getProperty(JRE_CONNECT_TIMEOUT_PROPERTY); + if (existingTimeout == null) { + System.setProperty(JRE_CONNECT_TIMEOUT_PROPERTY, DEFAULT_CONNECT_TIMEOUT); + } + existingTimeout = System.getProperty(JRE_READ_TIMEOUT_PROPERTY); + if (existingTimeout == null) { + System.setProperty(JRE_READ_TIMEOUT_PROPERTY, DEFAULT_READ_TIMEOUT); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.provider.filetransfer.browse.AbstractFileSystemBrowser#runRequest() + */ + protected void runRequest() throws Exception { + int code = -1; + try { + setupProxies(); + setupAuthentication(); + setupTimeouts(); + URLConnection urlConnection = directoryOrFile.openConnection(); + // set cache to off if using jar protocol + // this is for addressing bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=235933 + if (directoryOrFile.getProtocol().equalsIgnoreCase("jar")) { //$NON-NLS-1$ + urlConnection.setUseCaches(false); + } + // Add http 1.1 'Connection: close' header in order to potentially avoid + // server issue described here https://bugs.eclipse.org/bugs/show_bug.cgi?id=234916#c13 + // See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=247197 + // also see http 1.1 rfc section 14-10 in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + urlConnection.setRequestProperty("Connection", "close"); //$NON-NLS-1$ //$NON-NLS-2$ + + IURLConnectionModifier connectionModifier = Activator.getDefault().getURLConnectionModifier(); + if (connectionModifier != null) { + connectionModifier.setSocketFactoryForConnection(urlConnection); + } + if (urlConnection instanceof HttpURLConnection) { + HttpURLConnection httpConnection = (HttpURLConnection) urlConnection; + httpConnection.setRequestMethod("HEAD"); //$NON-NLS-1$ + httpConnection.connect(); + } else { + InputStream ins = urlConnection.getInputStream(); + ins.close(); + } + code = getResponseCode(urlConnection); + if (isHTTP()) { + if (code == HttpURLConnection.HTTP_OK) { + // do nothing + } else if (code == HttpURLConnection.HTTP_NOT_FOUND) { + throw new BrowseFileTransferException(NLS.bind("File not found: {0}", directoryOrFile.toString()), code); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_UNAUTHORIZED) { + throw new BrowseFileTransferException("Unauthorized", code); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_FORBIDDEN) { + throw new BrowseFileTransferException("Forbidden", code); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_PROXY_AUTH) { + throw new BrowseFileTransferException("Proxy auth required", code); //$NON-NLS-1$ + } else { + throw new BrowseFileTransferException(NLS.bind("General connection error with response code={0} and header(0)={1}", Integer.valueOf(code), urlConnection.getHeaderField(0)), code); //$NON-NLS-1$ + } + } + remoteFiles = new IRemoteFile[1]; + remoteFiles[0] = new URLRemoteFile(urlConnection.getLastModified(), urlConnection.getContentLength(), fileID); + } catch (final FileNotFoundException e) { + throw new IncomingFileTransferException(NLS.bind("File not found: {0}", directoryOrFile.toString()), 404); //$NON-NLS-1$ + } catch (Exception e) { + Exception except = (e instanceof BrowseFileTransferException) ? e : new BrowseFileTransferException(NLS.bind("Could not connect to {0}", directoryOrFile), e, code); //$NON-NLS-1$ + throw except; + } + } + + private boolean isHTTP() { + final String protocol = directoryOrFile.getProtocol(); + if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) //$NON-NLS-1$ //$NON-NLS-2$ + return true; + return false; + } + + private int getResponseCode(URLConnection urlConnection) { + int responseCode = -1; + String response = urlConnection.getHeaderField(0); + if (response == null) { + responseCode = -1; + return responseCode; + } + if (!response.startsWith("HTTP/")) //$NON-NLS-1$ + return -1; + response = response.trim(); + final int mark = response.indexOf(" ") + 1; //$NON-NLS-1$ + if (mark == 0) + return -1; + int last = mark + 3; + if (last > response.length()) + last = response.length(); + responseCode = Integer.parseInt(response.substring(mark, last)); + return responseCode; + + } + + protected void setupAuthentication() throws IOException, UnsupportedCallbackException { + if (connectContext == null) + return; + final CallbackHandler callbackHandler = connectContext.getCallbackHandler(); + if (callbackHandler == null) + return; + final NameCallback usernameCallback = new NameCallback(USERNAME_PREFIX); + final ObjectCallback passwordCallback = new ObjectCallback(); + // Call callback with username and password callbacks + callbackHandler.handle(new Callback[] {usernameCallback, passwordCallback}); + username = usernameCallback.getName(); + Object o = passwordCallback.getObject(); + if (!(o instanceof String)) + throw new UnsupportedCallbackException(passwordCallback, Messages.UrlConnectionRetrieveFileTransfer_UnsupportedCallbackException); + password = (String) passwordCallback.getObject(); + // Now set authenticator to our authenticator with user and password + Authenticator.setDefault(new UrlConnectionAuthenticator()); + } + + class UrlConnectionAuthenticator extends Authenticator { + /* (non-Javadoc) + * @see java.net.Authenticator#getPasswordAuthentication() + */ + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password.toCharArray()); + } + } + + protected void setupProxy(final Proxy proxy2) { + proxyHelper.setupProxy(proxy2); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFile.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFile.java new file mode 100644 index 0000000000..5059bdea47 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFile.java @@ -0,0 +1,135 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.net.MalformedURLException; +import java.net.URL; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.filetransfer.IRemoteFile; +import org.eclipse.ecf.filetransfer.IRemoteFileAttributes; +import org.eclipse.ecf.filetransfer.IRemoteFileInfo; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; + +/** + * + */ +public class URLRemoteFile implements IRemoteFile { + + IFileID fileID; + + long lastModified; + long fileLength; + IRemoteFileAttributes remoteFileAttributes; + + public URLRemoteFile(long lastModified, long fileLength, IFileID fileID) { + this.lastModified = lastModified; + this.fileLength = fileLength; + Assert.isNotNull(fileID); + this.fileID = fileID; + remoteFileAttributes = new URLRemoteFileAttributes(); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFile#getID() + */ + public IFileID getID() { + return fileID; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFile#getInfo() + */ + public IRemoteFileInfo getInfo() { + return new IRemoteFileInfo() { + + public IRemoteFileAttributes getAttributes() { + return remoteFileAttributes; + } + + public long getLastModified() { + return lastModified; + } + + public long getLength() { + return fileLength; + } + + public String getName() { + URL url; + String result = null; + try { + url = fileID.getURL(); + String path = url.getPath(); + int index = path.lastIndexOf("/"); //$NON-NLS-1$ + if (index == -1) + return path; + result = path.substring(index + 1); + return result; + } catch (MalformedURLException e) { + return fileID.getName(); + } + } + + public boolean isDirectory() { + try { + return fileID.getURL().toString().endsWith("/"); //$NON-NLS-1$ + } catch (MalformedURLException e) { + return false; + } + } + + public void setAttributes(IRemoteFileAttributes attributes) { + // Not supported + } + + public void setLastModified(long time) { + // not supported + } + + public void setName(String name) { + // not supported + } + }; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + if (adapter == null) + return null; + if (adapter.isInstance(this)) + return adapter.cast(this); + IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + if (adapterManager == null) + return null; + return (T) adapterManager.loadAdapter(this, adapter.getName()); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuilder buf = new StringBuilder("URLRemoteFile["); //$NON-NLS-1$ + buf.append("id=").append(getID()).append(";"); //$NON-NLS-1$//$NON-NLS-2$ + buf.append("name=").append(getInfo().getName()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("isDir=").append(getInfo().isDirectory()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("length=").append(getInfo().getLength()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("lastMod=").append(getInfo().getLastModified()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + buf.append("attr=").append(getInfo().getAttributes()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + return buf.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFileAttributes.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFileAttributes.java new file mode 100644 index 0000000000..386e91a638 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/browse/URLRemoteFileAttributes.java @@ -0,0 +1,77 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.browse; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import org.eclipse.ecf.filetransfer.IRemoteFileAttributes; + +/** + * + */ +public class URLRemoteFileAttributes implements IRemoteFileAttributes { + + static String[] fileAttributes = {IRemoteFileAttributes.READ_ATTRIBUTE, IRemoteFileAttributes.WRITE_ATTRIBUTE, IRemoteFileAttributes.HIDDEN_ATTRIBUTE, IRemoteFileAttributes.EXEC_ATTRIBUTE, IRemoteFileAttributes.ARCHIVE_ATTRIBUTE}; + static List attributeKeys = new ArrayList(Arrays.asList(fileAttributes)); + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileAttributes#getAttribute(java.lang.String) + */ + public String getAttribute(String key) { + if (key == null) + return null; + if (key.equals(IRemoteFileAttributes.READ_ATTRIBUTE)) { + return Boolean.TRUE.toString(); + } else if (key.equals(IRemoteFileAttributes.WRITE_ATTRIBUTE)) { + return Boolean.FALSE.toString(); + } else if (key.equals(IRemoteFileAttributes.HIDDEN_ATTRIBUTE)) { + return Boolean.FALSE.toString(); + } else if (key.equals(IRemoteFileAttributes.EXEC_ATTRIBUTE)) { + return Boolean.FALSE.toString(); + } else if (key.equals(IRemoteFileAttributes.ARCHIVE_ATTRIBUTE)) { + return Boolean.TRUE.toString(); + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileAttributes#getAttributeKeys() + */ + public Iterator getAttributeKeys() { + return attributeKeys.iterator(); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IRemoteFileAttributes#setAttribute(java.lang.String, java.lang.String) + */ + public void setAttribute(String key, String value) { + // + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + StringBuilder buf = new StringBuilder("URLRemoteFileAttributes["); //$NON-NLS-1$ + for (Iterator i = getAttributeKeys(); i.hasNext();) { + String key = (String) i.next(); + buf.append(key).append("=").append(getAttribute(key)); //$NON-NLS-1$ + buf.append(i.hasNext() ? ";" : "]"); //$NON-NLS-1$ //$NON-NLS-2$ + } + return buf.toString(); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketEvent.java new file mode 100644 index 0000000000..e4916de209 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketEvent.java @@ -0,0 +1,68 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.events.socket; + +import java.net.Socket; +import org.eclipse.core.runtime.Assert; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEvent; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEventSource; + +public abstract class AbstractSocketEvent implements ISocketEvent { + private Socket factorySocket; + private Socket wrappedSocket; + private ISocketEventSource source; + + protected AbstractSocketEvent(ISocketEventSource source, Socket factorySocket, Socket wrappedSocket) { + Assert.isNotNull(source); + Assert.isNotNull(factorySocket); + Assert.isNotNull(wrappedSocket); + this.source = source; + this.factorySocket = factorySocket; + this.wrappedSocket = wrappedSocket; + } + + public ISocketEventSource getSource() { + return source; + } + + public Socket getFactorySocket() { + return factorySocket; + } + + public boolean isSameFactorySocket(ISocketEvent event) { + AbstractSocketEvent other = (AbstractSocketEvent) event; + return this.getFactorySocket() == other.getFactorySocket(); + } + + public Socket getSocket() { + return wrappedSocket; + } + + protected void setSocket(Socket socket) { + this.wrappedSocket = socket; + } + + public String toString() { + StringBuilder sb = new StringBuilder(getEventName() + "["); //$NON-NLS-1$ + sb.append("source="); //$NON-NLS-1$ + sb.append(source); + sb.append(" socket="); //$NON-NLS-1$ + sb.append(getSocket()); + sb.append(']'); + return sb.toString(); + } + + protected abstract String getEventName(); + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketWrapper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketWrapper.java new file mode 100644 index 0000000000..4110026db0 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/AbstractSocketWrapper.java @@ -0,0 +1,217 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.events.socket; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import org.eclipse.core.runtime.Assert; + +public abstract class AbstractSocketWrapper extends Socket { + + private Socket socket; + + /** + * @throws IOException if some problem + */ + protected void checkCancel() throws IOException { + // default does not check for cancel + } + + public Socket getSocket() { + return socket; + } + + /** + * @param socket for the wrapper + */ + public AbstractSocketWrapper(Socket socket) { + super(); + Assert.isNotNull(socket); + this.socket = socket; + } + + public void bind(SocketAddress bindpoint) throws IOException { + checkCancel(); + socket.bind(bindpoint); + } + + public void close() throws IOException { + socket.close(); + } + + public void connect(SocketAddress endpoint, int timeout) throws IOException { + checkCancel(); + socket.connect(endpoint, timeout); + } + + public void connect(SocketAddress endpoint) throws IOException { + checkCancel(); + socket.connect(endpoint); + } + + public boolean equals(Object obj) { + return socket.equals(obj); + } + + public InetAddress getInetAddress() { + return socket.getInetAddress(); + } + + public InputStream getInputStream() throws IOException { + checkCancel(); + return socket.getInputStream(); + } + + public boolean getKeepAlive() throws SocketException { + return socket.getKeepAlive(); + } + + public InetAddress getLocalAddress() { + return socket.getLocalAddress(); + } + + public int getLocalPort() { + return socket.getLocalPort(); + } + + public SocketAddress getLocalSocketAddress() { + return socket.getLocalSocketAddress(); + } + + public boolean getOOBInline() throws SocketException { + return socket.getOOBInline(); + } + + public OutputStream getOutputStream() throws IOException { + checkCancel(); + return socket.getOutputStream(); + } + + public int getPort() { + return socket.getPort(); + } + + public int getReceiveBufferSize() throws SocketException { + return socket.getReceiveBufferSize(); + } + + public SocketAddress getRemoteSocketAddress() { + return socket.getRemoteSocketAddress(); + } + + public boolean getReuseAddress() throws SocketException { + return socket.getReuseAddress(); + } + + public int getSendBufferSize() throws SocketException { + return socket.getSendBufferSize(); + } + + public int getSoLinger() throws SocketException { + return socket.getSoLinger(); + } + + public int getSoTimeout() throws SocketException { + return socket.getSoTimeout(); + } + + public boolean getTcpNoDelay() throws SocketException { + return socket.getTcpNoDelay(); + } + + public int getTrafficClass() throws SocketException { + return socket.getTrafficClass(); + } + + public int hashCode() { + return socket.hashCode(); + } + + public boolean isBound() { + return socket.isBound(); + } + + public boolean isClosed() { + return socket.isClosed(); + } + + public boolean isConnected() { + return socket.isConnected(); + } + + public boolean isInputShutdown() { + return socket.isInputShutdown(); + } + + public boolean isOutputShutdown() { + return socket.isOutputShutdown(); + } + + public void sendUrgentData(int data) throws IOException { + checkCancel(); + socket.sendUrgentData(data); + } + + public void setKeepAlive(boolean on) throws SocketException { + socket.setKeepAlive(on); + } + + public void setOOBInline(boolean on) throws SocketException { + socket.setOOBInline(on); + } + + public void setReceiveBufferSize(int size) throws SocketException { + socket.setReceiveBufferSize(size); + } + + public void setReuseAddress(boolean on) throws SocketException { + socket.setReuseAddress(on); + } + + public void setSendBufferSize(int size) throws SocketException { + socket.setSendBufferSize(size); + } + + public void setSoLinger(boolean on, int linger) throws SocketException { + socket.setSoLinger(on, linger); + } + + public void setSoTimeout(int timeout) throws SocketException { + socket.setSoTimeout(timeout); + } + + public void setTcpNoDelay(boolean on) throws SocketException { + socket.setTcpNoDelay(on); + } + + public void setTrafficClass(int tc) throws SocketException { + socket.setTrafficClass(tc); + } + + public void shutdownInput() throws IOException { + socket.shutdownInput(); + } + + public void shutdownOutput() throws IOException { + socket.shutdownOutput(); + } + + public String toString() { + return socket.toString(); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketClosedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketClosedEvent.java new file mode 100644 index 0000000000..384410b8e8 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketClosedEvent.java @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.events.socket; + +import java.net.Socket; +import org.eclipse.ecf.filetransfer.events.socket.ISocketClosedEvent; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEventSource; + +public class SocketClosedEvent extends AbstractSocketEvent implements ISocketClosedEvent { + + public SocketClosedEvent(ISocketEventSource source, Socket factorySocket, Socket wrappedSocket) { + super(source, factorySocket, wrappedSocket); + } + + protected String getEventName() { + return "SocketClosedEvent"; //$NON-NLS-1$ + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketConnectedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketConnectedEvent.java new file mode 100644 index 0000000000..cc0c5bb851 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketConnectedEvent.java @@ -0,0 +1,33 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.events.socket; + +import java.net.Socket; +import org.eclipse.ecf.filetransfer.events.socket.ISocketConnectedEvent; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEventSource; + +public class SocketConnectedEvent extends AbstractSocketEvent implements ISocketConnectedEvent { + + public SocketConnectedEvent(ISocketEventSource source, Socket factorySocket, Socket wrappedSocket) { + super(source, factorySocket, wrappedSocket); + } + + protected String getEventName() { + return "SocketConnectedEvent"; //$NON-NLS-1$ + } + + public void setSocket(Socket socket) { + super.setSocket(socket); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketCreatedEvent.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketCreatedEvent.java new file mode 100644 index 0000000000..ba974a780b --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketCreatedEvent.java @@ -0,0 +1,29 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.events.socket; + +import java.net.Socket; +import org.eclipse.ecf.filetransfer.events.socket.ISocketCreatedEvent; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEventSource; + +public class SocketCreatedEvent extends AbstractSocketEvent implements ISocketCreatedEvent { + + public SocketCreatedEvent(ISocketEventSource source, Socket socket) { + super(source, socket, socket); + } + + protected String getEventName() { + return "SocketCreatedEvent"; //$NON-NLS-1$ + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventCreateUtil.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventCreateUtil.java new file mode 100644 index 0000000000..2550e4f054 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventCreateUtil.java @@ -0,0 +1,75 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.events.socket; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import org.eclipse.ecf.core.util.Trace; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEvent; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEventSource; +import org.eclipse.ecf.filetransfer.events.socket.ISocketListener; +import org.eclipse.ecf.filetransfer.events.socketfactory.INonconnectedSocketFactory; +import org.eclipse.ecf.internal.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.DebugOptions; + +public class SocketEventCreateUtil { + + static void fireEvent(final ISocketListener spyListener, ISocketEvent event) { + if (spyListener != null) { + spyListener.handleSocketEvent(event); + } + event.getSource().fireEvent(event); + } + + public static Socket createSocket(final ISocketListener spyListener, final ISocketEventSource socketEventSource, final INonconnectedSocketFactory unconnectedFactory, final InetSocketAddress remoteInetAddress, final InetSocketAddress localInetAddress, int timeout) throws IOException { + Trace.entering(Activator.PLUGIN_ID, DebugOptions.METHODS_ENTERING, SocketEventCreateUtil.class, "createSocket " + remoteInetAddress.toString() + " timeout=" + timeout); //$NON-NLS-1$ //$NON-NLS-2$ + + final Socket factorySocket = unconnectedFactory.createSocket(); + fireEvent(spyListener, new SocketCreatedEvent(socketEventSource, factorySocket)); + try { + Trace.trace(Activator.PLUGIN_ID, "bind(" + localInetAddress.toString() + ")"); //$NON-NLS-1$//$NON-NLS-2$ + factorySocket.bind(localInetAddress); + Trace.trace(Activator.PLUGIN_ID, "connect(" + remoteInetAddress.toString() + ", " + timeout + ")"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + factorySocket.connect(remoteInetAddress, timeout); + Trace.trace(Activator.PLUGIN_ID, "connected"); //$NON-NLS-1$ + } catch (IOException e) { + Trace.catching(Activator.PLUGIN_ID, DebugOptions.EXCEPTIONS_CATCHING, SocketEventCreateUtil.class, "createSocket", e); //$NON-NLS-1$ + fireEvent(spyListener, new SocketClosedEvent(socketEventSource, factorySocket, factorySocket)); + Trace.throwing(Activator.PLUGIN_ID, DebugOptions.EXCEPTIONS_THROWING, SocketEventCreateUtil.class, "createSocket", e); //$NON-NLS-1$ + throw e; + } + final Socket[] wrap = new Socket[1]; + final Socket myWrap = new AbstractSocketWrapper(factorySocket) { + public void close() throws IOException { + try { + Trace.trace(Activator.PLUGIN_ID, "closing socket " + this.toString()); //$NON-NLS-1$ + super.close(); + } finally { + fireEvent(spyListener, new SocketClosedEvent(socketEventSource, factorySocket, wrap[0])); + } + } + }; + SocketConnectedEvent connectedEvent = new SocketConnectedEvent(socketEventSource, factorySocket, myWrap); + fireEvent(spyListener, connectedEvent); + if (connectedEvent.getSocket() == myWrap) { + wrap[0] = myWrap; + } else { + wrap[0] = connectedEvent.getSocket(); + } + + return wrap[0]; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventSource.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventSource.java new file mode 100644 index 0000000000..869564fae9 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/events/socket/SocketEventSource.java @@ -0,0 +1,53 @@ +/**************************************************************************** + * Copyright (c) 2009 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.events.socket; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEvent; +import org.eclipse.ecf.filetransfer.events.socket.ISocketEventSource; +import org.eclipse.ecf.filetransfer.events.socket.ISocketListener; + +public abstract class SocketEventSource implements ISocketEventSource { + + private final List listeners = new ArrayList(); + + public void addListener(ISocketListener l) { + synchronized (listeners) { + listeners.add(l); + } + } + + public void removeListener(ISocketListener l) { + synchronized (listeners) { + listeners.remove(l); + } + } + + public void fireEvent(ISocketEvent event) { + List toNotify = null; + // Copy array + synchronized (listeners) { + toNotify = new ArrayList(listeners); + } + // Notify all in toNotify + for (Iterator i = toNotify.iterator(); i.hasNext();) { + ISocketListener l = (ISocketListener) i.next(); + l.handleSocketEvent(event); + } + + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferID.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferID.java new file mode 100644 index 0000000000..4730f726b3 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferID.java @@ -0,0 +1,101 @@ +/**************************************************************************** + * Copyright (c) 2006, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.identity; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import org.eclipse.core.runtime.Assert; +import org.eclipse.ecf.core.identity.BaseID; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; + +public class FileTransferID extends BaseID implements IFileID { + + private static final long serialVersionUID = 1274308869502156992L; + + URL fileURL; + URI fileURI; + + public FileTransferID(Namespace namespace, URL url) { + super(namespace); + Assert.isNotNull(url, Messages.FileTransferID_Exception_Url_Not_Null); + this.fileURL = url; + } + + /** + * @param namespace namespace + * @param uri uri + * @since 3.2 + */ + public FileTransferID(Namespace namespace, URI uri) { + super(namespace); + Assert.isNotNull(uri, "FileTransferID URI cannot be null"); //$NON-NLS-1$ + this.fileURI = uri; + } + + protected int namespaceCompareTo(BaseID o) { + if (o == null) + return 1; + if (!(o instanceof FileTransferID)) + return 1; + + return (fileURI != null) ? fileURI.compareTo(((FileTransferID) o).fileURI) : fileURL.toExternalForm().compareTo(((FileTransferID) o).toExternalForm()); + } + + protected boolean namespaceEquals(BaseID o) { + if (o == null) + return false; + if (!(o instanceof FileTransferID)) + return false; + + return (fileURI != null) ? fileURI.equals(((FileTransferID) o).fileURI) : fileURL.equals(((FileTransferID) o).fileURL); + } + + protected String namespaceGetName() { + return (fileURI != null) ? fileURI.toASCIIString() : fileURL.toExternalForm(); + } + + protected int namespaceHashCode() { + return (fileURI != null) ? fileURI.hashCode() : this.fileURL.hashCode(); + } + + public String getFilename() { + return getFileNameOnly(); + } + + public URL getURL() throws MalformedURLException { + return (fileURI != null) ? fileURI.toURL() : fileURL; + } + + protected String getFileNameOnly() { + String path = (fileURI != null) ? fileURI.getPath() : fileURL.getPath(); + return (path == null) ? null : path.substring(path.lastIndexOf("/") + 1); //$NON-NLS-1$; + } + + public String toString() { + final StringBuffer b = new StringBuffer("FileTransferID["); //$NON-NLS-1$ + b.append(toExternalForm()); + b.append("]"); //$NON-NLS-1$ + return b.toString(); + } + + /** + * @since 3.2 + */ + public URI getURI() throws URISyntaxException { + return (fileURI != null) ? fileURI : new URI(fileURL.toExternalForm()); + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferNamespace.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferNamespace.java new file mode 100644 index 0000000000..9885b9e079 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/identity/FileTransferNamespace.java @@ -0,0 +1,102 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.identity; + +import java.net.URI; +import java.net.URL; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.core.identity.IDCreateException; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; + +/** + * URL file namespace class. This defines a namespace that understands how to + * create IFileID instances from arbitary URLs + */ +public class FileTransferNamespace extends Namespace { + + private static final long serialVersionUID = 8204058147686930765L; + + public static final String PROTOCOL = Messages.FileTransferNamespace_Namespace_Protocol; + + private String getInitFromExternalForm(Object[] args) { + if (args == null || args.length < 1 || args[0] == null) + return null; + if (args[0] instanceof String) { + String arg = (String) args[0]; + if (arg.startsWith(getScheme() + Namespace.SCHEME_SEPARATOR)) { + int index = arg.indexOf(Namespace.SCHEME_SEPARATOR); + if (index >= arg.length()) + return null; + return arg.substring(index + 1); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.Namespace#createInstance(java.lang.Object[]) + */ + public ID createInstance(Object[] args) throws IDCreateException { + try { + String init = getInitFromExternalForm(args); + if (init != null) + return new FileTransferID(this, new URI(init)); + if (args[0] instanceof URL) + return new FileTransferID(this, (URL) args[0]); + if (args[0] instanceof String) + return new FileTransferID(this, new URI((String) args[0])); + if (args[0] instanceof URI) + return new FileTransferID(this, (URI) args[0]); + } catch (Exception e) { + throw new IDCreateException(Messages.FileTransferNamespace_Exception_Create_Instance, e); + } + throw new IDCreateException(Messages.FileTransferNamespace_Exception_Create_Instance_Failed); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.Namespace#getSupportedSchemes() + */ + public String[] getSupportedSchemes() { + Set result = new HashSet(); + String[] platformSchemes = Activator.getDefault().getPlatformSupportedSchemes(); + result.addAll(Arrays.asList(platformSchemes)); + return (String[]) result.toArray(new String[] {}); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.Namespace#getScheme() + */ + public String getScheme() { + return PROTOCOL; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.Namespace#getSupportedParameterTypesForCreateInstance() + */ + public Class[][] getSupportedParameterTypes() { + return new Class[][] {{URL.class}, {String.class}, {URI.class}}; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractOutgoingFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractOutgoingFileTransfer.java new file mode 100644 index 0000000000..79d57e9da6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractOutgoingFileTransfer.java @@ -0,0 +1,468 @@ +/**************************************************************************** + * Copyright (c) 2004, 2010 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * Cloudsmith, Inc. - additional API and implementation + * Henrich Kraemer - bug 295030, Update Manager doesn't work with SOCKS proxy + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.outgoing; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.FileTransferInfo; +import org.eclipse.ecf.filetransfer.FileTransferJob; +import org.eclipse.ecf.filetransfer.IFileTransferInfo; +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IFileTransferRunnable; +import org.eclipse.ecf.filetransfer.IIncomingFileTransferRequestListener; +import org.eclipse.ecf.filetransfer.IOutgoingFileTransfer; +import org.eclipse.ecf.filetransfer.SendFileTransferException; +import org.eclipse.ecf.filetransfer.UserCancelledException; +import org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferResponseEvent; +import org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferSendDataEvent; +import org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferSendDoneEvent; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.filetransfer.service.ISendFileTransfer; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; +import org.eclipse.ecf.provider.filetransfer.util.ProxySetupHelper; +import org.eclipse.osgi.util.NLS; + +/** + * + */ +public abstract class AbstractOutgoingFileTransfer implements IOutgoingFileTransfer, ISendFileTransfer { + + public static final int DEFAULT_BUF_LENGTH = 4096; + + protected Job job; + + protected URL remoteFileURL; + + protected IFileID remoteFileID; + + protected IFileTransferListener listener; + + protected int buff_length = DEFAULT_BUF_LENGTH; + + protected boolean done = false; + + protected long bytesSent = 0; + + protected InputStream localFileContents; + + protected OutputStream remoteFileContents; + + protected Exception exception; + + protected IFileTransferInfo fileTransferInfo; + + protected Map options = null; + + protected IConnectContext connectContext; + + protected Proxy proxy; + + private final IFileTransferRunnable fileTransferRunnable = new IFileTransferRunnable() { + public IStatus performFileTransfer(IProgressMonitor monitor) { + final byte[] buf = new byte[buff_length]; + final long totalWork = ((fileTransferInfo.getFileSize() == -1) ? 100 : fileTransferInfo.getFileSize()); + double factor = (totalWork > Integer.MAX_VALUE) ? (((double) Integer.MAX_VALUE) / ((double) totalWork)) : 1.0; + int work = (totalWork > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) totalWork; + monitor.beginTask(getRemoteFileURL().toString() + Messages.AbstractOutgoingFileTransfer_Progress_Data, work); + try { + while (!isDone()) { + if (monitor.isCanceled()) + throw new UserCancelledException(Messages.AbstractOutgoingFileTransfer_Exception_User_Cancelled); + final int bytes = localFileContents.read(buf); + if (bytes != -1) { + bytesSent += bytes; + remoteFileContents.write(buf, 0, bytes); + fireTransferSendDataEvent(); + monitor.worked((int) Math.round(factor * bytes)); + } else { + done = true; + } + } + } catch (final Exception e) { + exception = e; + done = true; + } finally { + hardClose(); + monitor.done(); + try { + fireTransferSendDoneEvent(); + } catch (Exception e) { + Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, Messages.AbstractOutgoingFileTransfer_EXCEPTION_IN_FINALLY, e)); + } + } + return getFinalStatus(exception); + } + }; + + FileTransferJob fileTransferJob; + + protected URL getRemoteFileURL() { + return remoteFileURL; + } + + protected void setInputStream(InputStream ins) { + localFileContents = ins; + } + + protected void setOutputStream(OutputStream outs) { + remoteFileContents = outs; + } + + protected IFileTransferInfo getFileTransferInfo() { + return fileTransferInfo; + } + + protected Map getOptions() { + return options; + } + + public AbstractOutgoingFileTransfer() { + // + } + + protected IStatus getFinalStatus(Throwable exception1) { + return Status.OK_STATUS; + } + + protected void hardClose() { + try { + if (remoteFileContents != null) + remoteFileContents.close(); + } catch (final IOException e) { + Activator.getDefault().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, String.format("hardClose url=%s", remoteFileURL), e)); //$NON-NLS-1$ + } + try { + if (localFileContents != null) + localFileContents.close(); + } catch (final IOException e) { + Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, String.format("hardClose url=%s", remoteFileURL), e)); //$NON-NLS-1$ + } + job = null; + remoteFileContents = null; + localFileContents = null; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.core.identity.IIdentifiable#getID() + */ + public ID getID() { + return remoteFileID; + } + + protected void fireTransferSendDoneEvent() { + listener.handleTransferEvent(new IOutgoingFileTransferSendDoneEvent() { + + public IOutgoingFileTransfer getSource() { + return AbstractOutgoingFileTransfer.this; + } + + public Exception getException() { + return AbstractOutgoingFileTransfer.this.getException(); + } + + public String toString() { + final StringBuffer sb = new StringBuffer("IOutgoingFileTransferSendDoneEvent["); //$NON-NLS-1$ + sb.append("bytesSent=").append(bytesSent) //$NON-NLS-1$ + .append(";fileLength=").append(fileTransferInfo.getFileSize()).append(";exception=").append(getException()) //$NON-NLS-1$ //$NON-NLS-2$ + .append("]"); //$NON-NLS-1$ + return sb.toString(); + } + }); + } + + protected void fireTransferSendDataEvent() { + listener.handleTransferEvent(new IOutgoingFileTransferSendDataEvent() { + + public IOutgoingFileTransfer getSource() { + return AbstractOutgoingFileTransfer.this; + } + + public String toString() { + final StringBuffer sb = new StringBuffer("IOutgoingFileTransferSendDataEvent["); //$NON-NLS-1$ + sb.append("bytesSent=").append(bytesSent) //$NON-NLS-1$ + .append(";fileLength=").append(fileTransferInfo.getFileSize()) //$NON-NLS-1$ + .append("]"); //$NON-NLS-1$ + return sb.toString(); + } + }); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IOutgoingFileTransfer#getBytesSent() + */ + public long getBytesSent() { + return bytesSent; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IFileTransfer#cancel() + */ + public void cancel() { + if (job != null) + job.cancel(); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IFileTransfer#getException() + */ + public Exception getException() { + return exception; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransfer#getPercentComplete() + */ + public double getPercentComplete() { + long fileLength = getFileLength(); + if (fileLength == -1 || fileLength == 0) + return fileLength; + return ((double) bytesSent / (double) fileLength); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IFileTransfer#getFileLength() + */ + public long getFileLength() { + return fileTransferInfo.getFileSize(); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.IFileTransfer#isDone() + */ + public boolean isDone() { + return done; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public Object getAdapter(Class adapter) { + if (adapter == null) + return null; + if (adapter.isInstance(this)) { + return this; + } + final IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + return (adapterManager == null) ? null : adapterManager.loadAdapter(this, adapter.getName()); + } + + /** + * Open incoming and outgoing streams associated with this file transfer. + * Subclasses must implement this method to open input and output streams. + * The remoteFileContents and localFileContent + * must be non-null after successful completion of the + * implementation of this method. + * + * @throws SendFileTransferException if some problem + */ + protected abstract void openStreams() throws SendFileTransferException; + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#getOutgoingNamespace() + */ + public Namespace getOutgoingNamespace() { + return IDFactory.getDefault().getNamespaceByName(FileTransferNamespace.PROTOCOL); + } + + public IFileTransferListener getListener() { + return listener; + } + + protected String createJobName() { + return getRemoteFileURL().toString(); + } + + protected void setupAndScheduleJob() { + if (fileTransferJob == null) + fileTransferJob = new FileTransferJob(createJobName()); + fileTransferJob.setFileTransferRunnable(fileTransferRunnable); + fileTransferJob.setFileTransfer(this); + job = fileTransferJob; + job.schedule(); + } + + protected void fireSendStartEvent() { + listener.handleTransferEvent(new IOutgoingFileTransferResponseEvent() { + + public String toString() { + final StringBuffer sb = new StringBuffer("IOutgoingFileTransferResponseEvent["); //$NON-NLS-1$ + sb.append("isdone=").append(done).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append("bytesSent=").append(bytesSent) //$NON-NLS-1$ + .append("]"); //$NON-NLS-1$ + return sb.toString(); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferResponseEvent#requestAccepted() + */ + public boolean requestAccepted() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferEvent#getSource() + */ + public IOutgoingFileTransfer getSource() { + return AbstractOutgoingFileTransfer.this; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.events.IOutgoingFileTransferResponseEvent#setFileTransferJob(org.eclipse.ecf.filetransfer.FileTransferJob) + */ + public void setFileTransferJob(org.eclipse.ecf.filetransfer.FileTransferJob ftj) { + AbstractOutgoingFileTransfer.this.fileTransferJob = ftj; + } + + }); + } + + protected abstract void setupProxy(Proxy proxy); + + protected void setupProxies() { + // If it's been set directly (via ECF API) then this overrides platform settings + if (proxy == null) { + try { + proxy = ProxySetupHelper.getProxy(getRemoteFileURL().toExternalForm()); + } catch (NoClassDefFoundError e) { + // If the proxy API is not available a NoClassDefFoundError will be thrown here. + // If that happens then we just want to continue on. + Activator.logNoProxyWarning(e); + } + } + if (proxy != null) + setupProxy(proxy); + + } + + /** + * Select a single proxy from a set of proxies available for the given host. This implementation + * selects in the following manner: 1) If proxies provided is null or array of 0 length, null + * is returned. If only one proxy is available (array of length 1) then the entry is returned. + * If proxies provided is length greater than 1, then if the type of a proxy in the array matches the given + * protocol (e.g. http, https), then the first matching proxy is returned. If the protocol does + * not match any of the proxies, then the *first* proxy (i.e. proxies[0]) is returned. Subclasses may + * override if desired. + * + * @param protocol the target protocol (e.g. http, https, scp, etc). Will not be null. + * @param proxies the proxies to select from. May be null or array of length 0. + * @return proxy data selected from the proxies provided. + */ + protected IProxyData selectProxyFromProxies(String protocol, IProxyData[] proxies) { + if (proxies == null || proxies.length == 0) + return null; + // If only one proxy is available, then use that + if (proxies.length == 1) + return proxies[0]; + // If more than one proxy is available, then if http/https protocol then look for that + // one...if not found then use first + if (protocol.equalsIgnoreCase("http")) { //$NON-NLS-1$ + for (IProxyData proxie : proxies) { + if (proxie.getType().equals(IProxyData.HTTP_PROXY_TYPE)) { + return proxie; + } + } + } else if (protocol.equalsIgnoreCase("https")) { //$NON-NLS-1$ + for (IProxyData proxie : proxies) { + if (proxie.getType().equals(IProxyData.HTTPS_PROXY_TYPE)) { + return proxie; + } + } + } + // If we haven't found it yet, then return the first one. + return proxies[0]; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#sendOutgoingRequest(org.eclipse.ecf.filetransfer.identity.IFileID, org.eclipse.ecf.filetransfer.IFileTransferInfo, org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map) + */ + public void sendOutgoingRequest(IFileID targetReceiver, IFileTransferInfo localFileToSend, IFileTransferListener transferListener, Map ops) throws SendFileTransferException { + Assert.isNotNull(targetReceiver, Messages.AbstractOutgoingFileTransfer_RemoteFileID_Not_Null); + Assert.isNotNull(transferListener, Messages.AbstractOutgoingFileTransfer_TransferListener_Not_Null); + Assert.isNotNull(localFileToSend, Messages.AbstractOutgoingFileTransfer_EXCEPTION_FILE_TRANSFER_INFO_NOT_NULL); + this.done = false; + this.bytesSent = 0; + this.exception = null; + this.fileTransferInfo = localFileToSend; + this.remoteFileID = targetReceiver; + this.options = ops; + + try { + this.remoteFileURL = targetReceiver.getURL(); + } catch (final MalformedURLException e) { + throw new SendFileTransferException(NLS.bind(Messages.AbstractOutgoingFileTransfer_MalformedURLException, targetReceiver), e); + } + this.listener = transferListener; + setupProxies(); + openStreams(); + fireSendStartEvent(); + setupAndScheduleJob(); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#sendOutgoingRequest(org.eclipse.ecf.filetransfer.identity.IFileID, java.io.File, org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map) + */ + public void sendOutgoingRequest(IFileID targetReceiver, final File localFileToSend, IFileTransferListener transferListener, Map ops) throws SendFileTransferException { + sendOutgoingRequest(targetReceiver, new FileTransferInfo(localFileToSend, null, null), transferListener, ops); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#addListener(org.eclipse.ecf.filetransfer.IIncomingFileTransferRequestListener) + */ + public void addListener(IIncomingFileTransferRequestListener l) { + // Not needed + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#removeListener(org.eclipse.ecf.filetransfer.IIncomingFileTransferRequestListener) + */ + public boolean removeListener(IIncomingFileTransferRequestListener l) { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#setConnectContextForAuthentication(org.eclipse.ecf.core.security.IConnectContext) + */ + public void setConnectContextForAuthentication(IConnectContext connectContext) { + this.connectContext = connectContext; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#setProxy(org.eclipse.ecf.core.util.Proxy) + */ + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractUrlConnectionOutgoingFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractUrlConnectionOutgoingFileTransfer.java new file mode 100644 index 0000000000..f15a2eb425 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/AbstractUrlConnectionOutgoingFileTransfer.java @@ -0,0 +1,146 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * Cloudsmith, Inc. - additional API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.outgoing; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.ProtocolException; +import java.net.URLConnection; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.SendFileTransferException; +import org.eclipse.ecf.filetransfer.service.ISendFileTransfer; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.util.JREProxyHelper; +import org.eclipse.osgi.util.NLS; + +public abstract class AbstractUrlConnectionOutgoingFileTransfer extends AbstractOutgoingFileTransfer implements ISendFileTransfer { + + private static final int OK_RESPONSE_CODE = 200; + + protected URLConnection urlConnection; + + protected long lastModifiedTime = 0L; + + protected int httpVersion = 1; + + protected int responseCode = -1; + + protected String responseMessage = null; + + private JREProxyHelper proxyHelper = null; + + public AbstractUrlConnectionOutgoingFileTransfer() { + super(); + proxyHelper = new JREProxyHelper(); + } + + /** + * Setup and connect. Subclasses should override as appropriate. After calling is complete, + * the urlConnection member variable should be non-null, and ready to have it's + * getInputStream() method called. + * + * @throws IOException if the connection cannot be opened. + */ + protected abstract void connect() throws IOException; + + protected boolean isConnected() { + return (urlConnection != null); + } + + public int getResponseCode() { + if (responseCode != -1) + return responseCode; + if (isHTTP()) { + final String response = urlConnection.getHeaderField(0); + if (response == null) { + responseCode = -1; + httpVersion = 1; + return responseCode; + } + if (response == null || !response.startsWith("HTTP/")) //$NON-NLS-1$ + return -1; + response.trim(); + final int mark = response.indexOf(" ") + 1; //$NON-NLS-1$ + if (mark == 0) + return -1; + if (response.charAt(mark - 2) != '1') + httpVersion = 0; + int last = mark + 3; + if (last > response.length()) + last = response.length(); + responseCode = Integer.parseInt(response.substring(mark, last)); + if (last + 1 <= response.length()) + responseMessage = response.substring(last + 1); + } else { + responseCode = OK_RESPONSE_CODE; + responseMessage = "OK"; //$NON-NLS-1$ + } + + return responseCode; + + } + + private boolean isHTTP() { + final String protocol = getRemoteFileURL().getProtocol(); + if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) //$NON-NLS-1$ //$NON-NLS-2$ + return true; + return false; + } + + /** + * @param proxy2 the ECF proxy to setup + */ + protected void setupProxy(final Proxy proxy2) { + proxyHelper.setupProxy(proxy2); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer#openStreams() + */ + protected void openStreams() throws SendFileTransferException { + try { + File localFile = getFileTransferInfo().getFile(); + // Set input stream from local file + setInputStream(new BufferedInputStream(new FileInputStream(localFile))); + // Then connect + connect(); + // Make PUT request + setOutputStream(urlConnection.getOutputStream()); + } catch (final Exception e) { + throw new SendFileTransferException(NLS.bind(Messages.UrlConnectionOutgoingFileTransfer_EXCEPTION_COULD_NOT_CONNECT, getRemoteFileURL().toString()), e); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer#hardClose() + */ + protected void hardClose() { + super.hardClose(); + int rCode = getResponseCode(); + if (rCode != OK_RESPONSE_CODE) { + exception = new ProtocolException(NLS.bind("{0} {1}", Integer.valueOf(rCode), responseMessage)); //$NON-NLS-1$ + } + urlConnection = null; + if (proxyHelper != null) { + proxyHelper.dispose(); + proxyHelper = null; + } + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/LocalFileOutgoingFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/LocalFileOutgoingFileTransfer.java new file mode 100644 index 0000000000..3f6afa41e5 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/LocalFileOutgoingFileTransfer.java @@ -0,0 +1,71 @@ +/**************************************************************************** + * Copyright (c) 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * Cloudsmith, Inc. - additional API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.outgoing; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.net.URL; +import org.eclipse.core.runtime.Assert; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.IFileTransferInfo; +import org.eclipse.ecf.filetransfer.SendFileTransferException; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.osgi.util.NLS; + +/** + * + */ +public class LocalFileOutgoingFileTransfer extends AbstractOutgoingFileTransfer { + + public LocalFileOutgoingFileTransfer() { + // not needed + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.provider.filetransfer.outgoing.AbstractOutgoingFileTransfer#openStreams() + */ + protected void openStreams() throws SendFileTransferException { + IFileTransferInfo localFileTransferInfo = getFileTransferInfo(); + Assert.isNotNull(localFileTransferInfo); + // Setup input file + File inputFile = localFileTransferInfo.getFile(); + try { + setInputStream(new BufferedInputStream(new FileInputStream(inputFile))); + } catch (Exception e) { + hardClose(); + throw new SendFileTransferException(NLS.bind(Messages.LocalFileOutgoingFileTransfer_EXCEPTION_OPENING_FOR_INPUT, inputFile)); + } + URL url = getRemoteFileURL(); + Assert.isNotNull(url); + try { + File outputFile = new File(url.getPath()); + setOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile))); + } catch (Exception e) { + hardClose(); + throw new SendFileTransferException(NLS.bind(Messages.LocalFileOutgoingFileTransfer_EXCEPTION_OPENING_FOR_OUTPUT, url)); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.provider.filetransfer.outgoing.AbstractOutgoingFileTransfer#setupProxy(org.eclipse.ecf.core.util.Proxy) + */ + protected void setupProxy(Proxy proxy) { + // No proxy for local file system + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapter.java new file mode 100644 index 0000000000..0b0effc568 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapter.java @@ -0,0 +1,165 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.outgoing; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.util.Map; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.IFileTransferInfo; +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IIncomingFileTransferRequestListener; +import org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter; +import org.eclipse.ecf.filetransfer.SendFileTransferException; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.filetransfer.service.ISendFileTransfer; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; +import org.eclipse.osgi.util.NLS; + +/** + * Multi protocol handler for outgoing file transfer. Multiplexes between Apache + * httpclient 3.0.1-based file retriever and the URLConnection-based file + * retriever. + */ +public class MultiProtocolOutgoingAdapter implements ISendFileTransfer { + + IConnectContext connectContext = null; + Proxy proxy = null; + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#getOutgoingNamespace() + */ + public Namespace getOutgoingNamespace() { + return IDFactory.getDefault().getNamespaceByName(FileTransferNamespace.PROTOCOL); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setConnectContextForAuthentication(org.eclipse.ecf.core.security.IConnectContext) + */ + public void setConnectContextForAuthentication(IConnectContext connectContext) { + this.connectContext = connectContext; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setProxy(org.eclipse.ecf.core.util.Proxy) + */ + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } + + public void sendOutgoingRequest(IFileID targetID, File outgoingFile, IFileTransferListener transferListener, Map options) throws SendFileTransferException { + + Assert.isNotNull(targetID); + Assert.isNotNull(outgoingFile); + Assert.isNotNull(transferListener); + + String protocol = null; + try { + protocol = targetID.getURI().getScheme(); + } catch (URISyntaxException e) { + try { + protocol = targetID.getURL().getProtocol(); + } catch (final MalformedURLException e1) { + throw new SendFileTransferException(Messages.AbstractRetrieveFileTransfer_MalformedURLException); + } + } + + ISendFileTransferContainerAdapter fileTransfer = Activator.getDefault().getSendFileTransfer(protocol); + + // If no handler setup for this protocol then throw + if (fileTransfer == null) { + if (protocol.equalsIgnoreCase("file")) { //$NON-NLS-1$ + fileTransfer = new LocalFileOutgoingFileTransfer(); + } + } + + if (fileTransfer == null) { + throw new SendFileTransferException(NLS.bind(Messages.MultiProtocolOutgoingAdapter_EXCEPTION_NO_PROTOCOL_HANDER, targetID)); + } + + fileTransfer.setConnectContextForAuthentication(connectContext); + fileTransfer.setProxy(proxy); + fileTransfer.sendOutgoingRequest(targetID, outgoingFile, transferListener, options); + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#addListener(org.eclipse.ecf.filetransfer.IIncomingFileTransferRequestListener) + */ + public void addListener(IIncomingFileTransferRequestListener listener) { + // We don't have any listeners + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#removeListener(org.eclipse.ecf.filetransfer.IIncomingFileTransferRequestListener) + */ + public boolean removeListener(IIncomingFileTransferRequestListener listener) { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter#sendOutgoingRequest(org.eclipse.ecf.filetransfer.identity.IFileID, org.eclipse.ecf.filetransfer.IFileTransferInfo, org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map) + */ + public void sendOutgoingRequest(IFileID targetID, IFileTransferInfo localFileToSend, IFileTransferListener transferListener, Map options) throws SendFileTransferException { + Assert.isNotNull(targetID); + Assert.isNotNull(localFileToSend); + Assert.isNotNull(transferListener); + + String protocol = null; + try { + protocol = targetID.getURI().getScheme(); + } catch (URISyntaxException e) { + try { + protocol = targetID.getURL().getProtocol(); + } catch (final MalformedURLException e1) { + throw new SendFileTransferException(Messages.AbstractRetrieveFileTransfer_MalformedURLException); + } + } + + ISendFileTransferContainerAdapter fileTransfer = Activator.getDefault().getSendFileTransfer(protocol); + + // If no handler setup for this protocol then throw + if (fileTransfer == null) { + throw new SendFileTransferException(NLS.bind(Messages.MultiProtocolOutgoingAdapter_EXCEPTION_NO_PROTOCOL_HANDER, targetID)); + } + + fileTransfer.setConnectContextForAuthentication(connectContext); + fileTransfer.setProxy(proxy); + fileTransfer.sendOutgoingRequest(targetID, localFileToSend, transferListener, options); + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + if (adapter == null) + return null; + final IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + if (adapterManager == null) + return null; + return (T) adapterManager.loadAdapter(this, adapter.getName()); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapterFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapterFactory.java new file mode 100644 index 0000000000..1b49ce176c --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/outgoing/MultiProtocolOutgoingAdapterFactory.java @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.outgoing; + +import org.eclipse.ecf.core.AbstractContainerAdapterFactory; +import org.eclipse.ecf.core.IContainer; +import org.eclipse.ecf.filetransfer.ISendFileTransferContainerAdapter; + +/** + * + */ +public class MultiProtocolOutgoingAdapterFactory extends AbstractContainerAdapterFactory { + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.sharedobject.AbstractSharedObjectContainerAdapterFactory#getAdapterList() + */ + public Class[] getAdapterList() { + return new Class[] {ISendFileTransferContainerAdapter.class}; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.AbstractContainerAdapterFactory#getContainerAdapter(org.eclipse.ecf.core.IContainer, + * java.lang.Class) + */ + protected Object getContainerAdapter(IContainer container, Class adapterType) { + if (adapterType.equals(ISendFileTransferContainerAdapter.class)) { + return new MultiProtocolOutgoingAdapter(); + } + return null; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/AbstractRetrieveFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/AbstractRetrieveFileTransfer.java new file mode 100644 index 0000000000..e620f52f96 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/AbstractRetrieveFileTransfer.java @@ -0,0 +1,991 @@ +/**************************************************************************** + * Copyright (c) 2004, 2010 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * Benjamin Cabe - bug 220258 + * Henrich Kraemer - bug 295030, Update Manager doesn't work with SOCKS proxy + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.retrieve; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.DecimalFormat; +import java.util.Date; +import java.util.Map; +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.ecf.core.identity.ID; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.FileTransferJob; +import org.eclipse.ecf.filetransfer.IFileRangeSpecification; +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IFileTransferPausable; +import org.eclipse.ecf.filetransfer.IFileTransferRunnable; +import org.eclipse.ecf.filetransfer.IIncomingFileTransfer; +import org.eclipse.ecf.filetransfer.IRetrieveFileTransferOptions; +import org.eclipse.ecf.filetransfer.IncomingFileTransferException; +import org.eclipse.ecf.filetransfer.UserCancelledException; +import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveDataEvent; +import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveDoneEvent; +import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceivePausedEvent; +import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveResumedEvent; +import org.eclipse.ecf.filetransfer.events.IIncomingFileTransferReceiveStartEvent; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransfer; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; +import org.eclipse.ecf.provider.filetransfer.util.PollingInputStream; +import org.eclipse.ecf.provider.filetransfer.util.ProxySetupHelper; +import org.eclipse.ecf.provider.filetransfer.util.TimeoutInputStream; +import org.eclipse.osgi.util.NLS; + +public abstract class AbstractRetrieveFileTransfer implements IIncomingFileTransfer, IRetrieveFileTransfer, IFileTransferPausable { + + public static final int DEFAULT_BUF_LENGTH = 4096; + + protected static final int POLLING_RETRY_ATTEMPTS = Integer.parseInt(System.getProperty("org.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts", "30")); //$NON-NLS-1$ //$NON-NLS-2$;; + + protected static final int TIMEOUT_INPUTSTREAM_BUFFER_SIZE = 8192; + + protected static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("org.eclipse.ecf.provider.filetransfer.retrieve.readTimeout", "1000")); //$NON-NLS-1$ //$NON-NLS-2$; + + protected static final int CLOSE_TIMEOUT = Integer.parseInt(System.getProperty("org.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout", "1000")); //$NON-NLS-1$ //$NON-NLS-2$; + + private static final String readTimeoutMessage = "Timeout while reading input stream.\n" + //$NON-NLS-1$ + "The following system properties can be used to adjust the readTimeout, retryAttempts, and closeTimeout\n" + //$NON-NLS-1$ + "\torg.eclipse.ecf.provider.filetransfer.retrieve.readTimeout=\n" + //$NON-NLS-1$ + "\torg.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts=\n" + //$NON-NLS-1$ + "\torg.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout=\n"; //$NON-NLS-1$ + + private static final String closeTimeoutMessage = "Timeout while closing input stream.\n" + //$NON-NLS-1$ + "The following system properties can be used to adjust the readTimeout, retryAttempts, and closeTimeout\n" + //$NON-NLS-1$ + "\torg.eclipse.ecf.provider.filetransfer.retrieve.readTimeout=\n" + //$NON-NLS-1$ + "\torg.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts=\n" + //$NON-NLS-1$ + "\torg.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout=\n"; //$NON-NLS-1$ + + protected Object jobLock = new Object(); + protected Job job; + + protected URL remoteFileURL; + + protected IFileID remoteFileID; + + protected IFileTransferListener listener; + + protected int buff_length = DEFAULT_BUF_LENGTH; + + protected boolean done = false; + + protected volatile long bytesReceived = 0; + + protected InputStream remoteFileContents; + + protected OutputStream localFileContents; + + protected boolean closeOutputStream = true; + + protected Exception exception; + + protected long fileLength = -1; + + protected long lastModifiedTime = 0L; + + protected Map options = null; + + protected boolean paused = false; + + protected IFileRangeSpecification rangeSpecification = null; + + protected Proxy proxy; + + protected IConnectContext connectContext; + + protected long transferStartTime; + + protected double downloadRateBytesPerSecond = 0L; + + /** + * @since 3.1 + */ + protected Map responseHeaders; + + public AbstractRetrieveFileTransfer() { + // + } + + protected InputStream wrapTransferReadInputStream(InputStream inputStream, IProgressMonitor monitor) { + return new PollingInputStream(inputStream, getRetryAttempts(), monitor, readTimeoutMessage, closeTimeoutMessage); + } + + private int getRetryAttempts() { + int result = POLLING_RETRY_ATTEMPTS; + Map localOptions = getOptions(); + if (localOptions != null) { + // See if the property is present, if so set + Object o = localOptions.get("org.eclipse.ecf.provider.filetransfer.retrieve.retryAttempts"); //$NON-NLS-1$ + if (o != null) { + if (o instanceof Integer) { + result = ((Integer) o).intValue(); + } else if (o instanceof String) { + result = Integer.parseInt(((String) o)); + } + } + } + return result; + } + + private IFileTransferRunnable fileTransferRunnable = new IFileTransferRunnable() { + public IStatus performFileTransfer(IProgressMonitor monitor) { + transferStartTime = System.currentTimeMillis(); + final byte[] buf = new byte[buff_length]; + final long totalWork = ((fileLength == -1) ? 100 : fileLength); + double factor = (totalWork > Integer.MAX_VALUE) ? (((double) Integer.MAX_VALUE) / ((double) totalWork)) : 1.0; + int work = (totalWork > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) totalWork; + monitor.beginTask(getRemoteFileURL().toString() + Messages.AbstractRetrieveFileTransfer_Progress_Data, work); + InputStream readInputStream = null; + try { + // We will test for remoteFileContents is null...if it is null then we can't continue. + // See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=425868 + if (remoteFileContents == null) + throw new IOException("input stream cannot be null"); //$NON-NLS-1$ + // Create read input stream + readInputStream = wrapTransferReadInputStream(remoteFileContents, monitor); + while (!isDone() && !isPaused()) { + try { + final int bytes = readInputStream.read(buf); + handleReceivedData(buf, bytes, factor, monitor); + } catch (OperationCanceledException e) { + throw new UserCancelledException(Messages.AbstractRetrieveFileTransfer_Exception_User_Cancelled); + } + } + } catch (final Exception e) { + if (!isDone()) { + setDoneException(e); + } + } finally { + try { + if (readInputStream != null) + readInputStream.close(); + } catch (final IOException e) { + Activator a = Activator.getDefault(); + if (a != null) + a.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, "hardClose", e)); //$NON-NLS-1$ + } + hardClose(); + monitor.done(); + try { + if (isPaused()) + fireTransferReceivePausedEvent(); + else + fireTransferReceiveDoneEvent(); + } catch (Exception e) { + // simply log + Activator a = Activator.getDefault(); + if (a != null) + a.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, Messages.AbstractRetrieveFileTransfer_EXCEPTION_IN_FINALLY, e)); + } + } + return getFinalStatus(exception); + } + + }; + + protected URL getRemoteFileURL() { + return remoteFileURL; + } + + protected int getSocketReadTimeout() { + int result = READ_TIMEOUT; + Map localOptions = getOptions(); + if (localOptions != null) { + // See if the connect timeout option is present, if so set + Object o = localOptions.get(IRetrieveFileTransferOptions.READ_TIMEOUT); + if (o != null) { + if (o instanceof Integer) { + result = ((Integer) o).intValue(); + } else if (o instanceof String) { + result = Integer.parseInt(((String) o)); + } + return result; + } + o = localOptions.get("org.eclipse.ecf.provider.filetransfer.httpclient.retrieve.readTimeout"); //$NON-NLS-1$ + if (o != null) { + if (o instanceof Integer) { + result = ((Integer) o).intValue(); + } else if (o instanceof String) { + result = Integer.parseInt(((String) o)); + } + } + } + return result; + } + + protected int getSocketCloseTimeout() { + int result = CLOSE_TIMEOUT; + Map localOptions = getOptions(); + if (localOptions != null) { + // See if the property is present, if so set + Object o = localOptions.get("org.eclipse.ecf.provider.filetransfer.retrieve.closeTimeout"); //$NON-NLS-1$ + if (o != null) { + if (o instanceof Integer) { + result = ((Integer) o).intValue(); + } else if (o instanceof String) { + result = Integer.parseInt(((String) o)); + } + } + } + return result; + } + + protected void setInputStream(InputStream ins) { + remoteFileContents = new TimeoutInputStream(ins, TIMEOUT_INPUTSTREAM_BUFFER_SIZE, getSocketReadTimeout(), getSocketCloseTimeout()); + } + + protected void setOutputStream(OutputStream outs) { + localFileContents = outs; + } + + protected void setCloseOutputStream(boolean close) { + closeOutputStream = close; + } + + protected void setFileLength(long length) { + fileLength = length; + } + + protected void setLastModifiedTime(long timestamp) { + lastModifiedTime = timestamp; + } + + protected Map getOptions() { + return options; + } + + protected synchronized void handleReceivedData(byte[] buf, int bytes, double factor, IProgressMonitor monitor) throws IOException { + if (bytes != -1) { + bytesReceived += bytes; + localFileContents.write(buf, 0, bytes); + downloadRateBytesPerSecond = (bytesReceived / ((System.currentTimeMillis() + 1 - transferStartTime) / 1000.0)); + monitor.setTaskName(createJobName() + Messages.AbstractRetrieveFileTransfer_Progress_Data + NLS.bind(Messages.AbstractRetrieveFileTransfer_InfoTransferRate, toHumanReadableBytes(downloadRateBytesPerSecond))); + monitor.worked((int) Math.round(factor * bytes)); + fireTransferReceiveDataEvent(); + } else + setDone(true); + } + + public static String toHumanReadableBytes(double size) { + double convertedSize; + String unit; + + if (size / (1024 * 1024 * 1024) >= 1) { + convertedSize = size / (1024 * 1024 * 1024); + unit = Messages.AbstractRetrieveFileTransfer_SizeUnitGB; + } else if (size / (1024 * 1024) >= 1) { + convertedSize = size / (1024 * 1024); + unit = Messages.AbstractRetrieveFileTransfer_SizeUnitMB; + } else if (size / 1024 >= 1) { + convertedSize = size / 1024; + unit = Messages.AbstractRetrieveFileTransfer_SizeUnitKB; + } else { + convertedSize = size; + unit = Messages.AbstractRetrieveFileTransfer_SizeUnitBytes; + } + + DecimalFormat df = new DecimalFormat(NLS.bind(Messages.AbstractRetrieveFileTransfer_TransferRateFormat, unit)); + return df.format(convertedSize); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.identity.IIdentifiable#getID() + */ + public ID getID() { + return remoteFileID; + } + + protected IStatus getFinalStatus(Throwable exception1) { + return Status.OK_STATUS; + } + + protected void hardClose() { + try { + if (remoteFileContents != null) + remoteFileContents.close(); + } catch (final IOException e) { + Activator.getDefault().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, String.format("hardClose url=%s", remoteFileURL), e)); //$NON-NLS-1$ + } + try { + if (localFileContents != null && closeOutputStream) + localFileContents.close(); + } catch (final IOException e) { + Activator.getDefault().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, String.format("hardClose url=%s", remoteFileURL), e)); //$NON-NLS-1$ + } + // leave job intact to ensure only one done event is fired + remoteFileContents = null; + localFileContents = null; + } + + protected void fireTransferReceivePausedEvent() { + listener.handleTransferEvent(new IIncomingFileTransferReceivePausedEvent() { + + public IIncomingFileTransfer getSource() { + return AbstractRetrieveFileTransfer.this; + } + + public String toString() { + final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceivePausedEvent["); //$NON-NLS-1$ + sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$ + .append(";fileLength=").append(fileLength).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ + return sb.toString(); + } + }); + } + + protected void fireTransferReceiveDoneEvent() { + listener.handleTransferEvent(new IIncomingFileTransferReceiveDoneEvent() { + + public IIncomingFileTransfer getSource() { + return AbstractRetrieveFileTransfer.this; + } + + public Exception getException() { + return AbstractRetrieveFileTransfer.this.getException(); + } + + public String toString() { + final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveDoneEvent["); //$NON-NLS-1$ + sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$ + .append(";fileLength=").append(fileLength).append(";exception=").append(getException()) //$NON-NLS-1$ //$NON-NLS-2$ + .append("]"); //$NON-NLS-1$ + return sb.toString(); + } + }); + } + + protected void fireTransferReceiveDataEvent() { + listener.handleTransferEvent(new IIncomingFileTransferReceiveDataEvent() { + public IIncomingFileTransfer getSource() { + return AbstractRetrieveFileTransfer.this; + } + + public String toString() { + final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveDataEvent["); //$NON-NLS-1$ + sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$ + .append(";fileLength=").append(fileLength) //$NON-NLS-1$ + .append("]"); //$NON-NLS-1$ + return sb.toString(); + } + }); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter# + * setConnectContextForAuthentication + * (org.eclipse.ecf.core.security.IConnectContext) + */ + public void setConnectContextForAuthentication(IConnectContext connectContext) { + this.connectContext = connectContext; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setProxy + * (org.eclipse.ecf.core.util.Proxy) + */ + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getBytesReceived() + */ + public long getBytesReceived() { + return bytesReceived; + } + + /** + * @return UserCancelledException if some user cancellation + * @since 3.0 + */ + protected UserCancelledException newUserCancelledException() { + return new UserCancelledException(Messages.AbstractRetrieveFileTransfer_Exception_User_Cancelled); + } + + protected synchronized void resetDoneAndException() { + setDone(false); + this.exception = null; + } + + protected synchronized void setDone(boolean done) { + this.done = done; + } + + protected synchronized void setDoneException(Exception e) { + this.done = true; + this.exception = e; + } + + protected synchronized boolean isCanceled() { + return done && exception instanceof UserCancelledException; + } + + protected void setDoneCanceled() { + setDoneCanceled(newUserCancelledException()); + } + + protected synchronized void setDoneCanceled(Exception e) { + this.done = true; + if (e instanceof UserCancelledException) { + exception = e; + } else { + exception = newUserCancelledException(); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransfer#cancel() + */ + public void cancel() { + if (isPaused()) { + setDoneCanceled(); + fireTransferReceiveDoneEvent(); + return; + } + synchronized (jobLock) { + if (job != null) + job.cancel(); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransfer#getException() + */ + public synchronized Exception getException() { + return exception; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransfer#getPercentComplete() + */ + public double getPercentComplete() { + if (fileLength == -1 || fileLength == 0) + return fileLength; + return ((double) bytesReceived / (double) fileLength); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransfer#getFileLength() + */ + public long getFileLength() { + return fileLength; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer + * #getRemoteLastModified() + */ + public Date getRemoteLastModified() { + return lastModifiedTime == 0L ? null : new Date(lastModifiedTime); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransfer#isDone() + */ + public synchronized boolean isDone() { + return done; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + if (adapter == null) + return null; + if (adapter.isInstance(this)) { + return adapter.cast(this); + } + final IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + return (T) ((adapterManager == null) ? null : adapterManager.loadAdapter(this, adapter.getName())); + } + + /** + * Open incoming and outgoing streams associated with this file transfer. + * Subclasses must implement this method to open input and output streams. + * The remoteFileContents and localFileContent + * must be non-null after successful completion of the + * implementation of this method. + * + * @throws IncomingFileTransferException if some problem + */ + protected abstract void openStreams() throws IncomingFileTransferException; + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter# + * sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, + * org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map) + */ + public void sendRetrieveRequest(final IFileID remoteFileID1, IFileTransferListener transferListener, Map options1) throws IncomingFileTransferException { + sendRetrieveRequest(remoteFileID1, null, transferListener, options1); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter# + * getRetrieveNamespace() + */ + public Namespace getRetrieveNamespace() { + return IDFactory.getDefault().getNamespaceByName(FileTransferNamespace.PROTOCOL); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferPausable#isPaused() + */ + public boolean isPaused() { + return paused; + } + + /** + * Subclass overridable version of {@link #pause()}. Subclasses must provide + * an implementation of this method to support {@link IFileTransferPausable} + * . + * + * @return true if the pause is successful. false otherwise. + */ + protected abstract boolean doPause(); + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferPausable#pause() + */ + public boolean pause() { + return doPause(); + } + + /** + * Subclass overridable version of {@link #resume()}. Subclasses must + * provide an implementation of this method to support + * {@link IFileTransferPausable}. + * + * @return true if the resume is successful. false otherwise. + */ + protected abstract boolean doResume(); + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IFileTransferPausable#resume() + */ + public boolean resume() { + return doResume(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getListener() + */ + public IFileTransferListener getListener() { + return listener; + } + + protected String createRangeName() { + if (rangeSpecification == null) + return ""; //$NON-NLS-1$ + return "[" + rangeSpecification.getStartPosition() + "," + rangeSpecification.getEndPosition() + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + protected String createJobName() { + return getRemoteFileURL().toString() + createRangeName(); + } + + protected void setupAndScheduleJob(FileTransferJob fileTransferJob) { + if (fileTransferJob == null) { + // Create our own + fileTransferJob = new FileTransferJob(createJobName()); + } + // Now set to our runnable + fileTransferJob.setFileTransferRunnable(fileTransferRunnable); + fileTransferJob.setFileTransfer(this); + if (isDone()) { + return; + } + synchronized (jobLock) { + job = fileTransferJob; + job.schedule(); + } + } + + protected void fireReceiveStartEvent() { + listener.handleTransferEvent(new IIncomingFileTransferReceiveStartEvent() { + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.events. + * IIncomingFileTransferEvent#getFileID() + */ + public IIncomingFileTransfer getSource() { + return AbstractRetrieveFileTransfer.this; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.events. + * IIncomingFileTransferReceiveStartEvent#getFileID() + */ + public IFileID getFileID() { + return remoteFileID; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.events. + * IIncomingFileTransferReceiveStartEvent + * #receive(java.io.File) + */ + public IIncomingFileTransfer receive(File localFileToSave) throws IOException { + return receive(localFileToSave, null); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.events. + * IIncomingFileTransferReceiveStartEvent + * #receive(java.io.File, + * org.eclipse.ecf.filetransfer.FileTransferJob) + */ + public IIncomingFileTransfer receive(File localFileToSave, FileTransferJob fileTransferJob) throws IOException { + setOutputStream(new BufferedOutputStream(new FileOutputStream(localFileToSave))); + setupAndScheduleJob(fileTransferJob); + return AbstractRetrieveFileTransfer.this; + } + + /** + * @param streamToStore + * @return incoming file transfer instance. + * @throws IOException + * not thrown in this implementation. + */ + public IIncomingFileTransfer receive(OutputStream streamToStore) throws IOException { + return receive(streamToStore, null); + } + + /** + * @throws IOException + * not actually thrown by this implementation. + */ + public IIncomingFileTransfer receive(OutputStream streamToStore, FileTransferJob fileTransferJob) throws IOException { + setOutputStream(streamToStore); + setCloseOutputStream(false); + setupAndScheduleJob(fileTransferJob); + return AbstractRetrieveFileTransfer.this; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.events. + * IIncomingFileTransferReceiveStartEvent#cancel() + */ + public void cancel() { + AbstractRetrieveFileTransfer.this.cancel(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveStartEvent["); //$NON-NLS-1$ + sb.append("isdone=").append(isDone()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$ + .append("]"); //$NON-NLS-1$ + return sb.toString(); + } + + public Map getResponseHeaders() { + return responseHeaders; + } + + }); + } + + protected void fireReceiveResumedEvent() { + listener.handleTransferEvent(new IIncomingFileTransferReceiveResumedEvent() { + + public IIncomingFileTransfer getSource() { + return AbstractRetrieveFileTransfer.this; + } + + public IFileID getFileID() { + return remoteFileID; + } + + public IIncomingFileTransfer receive(File localFileToSave, boolean append) throws IOException { + return receive(localFileToSave, null, append); + } + + public IIncomingFileTransfer receive(File localFileToSave, FileTransferJob fileTransferJob, boolean append) throws IOException { + setOutputStream(new BufferedOutputStream(new FileOutputStream(localFileToSave.getName(), append))); + setupAndScheduleJob(fileTransferJob); + return AbstractRetrieveFileTransfer.this; + } + + /** + * @param streamToStore + * @return incoming file transfer instance. + * @throws IOException + * not thrown in this implementation. + */ + public IIncomingFileTransfer receive(OutputStream streamToStore) throws IOException { + return receive(streamToStore, null); + } + + /** + * @throws IOException + * not actually thrown by this implementation. + */ + public IIncomingFileTransfer receive(OutputStream streamToStore, FileTransferJob fileTransferJob) throws IOException { + setOutputStream(streamToStore); + setCloseOutputStream(false); + setupAndScheduleJob(fileTransferJob); + return AbstractRetrieveFileTransfer.this; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.events. + * IIncomingFileTransferReceiveStartEvent#cancel() + */ + public void cancel() { + hardClose(); + } + + public String toString() { + final StringBuffer sb = new StringBuffer("IIncomingFileTransferReceiveResumedEvent["); //$NON-NLS-1$ + sb.append("isdone=").append(isDone()).append(";"); //$NON-NLS-1$ //$NON-NLS-2$ + sb.append("bytesReceived=").append(bytesReceived) //$NON-NLS-1$ + .append("]"); //$NON-NLS-1$ + return sb.toString(); + } + + public Map getResponseHeaders() { + return responseHeaders; + } + + }); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getFileRangeSpecification + * () + */ + public IFileRangeSpecification getFileRangeSpecification() { + return rangeSpecification; + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter# + * sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, + * org.eclipse.ecf.filetransfer.IFileRangeSpecification, + * org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map) + */ + /** + * @throws IncomingFileTransferException if some problem sending retrieve request + */ + public void sendRetrieveRequest(IFileID rFileID, IFileRangeSpecification rangeSpec, IFileTransferListener transferListener, Map ops) throws IncomingFileTransferException { + Assert.isNotNull(rFileID, Messages.AbstractRetrieveFileTransfer_RemoteFileID_Not_Null); + Assert.isNotNull(transferListener, Messages.AbstractRetrieveFileTransfer_TransferListener_Not_Null); + synchronized (jobLock) { + this.job = null; + } + this.remoteFileURL = null; + this.remoteFileID = rFileID; + this.listener = transferListener; + this.remoteFileContents = null; + this.localFileContents = null; + this.closeOutputStream = true; + resetDoneAndException(); + this.bytesReceived = 0; + this.fileLength = -1; + this.options = ops; + this.paused = false; + this.rangeSpecification = rangeSpec; + + try { + this.remoteFileURL = rFileID.getURL(); + } catch (final MalformedURLException e) { + setDoneException(e); + fireTransferReceiveDoneEvent(); + return; + } + try { + setupProxies(); + openStreams(); + } catch (final IncomingFileTransferException e) { + setDoneException(e); + fireTransferReceiveDoneEvent(); + } + } + + /** + * Setup ECF proxy. Subclasses must override this method to do appropriate + * proxy setup. This method will be called from within + * {@link #sendRetrieveRequest(IFileID, IFileTransferListener, Map)} and + * {@link #sendRetrieveRequest(IFileID, IFileRangeSpecification, IFileTransferListener, Map)} + * , prior to the actual call to {@link #openStreams()}. + * + * @param proxy + * the proxy to be setup. Will not be null. + */ + protected abstract void setupProxy(Proxy proxy); + + /** + * Select a single proxy from a set of proxies available for the given host. + * This implementation selects in the following manner: 1) If proxies + * provided is null or array of 0 length, null is returned. If only one + * proxy is available (array of length 1) then the entry is returned. If + * proxies provided is length greater than 1, then if the type of a proxy in the array + * matches the given protocol (e.g. http, https), then the first matching + * proxy is returned. If the protocol does not match any of the proxies, + * then the *first* proxy (i.e. proxies[0]) is returned. Subclasses may + * override if desired. + * + * @param protocol + * the target protocol (e.g. http, https, scp, etc). Will not be + * null. + * @param proxies + * the proxies to select from. May be null or array + * of length 0. + * @return proxy data selected from the proxies provided. + */ + protected IProxyData selectProxyFromProxies(String protocol, IProxyData[] proxies) { + if (proxies == null || proxies.length == 0) + return null; + // If only one proxy is available, then use that + if (proxies.length == 1) + return proxies[0]; + // If more than one proxy is available, then if http/https protocol then + // look for that + // one...if not found then use first + if (protocol.equalsIgnoreCase("http")) { //$NON-NLS-1$ + for (IProxyData proxie : proxies) { + if (proxie.getType().equals(IProxyData.HTTP_PROXY_TYPE)) { + return proxie; + } + } + } else if (protocol.equalsIgnoreCase("https")) { //$NON-NLS-1$ + for (IProxyData proxie : proxies) { + if (proxie.getType().equals(IProxyData.HTTPS_PROXY_TYPE)) { + return proxie; + } + } + } + // If we haven't found it yet, then return the first one. + return proxies[0]; + } + + protected void setupProxies() { + // If it's been set directly (via ECF API) then this overrides platform + // settings + if (proxy == null) { + try { + proxy = ProxySetupHelper.getProxy(getRemoteFileURL().toExternalForm()); + } catch (NoClassDefFoundError e) { + // If the proxy API is not available a NoClassDefFoundError will be thrown here. + // If that happens then we just want to continue on. + Activator.logNoProxyWarning(e); + } + } + if (proxy != null) + setupProxy(proxy); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.filetransfer.IIncomingFileTransfer#getRemoteFileName() + */ + public String getRemoteFileName() { + String pathStr = getRemoteFileURL().getPath(); + if (pathStr.length() > 0) { + IPath path = Path.fromPortableString(pathStr); + if (path.segmentCount() > 0) + return path.lastSegment(); + } + return null; + } + + protected boolean targetHasGzSuffix(String target) { + if (target == null) + return false; + if (target.endsWith(".gz")) //$NON-NLS-1$ + return true; + return false; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/HttpHelper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/HttpHelper.java new file mode 100644 index 0000000000..04c217ffd7 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/HttpHelper.java @@ -0,0 +1,41 @@ +/**************************************************************************** + * Copyright (c) 2008 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.retrieve; + +import java.util.StringTokenizer; + +/** + * + */ +public class HttpHelper { + + public static final String CONTENT_DISPOSITION_HEADER = "Content-Disposition"; //$NON-NLS-1$ + + public static String getRemoteFileNameFromContentDispositionHeader(String headerValue) { + if (headerValue != null) { + StringTokenizer tokens = new StringTokenizer(headerValue, " \t\n\r\f=;,"); //$NON-NLS-1$ + while (tokens.hasMoreTokens()) { + String token = tokens.nextToken(); + if (token.equals("filename") && tokens.hasMoreTokens()) { //$NON-NLS-1$ + // Expect next token to be the filename + String fileName = tokens.nextToken(); + if (fileName.startsWith("\"") && fileName.endsWith("\"")) //$NON-NLS-1$ //$NON-NLS-2$ + fileName = fileName.substring(1, fileName.length() - 1); + return fileName; + } + } + } + return null; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapter.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapter.java new file mode 100644 index 0000000000..8bf777f990 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapter.java @@ -0,0 +1,164 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.retrieve; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.util.Map; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdapterManager; +import org.eclipse.ecf.core.identity.IDFactory; +import org.eclipse.ecf.core.identity.Namespace; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.IFileRangeSpecification; +import org.eclipse.ecf.filetransfer.IFileTransferListener; +import org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter; +import org.eclipse.ecf.filetransfer.IncomingFileTransferException; +import org.eclipse.ecf.filetransfer.identity.IFileID; +import org.eclipse.ecf.filetransfer.service.IRetrieveFileTransfer; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.identity.FileTransferNamespace; + +/** + * Multi protocol handler for retrieve file transfer. Multiplexes between Apache + * httpclient 3.0.1-based file retriever and the URLConnection-based file + * retriever. + */ +public class MultiProtocolRetrieveAdapter implements IRetrieveFileTransfer { + + IConnectContext connectContext = null; + Proxy proxy = null; + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#getRetrieveNamespace() + */ + public Namespace getRetrieveNamespace() { + return IDFactory.getDefault().getNamespaceByName(FileTransferNamespace.PROTOCOL); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setConnectContextForAuthentication(org.eclipse.ecf.core.security.IConnectContext) + */ + public void setConnectContextForAuthentication(IConnectContext connectContext) { + this.connectContext = connectContext; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#setProxy(org.eclipse.ecf.core.util.Proxy) + */ + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, + * org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map) + */ + public void sendRetrieveRequest(IFileID remoteFileID, IFileTransferListener transferListener, Map options) throws IncomingFileTransferException { + + Assert.isNotNull(remoteFileID); + Assert.isNotNull(transferListener); + + String protocol = null; + try { + protocol = remoteFileID.getURI().getScheme(); + } catch (URISyntaxException e) { + try { + protocol = remoteFileID.getURL().getProtocol(); + } catch (final MalformedURLException e1) { + throw new IncomingFileTransferException(Messages.AbstractRetrieveFileTransfer_MalformedURLException); + } + } + + IRetrieveFileTransferContainerAdapter fileTransfer = Activator.getDefault().getFileTransfer(protocol); + + // We will default to JRE-provided file transfer if nothing else + // available + // for given protocol + if (fileTransfer == null) + fileTransfer = new UrlConnectionRetrieveFileTransfer(); + + // Set connect context + fileTransfer.setConnectContextForAuthentication(connectContext); + // Set Proxy + fileTransfer.setProxy(proxy); + + // send request using given file transfer protocol + fileTransfer.sendRetrieveRequest(remoteFileID, transferListener, options); + + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter#sendRetrieveRequest(org.eclipse.ecf.filetransfer.identity.IFileID, + * org.eclipse.ecf.filetransfer.IFileRangeSpecification, + * org.eclipse.ecf.filetransfer.IFileTransferListener, java.util.Map) + */ + public void sendRetrieveRequest(IFileID remoteFileID, IFileRangeSpecification rangeSpecification, IFileTransferListener transferListener, Map options) throws IncomingFileTransferException { + Assert.isNotNull(remoteFileID); + Assert.isNotNull(transferListener); + + String protocol = null; + try { + protocol = remoteFileID.getURI().getScheme(); + } catch (URISyntaxException e) { + try { + protocol = remoteFileID.getURL().getProtocol(); + } catch (final MalformedURLException e1) { + throw new IncomingFileTransferException(Messages.AbstractRetrieveFileTransfer_MalformedURLException); + } + } + + IRetrieveFileTransferContainerAdapter fileTransfer = Activator.getDefault().getFileTransfer(protocol); + + // We will default to JRE-provided file transfer if nothing else + // available + // for given protocol + if (fileTransfer == null) + fileTransfer = new UrlConnectionRetrieveFileTransfer(); + + // Set connect context + fileTransfer.setConnectContextForAuthentication(connectContext); + // Set Proxy + fileTransfer.setProxy(proxy); + + // send request using given file transfer protocol + fileTransfer.sendRetrieveRequest(remoteFileID, rangeSpecification, transferListener, options); + + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + if (adapter == null) + return null; + final IAdapterManager adapterManager = Activator.getDefault().getAdapterManager(); + if (adapterManager == null) + return null; + return (T) adapterManager.loadAdapter(this, adapter.getName()); + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapterFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapterFactory.java new file mode 100644 index 0000000000..fba1a32bcf --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/MultiProtocolRetrieveAdapterFactory.java @@ -0,0 +1,47 @@ +/**************************************************************************** + * Copyright (c) 2004, 2007 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.retrieve; + +import org.eclipse.ecf.core.AbstractContainerAdapterFactory; +import org.eclipse.ecf.core.IContainer; +import org.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter; + +/** + * + */ +public class MultiProtocolRetrieveAdapterFactory extends AbstractContainerAdapterFactory { + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.sharedobject.AbstractSharedObjectContainerAdapterFactory#getAdapterList() + */ + public Class[] getAdapterList() { + return new Class[] {IRetrieveFileTransferContainerAdapter.class}; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.ecf.core.AbstractContainerAdapterFactory#getContainerAdapter(org.eclipse.ecf.core.IContainer, + * java.lang.Class) + */ + protected Object getContainerAdapter(IContainer container, Class adapterType) { + if (adapterType.equals(IRetrieveFileTransferContainerAdapter.class)) { + return new MultiProtocolRetrieveAdapter(); + } + return null; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/UrlConnectionRetrieveFileTransfer.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/UrlConnectionRetrieveFileTransfer.java new file mode 100644 index 0000000000..6ecf85f80f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/retrieve/UrlConnectionRetrieveFileTransfer.java @@ -0,0 +1,574 @@ +/**************************************************************************** + * Copyright (c) 2004 Composent, Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: Composent, Inc. - initial API and implementation + * Maarten Meijer - bug 237936, added gzip encoded transfer default + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.retrieve; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.Authenticator; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.PasswordAuthentication; +import java.net.URL; +import java.net.URLConnection; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.net.ssl.SSLContext; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.ecf.core.security.Callback; +import org.eclipse.ecf.core.security.CallbackHandler; +import org.eclipse.ecf.core.security.IConnectContext; +import org.eclipse.ecf.core.security.NameCallback; +import org.eclipse.ecf.core.security.ObjectCallback; +import org.eclipse.ecf.core.security.UnsupportedCallbackException; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.filetransfer.IFileRangeSpecification; +import org.eclipse.ecf.filetransfer.IFileTransferPausable; +import org.eclipse.ecf.filetransfer.IRetrieveFileTransferOptions; +import org.eclipse.ecf.filetransfer.IncomingFileTransferException; +import org.eclipse.ecf.filetransfer.InvalidFileRangeSpecificationException; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; +import org.eclipse.ecf.internal.provider.filetransfer.IURLConnectionModifier; +import org.eclipse.ecf.internal.provider.filetransfer.Messages; +import org.eclipse.ecf.provider.filetransfer.util.JREProxyHelper; +import org.eclipse.osgi.util.NLS; + +public class UrlConnectionRetrieveFileTransfer extends AbstractRetrieveFileTransfer { + + private static final String USERNAME_PREFIX = Messages.UrlConnectionRetrieveFileTransfer_USERNAME_PROMPT; + + private static final int HTTP_RANGE_RESPONSE = 206; + + private static final int OK_RESPONSE_CODE = 200; + + private static final String JRE_CONNECT_TIMEOUT_PROPERTY = "sun.net.client.defaultConnectTimeout"; //$NON-NLS-1$ + + // 10/26/2009: Added being able to set with system property with name org.eclipse.ecf.provider.filetransfer.connectTimeout + // for https://bugs.eclipse.org/bugs/show_bug.cgi?id=292995 + private static final String DEFAULT_CONNECT_TIMEOUT = System.getProperty("org.eclipse.ecf.provider.filetransfer.retrieve.connectTimeout", "15000"); //$NON-NLS-1$ //$NON-NLS-2$ + + private static final String JRE_READ_TIMEOUT_PROPERTY = "sun.net.client.defaultReadTimeout"; //$NON-NLS-1$ + + protected URLConnection urlConnection; + + protected int httpVersion = 1; + + protected int responseCode = -1; + + private String remoteFileName; + + protected String responseMessage = null; + + private JREProxyHelper proxyHelper = null; + + protected String username = null; + + protected String password = null; + + public UrlConnectionRetrieveFileTransfer() { + super(); + proxyHelper = new JREProxyHelper(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer + * #getRemoteFileName() + */ + public String getRemoteFileName() { + return remoteFileName; + } + + protected void connect() throws IOException { + setupTimeouts(); + urlConnection = getRemoteFileURL().openConnection(); + try { + SSLContext.getDefault(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // set cache to off if using jar protocol + // this is for addressing bug + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=235933 + if (getRemoteFileURL().getProtocol().equalsIgnoreCase("jar")) { //$NON-NLS-1$ + urlConnection.setUseCaches(false); + } + IURLConnectionModifier connectionModifier = Activator.getDefault().getURLConnectionModifier(); + if (connectionModifier != null) { + connectionModifier.setSocketFactoryForConnection(urlConnection); + } + } + + protected boolean isConnected() { + return (urlConnection != null); + } + + protected void setResumeRequestHeaderValues() throws IOException { + if (this.bytesReceived <= 0 || this.fileLength <= this.bytesReceived) + throw new IOException(Messages.UrlConnectionRetrieveFileTransfer_RESUME_START_ERROR); + setRangeHeader("bytes=" + this.bytesReceived + "-"); //$NON-NLS-1$ //$NON-NLS-2$ + int maxAge = Integer.getInteger("org.eclipse.ecf.http.cache.max-age", 0).intValue(); //$NON-NLS-1$ + // set max-age for cache control to 0 for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=249990 + // fix the fix for bug 249990 with bug 410813 + if (maxAge == 0) { + urlConnection.setRequestProperty("Cache-Control", "max-age=0"); //$NON-NLS-1$//$NON-NLS-2$ + } else if (maxAge > 0) { + urlConnection.setRequestProperty("Cache-Control", "max-age=" + maxAge); //$NON-NLS-1$//$NON-NLS-2$ + } + setRequestHeaderValuesFromOptions(); + } + + private void setRequestHeaderValuesFromOptions() { + Map localOptions = getOptions(); + if (localOptions != null) { + Object o = localOptions.get(IRetrieveFileTransferOptions.REQUEST_HEADERS); + if (o != null && o instanceof Map) { + Map requestHeaders = (Map) o; + for (Iterator i = requestHeaders.keySet().iterator(); i.hasNext();) { + Object n = i.next(); + Object v = requestHeaders.get(n); + if (n != null && n instanceof String && v != null && v instanceof String) + urlConnection.addRequestProperty((String) n, (String) v); + } + } + } + } + + protected void setRequestHeaderValues() throws InvalidFileRangeSpecificationException { + final IFileRangeSpecification rangeSpec = getFileRangeSpecification(); + if (rangeSpec != null && isHTTP()) { + final long startPosition = rangeSpec.getStartPosition(); + final long endPosition = rangeSpec.getEndPosition(); + if (startPosition < 0) + throw new InvalidFileRangeSpecificationException(Messages.UrlConnectionRetrieveFileTransfer_RESUME_START_POSITION_LESS_THAN_ZERO, rangeSpec); + if (endPosition != -1L && endPosition <= startPosition) + throw new InvalidFileRangeSpecificationException(Messages.UrlConnectionRetrieveFileTransfer_RESUME_ERROR_END_POSITION_LESS_THAN_START, rangeSpec); + setRangeHeader("bytes=" + startPosition + "-" + ((endPosition == -1L) ? "" : ("" + endPosition))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + // Add http 1.1 'Connection: close' header in order to potentially avoid + // server issue described here + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=234916#c13 + // See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=247197 + // also see http 1.1 rfc section 14-10 in + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + urlConnection.setRequestProperty("Connection", "close"); //$NON-NLS-1$ //$NON-NLS-2$ + int maxAge = Integer.getInteger("org.eclipse.ecf.http.cache.max-age", 0).intValue(); //$NON-NLS-1$ + // set max-age for cache control to 0 for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=249990 + // fix the fix for bug 249990 with bug 410813 + if (maxAge == 0) { + urlConnection.setRequestProperty("Cache-Control", "max-age=0"); //$NON-NLS-1$//$NON-NLS-2$ + } else if (maxAge > 0) { + urlConnection.setRequestProperty("Cache-Control", "max-age=" + maxAge); //$NON-NLS-1$//$NON-NLS-2$ + } + setRequestHeaderValuesFromOptions(); + } + + private void setRangeHeader(String value) { + urlConnection.setRequestProperty("Range", value); //$NON-NLS-1$ + } + + public int getResponseCode() { + if (responseCode != -1) + return responseCode; + if (isHTTP()) { + String response = urlConnection.getHeaderField(0); + if (response == null) { + responseCode = -1; + httpVersion = 1; + return responseCode; + } + if (!response.startsWith("HTTP/")) //$NON-NLS-1$ + return -1; + response = response.trim(); + final int mark = response.indexOf(" ") + 1; //$NON-NLS-1$ + if (mark == 0) + return -1; + if (response.charAt(mark - 2) != '1') + httpVersion = 0; + int last = mark + 3; + if (last > response.length()) + last = response.length(); + responseCode = Integer.parseInt(response.substring(mark, last)); + if (last + 1 <= response.length()) + responseMessage = response.substring(last + 1); + } else { + responseCode = OK_RESPONSE_CODE; + responseMessage = "OK"; //$NON-NLS-1$ + } + + return responseCode; + + } + + private boolean isHTTP() { + final String protocol = getRemoteFileURL().getProtocol(); + if (protocol.equalsIgnoreCase("http") || protocol.equalsIgnoreCase("https")) //$NON-NLS-1$ //$NON-NLS-2$ + return true; + return false; + } + + private boolean isHTTP11() { + return (isHTTP() && httpVersion >= 1); + } + + protected void getResponseHeaderValues() throws IOException { + if (!isConnected()) + throw new ConnectException(Messages.UrlConnectionRetrieveFileTransfer_CONNECT_EXCEPTION_NOT_CONNECTED); + if (getResponseCode() == -1) + throw new IOException(Messages.UrlConnectionRetrieveFileTransfer_EXCEPTION_INVALID_SERVER_RESPONSE); + setLastModifiedTime(urlConnection.getLastModified()); + setFileLength(urlConnection.getContentLength()); + + String contentDispositionValue = urlConnection.getHeaderField(HttpHelper.CONTENT_DISPOSITION_HEADER); + if (contentDispositionValue != null) { + remoteFileName = HttpHelper.getRemoteFileNameFromContentDispositionHeader(contentDispositionValue); + } + + if (remoteFileName == null) { + String pathStr = urlConnection.getURL().getPath(); + if (pathStr != null) { + IPath path = Path.fromPortableString(pathStr); + if (path.segmentCount() > 0) + remoteFileName = path.lastSegment(); + } + if (remoteFileName == null) + remoteFileName = super.getRemoteFileName(); + } + } + + protected void getResumeResponseHeaderValues() throws IOException { + if (!isConnected()) + throw new ConnectException(Messages.UrlConnectionRetrieveFileTransfer_CONNECT_EXCEPTION_NOT_CONNECTED); + if (getResponseCode() != HTTP_RANGE_RESPONSE) + throw new IOException(Messages.UrlConnectionRetrieveFileTransfer_INVALID_SERVER_RESPONSE_TO_PARTIAL_RANGE_REQUEST); + if (lastModifiedTime != urlConnection.getLastModified()) + throw new IOException(Messages.UrlConnectionRetrieveFileTransfer_EXCEPTION_FILE_MODIFIED_SINCE_LAST_ACCESS); + } + + /** + * @param proxy2 + * the ECF proxy to setup + */ + protected void setupProxy(final Proxy proxy2) { + proxyHelper.setupProxy(proxy2); + } + + protected void setupAuthentication() throws IOException, UnsupportedCallbackException { + if (connectContext == null) + return; + final CallbackHandler callbackHandler = connectContext.getCallbackHandler(); + if (callbackHandler == null) + return; + final NameCallback usernameCallback = new NameCallback(USERNAME_PREFIX); + final ObjectCallback passwordCallback = new ObjectCallback(); + // Call callback with username and password callbacks + callbackHandler.handle(new Callback[] {usernameCallback, passwordCallback}); + username = usernameCallback.getName(); + Object o = passwordCallback.getObject(); + if (!(o instanceof String)) + throw new UnsupportedCallbackException(passwordCallback, Messages.UrlConnectionRetrieveFileTransfer_UnsupportedCallbackException); + password = (String) passwordCallback.getObject(); + // Now set authenticator to our authenticator with user and password + Authenticator.setDefault(new UrlConnectionAuthenticator()); + } + + class UrlConnectionAuthenticator extends Authenticator { + /* + * (non-Javadoc) + * + * @see java.net.Authenticator#getPasswordAuthentication() + */ + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password.toCharArray()); + } + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.ecf.filetransfer.IRetrieveFileTransferContainerAdapter# + * setConnectContextForAuthentication + * (org.eclipse.ecf.core.security.IConnectContext) + */ + public void setConnectContextForAuthentication(IConnectContext connectContext) { + super.setConnectContextForAuthentication(connectContext); + this.username = null; + this.password = null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer + * #openStreams() + */ + protected void openStreams() throws IncomingFileTransferException { + int code = -1; + try { + setupAuthentication(); + connect(); + setRequestHeaderValues(); + // Make actual GET request + // need to get response header about encoding before setting stream + setCompressionRequestHeader(); + setInputStream(getDecompressedStream()); + code = getResponseCode(); + responseHeaders = getResponseHeaders(); + if (isHTTP()) { + if (code == HttpURLConnection.HTTP_PARTIAL || code == HttpURLConnection.HTTP_OK) { + fireReceiveStartEvent(); + } else if (code == HttpURLConnection.HTTP_NOT_FOUND) { + throw new IncomingFileTransferException(NLS.bind("File not found: {0}", getRemoteFileURL().toString()), code, responseHeaders); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_UNAUTHORIZED) { + throw new IncomingFileTransferException("Unauthorized", code, responseHeaders); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_FORBIDDEN) { + throw new IncomingFileTransferException("Forbidden", code, responseHeaders); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_PROXY_AUTH) { + throw new IncomingFileTransferException("Proxy authentication required", code, responseHeaders); //$NON-NLS-1$ + } else { + throw new IncomingFileTransferException(NLS.bind("General connection error with response code={0}", Integer.valueOf(code)), code, responseHeaders); //$NON-NLS-1$ + } + } else { + fireReceiveStartEvent(); + } + } catch (final FileNotFoundException e) { + throw new IncomingFileTransferException(NLS.bind("File not found: {0}", getRemoteFileURL().toString()), 404); //$NON-NLS-1$ + } catch (final Exception e) { + IncomingFileTransferException except = (e instanceof IncomingFileTransferException) ? (IncomingFileTransferException) e : new IncomingFileTransferException(NLS.bind(Messages.UrlConnectionRetrieveFileTransfer_EXCEPTION_COULD_NOT_CONNECT, getRemoteFileURL().toString()), e, code, responseHeaders); + hardClose(); + throw except; + } + } + + private Map getResponseHeaders() { + if (responseHeaders != null) + return responseHeaders; + if (urlConnection == null) + return null; + Map headerFields = urlConnection.getHeaderFields(); + if (headerFields == null) + return null; + Map result = new HashMap(); + for (Iterator i = headerFields.keySet().iterator(); i.hasNext();) { + String name = (String) i.next(); + List listValue = (List) headerFields.get(name); + String val = null; + if (listValue != null && listValue.size() > 0) { + val = (String) ((listValue.size() > 1) ? listValue.get(listValue.size() - 1) : listValue.get(0)); + } + if (name != null && val != null) + result.put(name, val); + } + return Collections.unmodifiableMap(result); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer + * #hardClose() + */ + protected void hardClose() { + super.hardClose(); + urlConnection = null; + responseCode = -1; + if (proxyHelper != null) { + proxyHelper.dispose(); + proxyHelper = null; + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer + * #doPause() + */ + protected boolean doPause() { + if (isPaused() || !isConnected() || isDone()) + return false; + this.paused = true; + return this.paused; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer + * #doResume() + */ + protected boolean doResume() { + if (!isPaused() || isConnected()) + return false; + return openStreamsForResume(); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ecf.provider.filetransfer.retrieve.AbstractRetrieveFileTransfer + * #getAdapter(java.lang.Class) + */ + public T getAdapter(Class adapter) { + if (adapter == null) + return null; + if (adapter.equals(IFileTransferPausable.class) && isHTTP11()) + return adapter.cast(this); + return super.getAdapter(adapter); + } + + protected String getConnectTimeout() { + String result = DEFAULT_CONNECT_TIMEOUT; + Map localOptions = getOptions(); + if (localOptions != null) { + // See if the connect timeout option is present, if so set + Object o = localOptions.get(IRetrieveFileTransferOptions.CONNECT_TIMEOUT); + if (o != null) { + if (o instanceof Integer) { + result = ((Integer) o).toString(); + } else if (o instanceof String) { + result = (String) o; + } + return result; + } + o = localOptions.get("org.eclipse.ecf.provider.filetransfer.httpclient.retrieve.connectTimeout"); //$NON-NLS-1$ + if (o != null) { + if (o instanceof Integer) { + result = ((Integer) o).toString(); + } else if (o instanceof String) { + result = (String) o; + } + } + } + return result; + } + + private void setupTimeouts() { + String existingTimeout = System.getProperty(JRE_CONNECT_TIMEOUT_PROPERTY); + if (existingTimeout == null) { + System.setProperty(JRE_CONNECT_TIMEOUT_PROPERTY, getConnectTimeout()); + } + existingTimeout = System.getProperty(JRE_READ_TIMEOUT_PROPERTY); + if (existingTimeout == null) { + System.setProperty(JRE_READ_TIMEOUT_PROPERTY, "" + getSocketReadTimeout()); //$NON-NLS-1$ + } + } + + /** + * @return true if streams successfully, false + * otherwise. + */ + private boolean openStreamsForResume() { + final URL theURL = getRemoteFileURL(); + int code = -1; + try { + remoteFileURL = new URL(theURL.toString()); + setupAuthentication(); + connect(); + setResumeRequestHeaderValues(); + // Make actual GET request + setInputStream(urlConnection.getInputStream()); + code = getResponseCode(); + responseHeaders = getResponseHeaders(); + if (code == HttpURLConnection.HTTP_PARTIAL || code == HttpURLConnection.HTTP_OK) { + getResumeResponseHeaderValues(); + this.paused = false; + fireReceiveResumedEvent(); + return true; + } else if (code == HttpURLConnection.HTTP_NOT_FOUND) { + throw new IncomingFileTransferException(NLS.bind("File not found: {0}", getRemoteFileURL().toString()), code, responseHeaders); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_UNAUTHORIZED) { + throw new IncomingFileTransferException("Unauthorized", code, responseHeaders); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_FORBIDDEN) { + throw new IncomingFileTransferException("Forbidden", code, responseHeaders); //$NON-NLS-1$ + } else if (code == HttpURLConnection.HTTP_PROXY_AUTH) { + throw new IncomingFileTransferException("Proxy authentication required", code, responseHeaders); //$NON-NLS-1$ + } else { + throw new IncomingFileTransferException(NLS.bind("General connection error with response code={0}", Integer.valueOf(code)), code, responseHeaders); //$NON-NLS-1$ + } + } catch (final Exception e) { + this.exception = (e instanceof IncomingFileTransferException) ? e : new IncomingFileTransferException(NLS.bind(Messages.UrlConnectionRetrieveFileTransfer_EXCEPTION_COULD_NOT_CONNECT, getRemoteFileURL().toString()), e, code, responseHeaders); + this.done = true; + hardClose(); + fireTransferReceiveDoneEvent(); + return false; + } + } + + private static final String ACCEPT_ENCODING = "Accept-encoding"; //$NON-NLS-1$ + private static final String CONTENT_ENCODING_GZIP = "gzip"; //$NON-NLS-1$ + + private static final String CONTENT_ENCODING_ACCEPTED = CONTENT_ENCODING_GZIP; // + + + private static class Compression { + + private String type; + + private Compression(String i) { + this.type = i; + } + + static Compression NONE = new Compression("none"); //$NON-NLS-1$ + + static Compression GZIP = new Compression("gzip"); //$NON-NLS-1$ + + public String toString() { + return type; + } + } + + private void setCompressionRequestHeader() { + // Set request header for possible gzip encoding, but only if + // 1) The file range specification is null (we want the whole file) + // 2) The target remote file does *not* end in .gz (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=280205) + if (getFileRangeSpecification() == null && !targetHasGzSuffix(super.getRemoteFileName())) + urlConnection.setRequestProperty(ACCEPT_ENCODING, CONTENT_ENCODING_ACCEPTED); + } + + private Compression getCompressionResponseHeader() { + String encoding = urlConnection.getContentEncoding(); + if (null == encoding) { + return Compression.NONE; + // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=269018 + } else if (encoding.equalsIgnoreCase(CONTENT_ENCODING_GZIP) && !targetHasGzSuffix(remoteFileName)) { + return Compression.GZIP; + } + return Compression.NONE; + } + + private InputStream getDecompressedStream() throws IOException { + InputStream input = urlConnection.getInputStream(); + getResponseHeaderValues(); + Compression type = getCompressionResponseHeader(); + + if (Compression.GZIP == type) { + return new java.util.zip.GZIPInputStream(input); + // } else if (Compression.DEFLATE == type) { + // return new java.util.zip.InflaterInputStream(input); + } + return input; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/JREProxyHelper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/JREProxyHelper.java new file mode 100644 index 0000000000..02f943ac27 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/JREProxyHelper.java @@ -0,0 +1,92 @@ +/**************************************************************************** + * Copyright (c) 2007, 2010 Composent, Inc. and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Composent, Inc. - initial API and implementation + * Henrich Kraemer - bug 295030, Update Manager doesn't work with SOCKS proxy + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ + +package org.eclipse.ecf.provider.filetransfer.util; + +import java.net.Authenticator; +import java.net.PasswordAuthentication; +import java.util.Properties; +import org.eclipse.ecf.core.util.Proxy; + +/** + * Helper class for setting the JRE proxy value (http and socks). + */ +public class JREProxyHelper { + + private static final String SOCKS_PROXY_PORT_SYSTEM_PROPERTY = "socksProxyPort"; //$NON-NLS-1$ + + private static final String SOCKS_PROXY_HOST_SYSTEM_PROPERTY = "socksProxyHost"; //$NON-NLS-1$ + + private static final String HTTP_PROXY_PORT_SYSTEM_PROPERTY = "http.proxyPort"; //$NON-NLS-1$ + + private static final String HTTP_PROXY_HOST_SYSTEM_PROPERTY = "http.proxyHost"; //$NON-NLS-1$ + + private String proxyHostProperty; + private String proxyPortProperty; + + private String oldHost; + private String oldPort; + + public void setupProxy(final Proxy proxy2) { + Properties systemProperties = System.getProperties(); + proxyHostProperty = (proxy2.getType().equals(Proxy.Type.HTTP)) ? HTTP_PROXY_HOST_SYSTEM_PROPERTY : SOCKS_PROXY_HOST_SYSTEM_PROPERTY; + proxyPortProperty = (proxy2.getType().equals(Proxy.Type.HTTP)) ? HTTP_PROXY_PORT_SYSTEM_PROPERTY : SOCKS_PROXY_PORT_SYSTEM_PROPERTY; + oldHost = systemProperties.getProperty(proxyHostProperty); + if (oldHost != null) { + oldPort = systemProperties.getProperty(proxyPortProperty); + } + systemProperties.setProperty(proxyHostProperty, proxy2.getAddress().getHostName()); + int proxyPort = proxy2.getAddress().getPort(); + if (proxyPort != -1) + systemProperties.setProperty(proxyPortProperty, proxyPort + ""); //$NON-NLS-1$ + final String username = proxy2.getUsername(); + boolean setAuthenticator = false; + if (username != null && !username.equals("")) { //$NON-NLS-1$ + final String password = (proxy2.getPassword() == null) ? "" : proxy2.getPassword(); //$NON-NLS-1$ + if (proxy2.hasCredentials()) { + Authenticator.setDefault(new Authenticator() { + /* (non-Javadoc) + * @see java.net.Authenticator#getPasswordAuthentication() + */ + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password.toCharArray()); + } + }); + setAuthenticator = true; + } + } + if (!setAuthenticator) { + Authenticator.setDefault(new Authenticator() { + /* (non-Javadoc) + * @see java.net.Authenticator#getPasswordAuthentication() + */ + protected PasswordAuthentication getPasswordAuthentication() { + return null; + } + }); + } + } + + public void dispose() { + // reset old values + if (oldHost != null) { + System.getProperties().setProperty(proxyHostProperty, oldHost); + oldHost = null; + if (oldPort != null) { + System.getProperties().setProperty(proxyPortProperty, oldPort); + oldPort = null; + } + } + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/PollingInputStream.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/PollingInputStream.java new file mode 100644 index 0000000000..c78b09e310 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/PollingInputStream.java @@ -0,0 +1,276 @@ +/**************************************************************************** + * Copyright (c) 2000, 2007 IBM Corporation and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * EclipseSource - modification after copying to ECF filetransfer provider + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.util; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.core.runtime.Status; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; + +/** + * Polls a progress monitor periodically and handles timeouts over extended + * durations. For this class to be effective, a high numAttempts should be + * specified, and the underlying stream should time out frequently on reads + * (every second or so). + * + * Supports resuming partially completed operations after an + * InterruptedIOException if the underlying stream does. Check the + * bytesTransferred field to determine how much of the operation completed; + * conversely, at what point to resume. + * + * @since 3.0 + */ +public class PollingInputStream extends FilterInputStream { + private int numAttempts; + private IProgressMonitor monitor; + private boolean cancellable; + + private String readTimeoutMessage = "Timeout while reading input stream"; //$NON-NLS-1$ + private String closeTimeoutMessage = "Timeout while closing input stream"; //$NON-NLS-1$ + + /** + * Creates a new polling input stream. + * + * @param in + * the underlying input stream + * @param numAttempts + * the number of attempts before issuing an + * InterruptedIOException, if 0, retries indefinitely until + * canceled + * @param monitor + * the progress monitor to be polled for cancellation + */ + public PollingInputStream(InputStream in, int numAttempts, IProgressMonitor monitor) { + super(in); + this.numAttempts = numAttempts; + this.monitor = monitor; + this.cancellable = true; + } + + /** + * Creates a new polling input stream. + * + * @param in + * the underlying input stream + * @param numAttempts + * the number of attempts before issuing an + * InterruptedIOException, if 0, retries indefinitely until + * canceled + * @param monitor + * the progress monitor to be polled for cancellation + * @param readTimeoutMessage message to go with InteruptedIOException if read timeout + * @param closeTimeoutMessage message to go with InteruptedIOException if close timeout + * @since 3.1 + */ + public PollingInputStream(InputStream in, int numAttempts, IProgressMonitor monitor, String readTimeoutMessage, String closeTimeoutMessage) { + super(in); + this.numAttempts = numAttempts; + this.monitor = monitor; + this.cancellable = true; + if (readTimeoutMessage != null) + this.readTimeoutMessage = readTimeoutMessage; + if (closeTimeoutMessage != null) + this.closeTimeoutMessage = closeTimeoutMessage; + } + + /** + * Wraps the underlying stream's method. It may be important to wait for an + * input stream to be closed because it holds an implicit lock on a system + * resource (such as a file) while it is open. Closing a stream may take + * time if the underlying stream is still servicing a previous request. + * + * @throws OperationCanceledException + * if the progress monitor is canceled + * @throws InterruptedIOException + * if the underlying operation times out numAttempts times + */ + public void close() throws InterruptedIOException { + int attempts = 0; + try { + readPendingInput(); + } catch (IOException e) { + // We shouldn't get an exception when we're getting the available + // input. + // If we do, just log it so we can close. + logError(e.getMessage(), e); + } finally { + boolean stop = false; + while (!stop) { + try { + if (in != null) + in.close(); + stop = true; + } catch (InterruptedIOException e) { + if (checkCancellation()) + throw new OperationCanceledException(); + if (++attempts == numAttempts) + throw new InterruptedIOException(closeTimeoutMessage); + } catch (IOException e) { + // ignore it - see + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=203423#c10 + } + } + } + } + + private void logError(String message, IOException e) { + Activator a = Activator.getDefault(); + if (a != null) + a.log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, message, e)); + } + + /** + * Wraps the underlying stream's method. + * + * @return the next byte of data, or -1 if the end of the stream is reached. + * @throws OperationCanceledException + * if the progress monitor is canceled + * @throws InterruptedIOException + * if the underlying operation times out numAttempts times and + * no data was received, bytesTransferred will be zero + * @throws IOException + * if an i/o error occurs + */ + public int read() throws IOException { + int attempts = 0; + for (;;) { + if (checkCancellation()) + throw new OperationCanceledException(); + try { + return in.read(); + } catch (InterruptedIOException e) { + if (++attempts == numAttempts) + throw new InterruptedIOException(readTimeoutMessage); + } + } + } + + /** + * Wraps the underlying stream's method. + * + * @param buffer + * - the buffer into which the data is read. + * @param off + * - the start offset of the data. + * @param len + * - the maximum number of bytes read. + * @return the total number of bytes read into the buffer, or -1 if there is + * no more data because the end of the stream has been reached. + * @throws OperationCanceledException + * if the progress monitor is canceled + * @throws InterruptedIOException + * if the underlying operation times out numAttempts times and + * no data was received, bytesTransferred will be zero + * @throws IOException + * if an i/o error occurs + */ + public int read(byte[] buffer, int off, int len) throws IOException { + int attempts = 0; + for (;;) { + if (checkCancellation()) + throw new OperationCanceledException(); + try { + return in.read(buffer, off, len); + } catch (InterruptedIOException e) { + if (e.bytesTransferred != 0) + return e.bytesTransferred; // keep partial transfer + if (++attempts == numAttempts) + throw new InterruptedIOException(readTimeoutMessage); + } + } + } + + /** + * Wraps the underlying stream's method. + * + * @param count + * - the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @throws OperationCanceledException + * if the progress monitor is canceled + * @throws InterruptedIOException + * if the underlying operation times out numAttempts times and + * no data was received, bytesTransferred will be zero + * @throws IOException + * if an i/o error occurs + */ + public long skip(long count) throws IOException { + int attempts = 0; + for (;;) { + if (checkCancellation()) + throw new OperationCanceledException(); + try { + return in.skip(count); + } catch (InterruptedIOException e) { + if (e.bytesTransferred != 0) + return e.bytesTransferred; // keep partial transfer + if (++attempts == numAttempts) + throw new InterruptedIOException(readTimeoutMessage); + } + } + } + + /** + * Reads any pending input from the input stream so that the stream can + * savely be closed. + * + * @throws IOException if some problem reading + */ + protected void readPendingInput() throws IOException { + byte[] buffer = new byte[2048]; + while (true) { + int available = in.available(); + if (available < 1) + break; + if (available > buffer.length) + available = buffer.length; + if (in.read(buffer, 0, available) < 1) + break; + } + } + + /** + * Called to set whether cancellation will be checked by this stream. + * Turning cancellation checking off can be very useful for protecting + * critical portions of a protocol that shouldn't be interrupted. For + * example, it is often necessary to protect login sequences. + * + * @param cancellable + * a flag controlling whether this stream will check for + * cancellation. + */ + public void setIsCancellable(boolean cancellable) { + this.cancellable = cancellable; + } + + /** + * Checked whether the monitor for this stream has been cancelled. If the + * cancellable flag is false then the monitor is never + * cancelled. + * + * @return true if the monitor has been cancelled and + * false otherwise. + */ + private boolean checkCancellation() { + if (cancellable) { + return monitor.isCanceled(); + } + return false; + } +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/ProxySetupHelper.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/ProxySetupHelper.java new file mode 100644 index 0000000000..bcd20edd16 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/ProxySetupHelper.java @@ -0,0 +1,105 @@ +/**************************************************************************** + * Copyright (c) 2010 IBM, and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.util; + +import java.net.URI; +import java.net.URL; +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.net.proxy.IProxyService; +import org.eclipse.ecf.core.util.Proxy; +import org.eclipse.ecf.core.util.ProxyAddress; +import org.eclipse.ecf.internal.provider.filetransfer.Activator; + +/** + * Proxy setup utilities. + * + * NOTE: Use of this class implies the presence of the core.net.proxy + * API...this class will not load (NoClassDefFoundError will be thrown if load/use is attempted) + * if the core.net.proxy bundle is not present in the runtime. + * + * @noextend This class is not intended to be extended by clients. + * @since 3.1 + */ +public class ProxySetupHelper { + public static Proxy getProxy(String url) { + Proxy proxy = null; + try { + IProxyService proxyService = Activator.getDefault().getProxyService(); + // Only do this if platform service exists + if (proxyService != null && proxyService.isProxiesEnabled()) { + // Setup via proxyService entry + URI uri = new URI(url); + final IProxyData[] proxies = proxyService.select(uri); + IProxyData selectedProxy = selectProxyFromProxies(uri.getScheme(), proxies); + if (selectedProxy != null) { + proxy = new Proxy(((selectedProxy.getType().equalsIgnoreCase(IProxyData.SOCKS_PROXY_TYPE)) ? Proxy.Type.SOCKS : Proxy.Type.HTTP), new ProxyAddress(selectedProxy.getHost(), selectedProxy.getPort()), selectedProxy.getUserId(), selectedProxy.getPassword()); + } + } + } catch (Exception e) { + // If we don't even have the classes for this (i.e. the org.eclipse.core.net plugin not available) + // then we simply log and ignore + Activator.logNoProxyWarning(e); + } catch (NoClassDefFoundError e) { + Activator.logNoProxyWarning(e); + } + return proxy; + } + + public static Proxy getSocksProxy(URL url) { + String host = url.getHost(); + int port = url.getPort(); + String strURL = IProxyData.SOCKS_PROXY_TYPE + "://" + host; //$NON-NLS-1$ + if (port != -1) { + strURL += ":" + port; //$NON-NLS-1$ + } + return ProxySetupHelper.getProxy(strURL); + } + + /** + * Select a single proxy from a set of proxies available for the given host. This implementation + * selects in the following manner: 1) If proxies provided is null or array of 0 length, null + * is returned. If only one proxy is available (array of length 1) then the entry is returned. + * If proxies provided is length greater than 1, then if the type of a proxy in the array matches the given + * protocol (e.g. http, https), then the first matching proxy is returned. If the protocol does + * not match any of the proxies, then the *first* proxy (i.e. proxies[0]) is returned. + * + * @param protocol the target protocol (e.g. http, https, scp, etc). Will not be null. + * @param proxies the proxies to select from. May be null or array of length 0. + * @return proxy data selected from the proxies provided. + */ + public static IProxyData selectProxyFromProxies(String protocol, IProxyData[] proxies) { + if (proxies == null || proxies.length == 0) + return null; + // If only one proxy is available, then use that + if (proxies.length == 1) + return proxies[0]; + // If more than one proxy is available, then if http/https protocol then look for that + // one...if not found then use first + if (protocol.equalsIgnoreCase("http")) { //$NON-NLS-1$ + for (IProxyData proxie : proxies) { + if (proxie.getType().equals(IProxyData.HTTP_PROXY_TYPE)) { + return proxie; + } + } + } else if (protocol.equalsIgnoreCase("https")) { //$NON-NLS-1$ + for (IProxyData proxie : proxies) { + if (proxie.getType().equals(IProxyData.HTTPS_PROXY_TYPE)) { + return proxie; + } + } + } + // If we haven't found it yet, then return the first one. + return proxies[0]; + } + +} diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/TimeoutInputStream.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/TimeoutInputStream.java new file mode 100644 index 0000000000..45109558a6 --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/ecf/provider/filetransfer/util/TimeoutInputStream.java @@ -0,0 +1,378 @@ +/**************************************************************************** + * Copyright (c) 2000, 2006 IBM Corporation and others. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * IBM Corporation - initial API and implementation + * + * SPDX-License-Identifier: EPL-2.0 + *****************************************************************************/ +package org.eclipse.ecf.provider.filetransfer.util; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; + +/** + * Wraps an input stream that blocks indefinitely to simulate timeouts on + * read(), skip(), and close(). The resulting input stream is buffered and + * supports retrying operations that failed due to an InterruptedIOException. + * + * Supports resuming partially completed operations after an + * InterruptedIOException REGARDLESS of whether the underlying stream does + * unless the underlying stream itself generates InterruptedIOExceptions in + * which case it must also support resuming. Check the bytesTransferred field to + * determine how much of the operation completed; conversely, at what point to + * resume. + * + * @since 3.0 + */ +public class TimeoutInputStream extends FilterInputStream { + // unsynchronized variables + private final long readTimeout; // read() timeout in millis + private final long closeTimeout; // close() timeout in millis, or -1 + + // requests for the thread (synchronized) + private boolean closeRequested = false; // if true, close requested + + // responses from the thread (synchronized) + private Thread thread; // if null, thread has terminated + private byte[] iobuffer; // circular buffer + private int head = 0; // points to first unread byte + private int length = 0; // number of remaining unread bytes + private IOException ioe = null; // if non-null, contains a pending exception + private boolean waitingForClose = false; // if true, thread is waiting for + // close() + + private boolean growWhenFull = false; // if true, buffer will grow when it + + // is full + + /** + * Creates a timeout wrapper for an input stream. + * + * @param in + * the underlying input stream + * @param bufferSize + * the buffer size in bytes; should be large enough to mitigate + * Thread synchronization and context switching overhead + * @param readTimeout + * the number of milliseconds to block for a read() or skip() + * before throwing an InterruptedIOException; 0 blocks + * indefinitely + * @param closeTimeout + * the number of milliseconds to block for a close() before + * throwing an InterruptedIOException; 0 blocks indefinitely, -1 + * closes the stream in the background + */ + public TimeoutInputStream(InputStream in, int bufferSize, long readTimeout, long closeTimeout) { + super(in); + this.readTimeout = readTimeout; + this.closeTimeout = closeTimeout; + this.iobuffer = new byte[bufferSize]; + thread = new Thread(new Runnable() { + public void run() { + runThread(); + } + }, "TimeoutInputStream");//$NON-NLS-1$ + thread.setDaemon(true); + thread.start(); + } + + public TimeoutInputStream(InputStream in, int bufferSize, long readTimeout, long closeTimeout, boolean growWhenFull) { + this(in, bufferSize, readTimeout, closeTimeout); + this.growWhenFull = growWhenFull; + } + + /** + * Wraps the underlying stream's method. It may be important to wait for a + * stream to actually be closed because it holds an implicit lock on a + * system resoure (such as a file) while it is open. Closing a stream may + * take time if the underlying stream is still servicing a previous request. + * + * @throws InterruptedIOException + * if the timeout expired + * @throws IOException + * if an i/o error occurs + */ + public void close() throws IOException { + Thread oldThread; + synchronized (this) { + if (thread == null) + return; + oldThread = thread; + closeRequested = true; + thread.interrupt(); + checkError(); + } + if (closeTimeout == -1) + return; + try { + oldThread.join(closeTimeout); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); // we weren't expecting to be + // interrupted + } + synchronized (this) { + checkError(); + if (thread != null) + throw new InterruptedIOException(); + } + } + + /** + * Returns the number of unread bytes in the buffer. + * + * @throws IOException + * if an i/o error occurs + */ + public synchronized int available() throws IOException { + if (length == 0) + checkError(); + return length > 0 ? length : 0; + } + + /** + * Reads a byte from the stream. + * + * @throws InterruptedIOException + * if the timeout expired and no data was received, + * bytesTransferred will be zero + * @throws IOException + * if an i/o error occurs + */ + public synchronized int read() throws IOException { + if (!syncFill()) + return -1; // EOF reached + int b = iobuffer[head++] & 255; + if (head == iobuffer.length) + head = 0; + length--; + notify(); + return b; + } + + /** + * Reads multiple bytes from the stream. + * + * @throws InterruptedIOException + * if the timeout expired and no data was received, + * bytesTransferred will be zero + * @throws IOException + * if an i/o error occurs + */ + public synchronized int read(byte[] buffer, int off, int len) throws IOException { + if (!syncFill()) + return -1; // EOF reached + int pos = off; + if (len > length) + len = length; + while (len-- > 0) { + buffer[pos++] = iobuffer[head++]; + if (head == iobuffer.length) + head = 0; + length--; + } + notify(); + return pos - off; + } + + /** + * Skips multiple bytes in the stream. + * + * @throws InterruptedIOException + * if the timeout expired before all of the bytes specified have + * been skipped, bytesTransferred may be non-zero + * @throws IOException + * if an i/o error occurs + */ + public synchronized long skip(long count) throws IOException { + long amount = 0; + try { + do { + if (!syncFill()) + break; // EOF reached + int skip = (int) Math.min(count - amount, length); + head = (head + skip) % iobuffer.length; + length -= skip; + amount += skip; + } while (amount < count); + } catch (InterruptedIOException e) { + e.bytesTransferred = (int) amount; // assumes amount < + // Integer.MAX_INT + throw e; + } + notify(); + return amount; + } + + /** + * Mark is not supported by the wrapper even if the underlying stream does, + * returns false. + */ + public boolean markSupported() { + return false; + } + + /** + * Waits for the buffer to fill if it is empty and the stream has not + * reached EOF. + * + * @return true if bytes are available, false if EOF has been reached + * @throws InterruptedIOException + * if EOF not reached but no bytes are available + */ + private boolean syncFill() throws IOException { + if (length != 0) + return true; + checkError(); // check errors only after we have read all remaining + // bytes + if (waitingForClose) + return false; + notify(); + try { + wait(readTimeout); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); // we weren't expecting to be + // interrupted + } + if (length != 0) + return true; + checkError(); // check errors only after we have read all remaining + // bytes + if (waitingForClose) + return false; + throw new InterruptedIOException(); + } + + /** + * If an exception is pending, throws it. + */ + private void checkError() throws IOException { + if (ioe != null) { + IOException e = ioe; + ioe = null; + throw e; + } + } + + /** + * Runs the thread in the background. + */ + void runThread() { + try { + readUntilDone(); + } catch (IOException e) { + synchronized (this) { + ioe = e; + } + } finally { + waitUntilClosed(); + try { + in.close(); + } catch (IOException e) { + synchronized (this) { + ioe = e; + } + } finally { + synchronized (this) { + thread = null; + notify(); + } + } + } + } + + /** + * Waits until we have been requested to close the stream. + */ + private synchronized void waitUntilClosed() { + waitingForClose = true; + notify(); + while (!closeRequested) { + try { + wait(); + } catch (InterruptedException e) { + closeRequested = true; // alternate quit signal + } + } + } + + /** + * Reads bytes into the buffer until EOF, closed, or error. + */ + private void readUntilDone() throws IOException { + for (;;) { + int off, len; + synchronized (this) { + while (isBufferFull()) { + if (closeRequested) + return; // quit signal + waitForRead(); + } + off = (head + length) % iobuffer.length; + len = ((head > off) ? head : iobuffer.length) - off; + } + int count; + try { + // the i/o operation might block without releasing the lock, + // so we do this outside of the synchronized block + count = in.read(iobuffer, off, len); + if (count == -1) + return; // EOF encountered + } catch (InterruptedIOException e) { + count = e.bytesTransferred; // keep partial transfer + } + synchronized (this) { + length += count; + notify(); + } + } + } + + /* + * Wait for a read when the buffer is full (with the implication that space + * will become available in the buffer after the read takes place). + */ + private synchronized void waitForRead() { + try { + if (growWhenFull) { + // wait a second before growing to let reads catch up + wait(readTimeout); + } else { + wait(); + } + } catch (InterruptedException e) { + closeRequested = true; // alternate quit signal + } + // If the buffer is still full, give it a chance to grow + if (growWhenFull && isBufferFull()) { + growBuffer(); + } + } + + private synchronized void growBuffer() { + int newSize = 2 * iobuffer.length; + if (newSize > iobuffer.length) { + byte[] newBuffer = new byte[newSize]; + int pos = 0; + int len = length; + while (len-- > 0) { + newBuffer[pos++] = iobuffer[head++]; + if (head == iobuffer.length) + head = 0; + } + iobuffer = newBuffer; + head = 0; + // length instance variable was not changed by this method + } + } + + private boolean isBufferFull() { + return length == iobuffer.length; + } +} From 4026e9cd9c003f44e9819b5c4946e8a9ce1e5a78 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 13 Dec 2025 16:02:46 +0000 Subject: [PATCH 4/4] Remove P2SSLContextFactory that depends on ECF interface Co-authored-by: laeubi <1331477+laeubi@users.noreply.github.com> --- .../p2/transport/ecf/P2SSLContextFactory.java | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java diff --git a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java b/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java deleted file mode 100644 index 4cfd64597c..0000000000 --- a/bundles/org.eclipse.equinox.p2.transport.native/src/org/eclipse/equinox/internal/p2/transport/ecf/P2SSLContextFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2025 Christoph Läubrich and others. - * The code, documentation and other materials contained herein have been - * licensed under the Eclipse Public License - v 1.0 by the copyright holder - * listed above, as the Initial Contributor under such license. The text of - * such license is available at www.eclipse.org. - * Contributors: - * Christoph Läubrich - initial implementation - ******************************************************************************/ -package org.eclipse.equinox.internal.p2.transport.ecf; - -import java.security.*; -import javax.net.ssl.SSLContext; -import org.eclipse.ecf.core.security.SSLContextFactory; -import org.osgi.framework.Constants; -import org.osgi.service.component.annotations.Component; - -@Component(property = Constants.SERVICE_RANKING + ":Integer=100") -public class P2SSLContextFactory implements SSLContextFactory { - - @Override - public SSLContext getDefault() throws NoSuchAlgorithmException { - // the default is guaranteed to be initialized always - return SSLContext.getDefault(); - } - - @Override - public SSLContext getInstance(String protocol) throws NoSuchAlgorithmException, NoSuchProviderException { - SSLContext context = SSLContext.getInstance(protocol); - try { - // init it as we have a new context here - context.init(null, null, null); - } catch (KeyManagementException e) { - throw new NoSuchProviderException(); - } - return context; - } - - @Override - public SSLContext getInstance(String protocol, String providerName) - throws NoSuchAlgorithmException, NoSuchProviderException { - SSLContext context = SSLContext.getInstance(protocol, providerName); - try { - // init it as we have a new context here - context.init(null, null, null); - } catch (KeyManagementException e) { - throw new NoSuchProviderException(); - } - return context; - } - -}