Initial contribution to Eclipse.org
diff --git a/.project b/.project
new file mode 100644
index 0000000..e0efa3a
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet-rj</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..c99f846
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,4 @@
+eclipse.preferences.version=1
+encoding//core/_build/org.eclipse.statet.rj.core/about.ini=ISO-8859-1
+encoding//eclient/org.eclipse.statet.rj.eclient.core/about.ini=ISO-8859-1
+encoding/<project>=UTF-8
diff --git a/.settings/org.eclipse.core.runtime.prefs b/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/.project b/core/_build/org.eclipse.statet.rj.core-feature/.project
new file mode 100644
index 0000000..39a2158
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.core-feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/build.properties b/core/_build/org.eclipse.statet.rj.core-feature/build.properties
new file mode 100644
index 0000000..4fc35c8
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes= feature.xml,\
+ feature.properties
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/feature.properties b/core/_build/org.eclipse.statet.rj.core-feature/feature.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/feature.properties
diff --git a/core/_build/org.eclipse.statet.rj.core-feature/feature.xml b/core/_build/org.eclipse.statet.rj.core-feature/feature.xml
new file mode 100644
index 0000000..3df684c
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core-feature/feature.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.statet.rj.core"
+ version="2.1.0.qualifier"
+ label="StatET RJ - Java Core"
+ provider-name="Eclipse.org"
+ license-feature="org.eclipse.license"
+ license-feature-version="1.0.1">
+
+ <description url="https://www.eclipse.org/statet">
+ Core of high-level Java-R library RJ
+ </description>
+
+ <copyright>
+ Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.
+ </copyright>
+
+ <license url="%license_url">
+ %license_text
+ </license>
+
+ <plugin
+ id="org.eclipse.statet.rj.core"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.statet.rj.data"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.statet.rj.server"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/core/_build/org.eclipse.statet.rj.core/.gitignore b/core/_build/org.eclipse.statet.rj.core/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/core/_build/org.eclipse.statet.rj.core/.project b/core/_build/org.eclipse.statet.rj.core/.project
new file mode 100644
index 0000000..89ad76e
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/_build/org.eclipse.statet.rj.core/META-INF/MANIFEST.MF b/core/_build/org.eclipse.statet.rj.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..cf22859
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/META-INF/MANIFEST.MF
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.core;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Java Core
diff --git a/core/_build/org.eclipse.statet.rj.core/about.html b/core/_build/org.eclipse.statet.rj.core/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/_build/org.eclipse.statet.rj.core/about.ini b/core/_build/org.eclipse.statet.rj.core/about.ini
new file mode 100644
index 0000000..a14498e
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/about.ini
@@ -0,0 +1,7 @@
+featureImage= rj32.png
+aboutText= \
+StatET RJ - Java Core\n\
+\n\
+Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.\n\
+Visit https://www.eclipse.org/statet\n\
+\n\
diff --git a/core/_build/org.eclipse.statet.rj.core/build.properties b/core/_build/org.eclipse.statet.rj.core/build.properties
new file mode 100644
index 0000000..7d15c10
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/build.properties
@@ -0,0 +1,4 @@
+bin.includes= META-INF/,\
+ about.html,\
+ about.ini,\
+ rj32.png
diff --git a/core/_build/org.eclipse.statet.rj.core/rj32.png b/core/_build/org.eclipse.statet.rj.core/rj32.png
new file mode 100644
index 0000000..d9450d1
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.core/rj32.png
Binary files differ
diff --git a/core/_build/org.eclipse.statet.rj.server-consoleserver/pom.xml b/core/_build/org.eclipse.statet.rj.server-consoleserver/pom.xml
new file mode 100644
index 0000000..0bfc76c
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.server-consoleserver/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>rj-core</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.eclipse.statet.rj-packaging</groupId>
+ <artifactId>org.eclipse.statet.rj.core-consoleserver</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.data</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>eclipse-plugin</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.server</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>eclipse-plugin</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.server.remotetools</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>eclipse-plugin</type>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ <executions>
+ <execution>
+ <id>pack-server</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>server.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/core/_build/org.eclipse.statet.rj.server-consoleserver/server.xml b/core/_build/org.eclipse.statet.rj.server-consoleserver/server.xml
new file mode 100644
index 0000000..eecd8c6
--- /dev/null
+++ b/core/_build/org.eclipse.statet.rj.server-consoleserver/server.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>distr</id>
+
+ <formats>
+ <format>tar.gz</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+
+ <fileSets>
+ <fileSet>
+ <outputDirectory>/</outputDirectory>
+ <directory>../../org.eclipse.statet.rj.remotetools</directory>
+ <includes>
+ <include>startup.sh</include>
+ </includes>
+ <fileMode>755</fileMode>
+ </fileSet>
+ </fileSets>
+
+ <dependencySets>
+ <dependencySet>
+ <outputDirectory>/</outputDirectory>
+ <useTransitiveDependencies>false</useTransitiveDependencies>
+ <includes>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.remotetools</include>
+ </includes>
+ <unpack>true</unpack>
+ <unpackOptions>
+ <excludes>
+ <exclude>startup.sh</exclude>
+ <exclude>META-INF/**</exclude>
+ </excludes>
+ </unpackOptions>
+ </dependencySet>
+ <dependencySet>
+ <outputDirectory>/</outputDirectory>
+ <useTransitiveDependencies>false</useTransitiveDependencies>
+ <includes>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.data</include>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.server</include>
+ </includes>
+ <outputFileNameMapping>${artifact.artifactId}.${artifact.extension}</outputFileNameMapping>
+ </dependencySet>
+ </dependencySets>
+
+</assembly>
diff --git a/core/org.eclipse.statet.rj.client/.classpath b/core/org.eclipse.statet.rj.client/.classpath
new file mode 100644
index 0000000..465ce24
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+ <attributes>
+ <attribute name="owner.project.facets" value="java"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="srcRSetups"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.client/.gitignore b/core/org.eclipse.statet.rj.client/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/core/org.eclipse.statet.rj.client/.project b/core/org.eclipse.statet.rj.client/.project
new file mode 100644
index 0000000..20b6194
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.project
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.client</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..fba8ab5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="org.eclipse.statet.rj.client">
+ <wb-resource deploy-path="/" source-path="/src"/>
+ </wb-module>
+</project-modules>
diff --git a/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..a1f5f3c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <fixed facet="java"/>
+ <fixed facet="jst.utility"/>
+ <installed facet="java" version="1.8"/>
+ <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.client/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.client/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..19dae44
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.client;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Client Implementation
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)"
+Import-Package: org.osgi.framework;version="1.8.0",
+ org.eclipse.core.runtime
+Export-Package: org.eclipse.statet.rj.rsetups;version="3.0.0",
+ org.eclipse.statet.rj.server.client
diff --git a/core/org.eclipse.statet.rj.client/about.html b/core/org.eclipse.statet.rj.client/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.client/build.properties b/core/org.eclipse.statet.rj.client/build.properties
new file mode 100644
index 0000000..5ce0c73
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/build.properties
@@ -0,0 +1,9 @@
+source..= src/,\
+ srcRSetups/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ .,\
+ about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClient.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClient.java
new file mode 100644
index 0000000..619e4a2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClient.java
@@ -0,0 +1,1798 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.MISSING_ANSWER_STATUS;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.OutputStream;
+import java.rmi.ConnectException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.eclipse.core.runtime.CoreException;
+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.statet.rj.RjException;
+import org.eclipse.statet.rj.data.REnvironment;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.server.BinExchange;
+import org.eclipse.statet.rj.server.ComHandler;
+import org.eclipse.statet.rj.server.ConsoleReadCmdItem;
+import org.eclipse.statet.rj.server.CtrlCmdItem;
+import org.eclipse.statet.rj.server.DataCmdItem;
+import org.eclipse.statet.rj.server.DataCmdItem.Operation;
+import org.eclipse.statet.rj.server.DbgCmdItem;
+import org.eclipse.statet.rj.server.DbgCmdItem.CustomDataReader;
+import org.eclipse.statet.rj.server.ExtUICmdItem;
+import org.eclipse.statet.rj.server.GDCmdItem;
+import org.eclipse.statet.rj.server.GraOpCmdItem;
+import org.eclipse.statet.rj.server.MainCmdC2SList;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.MainCtrlCmdItem;
+import org.eclipse.statet.rj.server.REngine;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.RjsPing;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.client.RClientGraphic.InitConfig;
+import org.eclipse.statet.rj.server.dbg.CtrlReport;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Generic RJ Com protocol client for servers offering a {@link REngine}.
+ * <p>
+ * It offers basic implementation for most methods of the {@link RService} API,
+ * including:</p>
+ * <ul>
+ * <li>Expression evaluation</li>
+ * <li>Data exchange to assign or eval/read {@link RObject}</li>
+ * <li>File exchange to write/read file on the server (must be enabled at server side)</li>
+ * <li>R graphics (requires an {@link RClientGraphicFactory}, set in {@link #initGraphicFactory()},
+ * or via {@link #setGraphicFactory(RClientGraphicFactory, RClientGraphicActions)})</li>
+ * <li>Console (REPL), if connected to server slot 0</li>
+ * </ul>
+ * <p>
+ * If offers two mechanisms allowing the usage of RService API and R thread when they are already
+ * used by a regular call. So the two modes allows to "hijack" the R thread to "inject" additional
+ * calls to the RService API:</p>
+ * <ul>
+ * <li>Hot Mode: Enables to run code in any situation, also if R is busy. Nesting of hot modes is
+ * not possible. It can be requested asynchronous from any thread. The hot mode is appropriate
+ * for e.g. short task for the GUI.</li>
+ * <li>Extra Mode: Enables to run code at the before or after of a client-server communication.
+ * Must be requested synchronous from the R thread.</li>
+ * </ul>
+ */
+public abstract class AbstractRJComClient implements ComHandler {
+
+
+ public static final String RJ_CLIENT_ID= "org.eclipse.statet.rj.client";
+
+ public static int[] version() {
+ return new int[] { 2, 1, 0 };
+ }
+
+ public static final int EXTRA_BEFORE= 1;
+ public static final int EXTRA_NESTED= 2;
+
+ private static final ScheduledExecutorService RJHelper_EXECUTOR =
+ Executors.newSingleThreadScheduledExecutor(new DaemonThreadFactory("RJHelper"));
+
+ private static final Random RAND= new Random();
+
+
+ private static class DummyFactory implements RClientGraphicFactory {
+
+ @Override
+ public Map<String, ? extends Object> getInitServerProperties() {
+ return null;
+ }
+
+ @Override
+ public RClientGraphic newGraphic(final int devId, final double w, final double h,
+ final InitConfig config,
+ final boolean active, final RClientGraphicActions actions, final int options) {
+ return new RClientGraphicDummy(devId, w, h);
+ }
+
+ @Override
+ public void closeGraphic(final RClientGraphic graphic) {
+ }
+
+ }
+
+ private final static class RunnableList {
+
+ private Runnable[] array;
+ private int size;
+
+ public RunnableList() {
+ this.array= new Runnable[4];
+ this.size= 0;
+ }
+
+
+ public void add(final Runnable value) {
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+ final int oldCapacity= this.array.length;
+ if (this.size < oldCapacity) {
+ this.array[this.size++]= value;
+ return;
+ }
+ final Runnable[] newArray= new Runnable[oldCapacity + 4];
+ System.arraycopy(this.array, 0, newArray, 0, oldCapacity);
+ newArray[this.size++]= value;
+ this.array= newArray;
+ }
+
+ public boolean isNotEmpty() {
+ return (this.size != 0);
+ }
+
+ public Runnable[] consume() {
+ final Runnable[] oldListeners= this.array;
+ this.size= 0;
+ this.array= new Runnable[4];
+ return oldListeners;
+ }
+
+ }
+
+
+ private class KeepAliveRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ runAsyncPing();
+ }
+
+ }
+
+ private class HotModeRequestRunnable implements Runnable {
+
+ @Override
+ public void run() {
+ if (AbstractRJComClient.this.hotModeRequested.get()) {
+ try {
+ runAsyncCtrl(CtrlCmdItem.REQUEST_HOT_MODE);
+ }
+ catch (final CoreException e) {
+ if (e.getStatus().getSeverity() != IStatus.CANCEL) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when requesting hot mode.", e));
+ }
+ }
+ }
+ }
+ }
+
+
+ private RService rService;
+ private Object rHandle;
+
+ private IProgressMonitor progressMonitor;
+
+ private final RJIO mainIO= new RJIO();
+ private MainCmdItem mainC2SFirst;
+ private final MainCmdC2SList mainC2SList= new MainCmdC2SList(this.mainIO);
+ private final RunnableList mainDeferredCmds= new RunnableList();
+ private boolean mainRunGC;
+
+ private boolean consoleReadCallbackRequired;
+ private ConsoleReadCmdItem consoleReadCallback;
+
+ private final Object platformLock= new Object();
+ private Map<String, Object> platformData;
+ private RPlatform platformObj;
+
+ private final byte randomId= (byte) (0xff & RAND.nextInt(255));
+
+ private int dataLevelRequest= 0;
+ private int dataLevelAnswer= 0;
+ private int dataLevelIgnore= 0;
+ private byte dataRequestCounter= (byte) (0xff & RAND.nextInt(255));
+ private final int[] dataRequestId= new int[32];
+ private final MainCmdItem[] dataAnswer= new MainCmdItem[32];
+
+ private boolean runFinishTask;
+
+ private boolean dbgOpRequest;
+ private DbgCmdItem dbgOpAnswer;
+ private CustomDataReader dbgOpCustomReader;
+
+ private int hotModeState;
+ private ConsoleReadCmdItem hotModeReadCallbackBackup;
+ private MainCmdItem hotModeC2SFirstBackup;
+ private final AtomicBoolean hotModeRequested= new AtomicBoolean();
+ private final Runnable hotModeRunnable= new HotModeRequestRunnable();
+
+ private int extraModeRequested;
+
+ private RClientGraphicFactory graphicFactory;
+ private RClientGraphicActions graphicActions;
+ private final RClientGraphic graphicDummy= new RClientGraphicDummy(1, 0, 0);
+ private RClientGraphic[] graphics= new RClientGraphic[16];
+ private int currentGraphicOptions;
+ private RClientGraphic lastGraphic;
+
+ private REngine rjConsoleEngine;
+
+ private List<Runnable> defferedRunnables;
+
+ private boolean closed;
+ private ScheduledFuture<?> keepAliveJob;
+ private String closedMessage= "Connection to R engine is closed.";
+
+ private final Lock clientWaitLock= new ReentrantLock();
+ private final Condition clientWaitCondition= this.clientWaitLock.newCondition();
+ private final List<Callable<Boolean>> cancelHandler= new ArrayList<>();
+
+
+ protected AbstractRJComClient() {
+ }
+
+
+ public void initClient(final Object rHandle, final RService r,
+ final Map<String, Object> properties, final int id) {
+ this.rHandle= rHandle;
+ this.rService= r;
+ properties.put("rj.com.init", Boolean.TRUE); //$NON-NLS-1$
+ properties.put(RjsComConfig.RJ_COM_S2C_ID_PROPERTY_ID, id);
+
+ try {
+ initGraphicFactory();
+ }
+ catch (final Exception e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when initializing R client graphic factory.", e));
+ }
+ if (this.graphicFactory != null) {
+ final Map<String, ? extends Object> additional= this.graphicFactory.getInitServerProperties();
+ if (additional != null) {
+ properties.putAll(additional);
+ }
+ }
+ else {
+ this.graphicFactory= new DummyFactory();
+ log(new Status(IStatus.WARNING, RJ_CLIENT_ID, -1, "No R client graphic factory configured.", null));
+ }
+ }
+
+ public void setDbgCustomCmdReader(final DbgCmdItem.CustomDataReader reader) {
+ this.dbgOpCustomReader= reader;
+ }
+
+ public final void setServer(final REngine rjServer, final int client) {
+ final List<Runnable> runnables;
+ synchronized (this) {
+ this.rjConsoleEngine= rjServer;
+ if (client == 0) {
+ long t= 45 * 1000;
+ try {
+ final String p= System.getProperty("org.eclipse.statet.rj.client.keepaliveInterval"); //$NON-NLS-1$
+ if (p != null && p.length() > 0) {
+ t= Long.parseLong(p);
+ }
+ }
+ catch (final Exception e) {}
+ this.keepAliveJob= RJHelper_EXECUTOR.scheduleWithFixedDelay(
+ new KeepAliveRunnable(), t, t, TimeUnit.MILLISECONDS );
+ }
+ runnables= this.defferedRunnables;
+ this.defferedRunnables= null;
+ }
+ if (runnables != null) {
+ for (int i= 0; i < runnables.size(); i++) {
+ RJHelper_EXECUTOR.execute(runnables.get(i));
+ }
+ }
+ }
+
+ public Object getRHandle() {
+ return this.rHandle;
+ }
+
+ public RService getRService() {
+ return this.rService;
+ }
+
+ public final REngine getConsoleEngine() {
+ return this.rjConsoleEngine;
+ }
+
+ protected void execAsync(final Runnable runnable) {
+ synchronized (this) {
+ if (this.rjConsoleEngine == null) {
+ if (this.defferedRunnables == null) {
+ this.defferedRunnables= new ArrayList<>(8);
+ }
+ this.defferedRunnables.add(runnable);
+ return;
+ }
+ }
+ RJHelper_EXECUTOR.execute(runnable);
+ }
+
+ protected void initGraphicFactory() {
+ }
+
+
+ public final void setGraphicFactory(final RClientGraphicFactory factory, final RClientGraphicActions actions) {
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ this.graphicFactory= factory;
+ this.graphicActions= actions;
+ }
+
+ public boolean isClosed() {
+ return this.closed;
+ }
+
+ public void setClosed(final boolean closed) {
+ if (this.closed != closed) {
+ this.closed= closed;
+ if (closed) {
+ final ScheduledFuture<?> job= this.keepAliveJob;
+ if (job != null) {
+ this.keepAliveJob= null;
+ job.cancel(true);
+ }
+ }
+ }
+ }
+
+ public void setRjsProperties(final Map<String, ? extends Object> properties) throws CoreException {
+ try {
+ this.rjConsoleEngine.setProperties(properties);
+ }
+ catch (final RemoteException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, "An error occurred when setting server properties.", e));
+ }
+ }
+
+
+ @Override
+ public final void processMainCmd(final ObjectInput in) throws IOException {
+ boolean runGC= false;
+ updateBusy(in.readBoolean());
+ if (this.hotModeState == 4) {
+ this.hotModeState= 0;
+ this.consoleReadCallback= this.hotModeReadCallbackBackup;
+ this.hotModeReadCallbackBackup= null;
+ if (this.hotModeC2SFirstBackup != null) {
+ addC2SCmd(this.hotModeC2SFirstBackup);
+ this.hotModeC2SFirstBackup= null;
+ }
+ }
+
+ this.mainIO.connect(in);
+ final int check= this.mainIO.readCheck1();
+
+ while (true) {
+ final byte type= in.readByte();
+ switch (type) {
+ case MainCmdItem.T_NONE:
+ this.mainIO.readCheck2(check);
+ this.mainIO.disconnect(in);
+ this.mainRunGC= runGC;
+ return;
+ case MainCmdItem.T_CONSOLE_READ_ITEM:
+ processPrompt(new ConsoleReadCmdItem(this.mainIO));
+ continue;
+ case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+ runGC= true;
+ writeConsoleOutput(this.mainIO.readByte(), this.mainIO.readString());
+ continue;
+ case MainCmdItem.T_MESSAGE_ITEM:
+ runGC= true;
+ showMessage(this.mainIO.readString());
+ continue;
+ case MainCmdItem.T_EXTENDEDUI_ITEM:
+ runGC= true;
+ processUICallback(this.mainIO);
+ continue;
+ case MainCmdItem.T_GRAPH_ITEM:
+ runGC= true;
+ processGDCmd(this.mainIO);
+ continue;
+ case MainCmdItem.T_MAIN_CTRL_ITEM:
+ runGC= true;
+ processMainCtrlCmd(this.mainIO);
+ continue;
+ case MainCmdItem.T_DATA_ITEM:
+ runGC= true;
+ processDataCmd(this.mainIO);
+ continue;
+ case MainCmdItem.T_GRAPHICS_OP_ITEM:
+ runGC= true;
+ processGraphicsOpCmd(this.mainIO);
+ continue;
+ case MainCmdItem.T_DBG_ITEM:
+ runGC= true;
+ processDbgCmd(this.mainIO);
+ continue;
+ default:
+ this.mainIO.disconnect(in);
+ throw new IOException("Unknown cmdtype id: " + type);
+ }
+ }
+ }
+
+ private final void processCmdDeferred(final Runnable runnable) {
+ this.mainDeferredCmds.add(runnable);
+ }
+
+
+ public final boolean processUICallback(final RJIO io) throws IOException {
+ final ExtUICmdItem item= new ExtUICmdItem(io);
+ try {
+ final RList answer= handleUICallback(item.getDataText(), item.getDataArgs(),
+ this.progressMonitor);
+ item.setAnswer(answer);
+ }
+ catch (final IOException e) {
+ throw e;
+ }
+ catch (final Exception e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when exec RJ UI command '" + item.getDataText() + "'.", e));
+ if (item.waitForClient()) {
+ item.setAnswer(new RjsStatus(RjsStatus.ERROR, 0, "Client error processing current command."));
+ }
+ }
+ if (item.waitForClient()) {
+ addC2SCmd(item);
+ return true;
+ }
+ return false;
+ }
+
+ protected RList handleUICallback(final String commandId, final RList args,
+ final IProgressMonitor monitor) throws Exception {
+ throw new CoreException(new Status(IStatus.WARNING, RJ_CLIENT_ID, -1, "Unhandled RJ UI command '" + commandId + "'.", null));
+ }
+
+
+ public final void processGDCmd(final RJIO io) throws IOException {
+ final int devId;
+ final int options;
+ { final int i= io.readInt();
+ options= (i & MainCmdItem.OV_WAITFORCLIENT);
+ devId= (i & ~MainCmdItem.OV_WAITFORCLIENT);
+ }
+ byte requestId= -1;
+ try {
+ switch (io.readByte()) {
+ case GDCmdItem.C_NEW_PAGE:
+ addGraphic(devId,
+ io.readDouble(),
+ io.readDouble(),
+ io.readInt(),
+ io.readBoolean() );
+ return;
+ case GDCmdItem.C_CLOSE_DEVICE:
+ removeGraphic(devId);
+ return;
+ case GDCmdItem.C_GET_SIZE:
+ addC2SCmd(new GDCmdItem.DoubleAnswer(requestId= io.readByte(),
+ devId, getGraphic(devId).computeSize() ));
+ return;
+ case GDCmdItem.C_SET_ACTIVE_OFF:
+ getGraphic(devId).setActive(false);
+ return;
+ case GDCmdItem.C_SET_ACTIVE_ON:
+ getGraphic(devId).setActive(true);
+ return;
+ case GDCmdItem.C_SET_MODE:
+ getGraphic(devId).setMode(io.readByte());
+ return;
+ case GDCmdItem.C_GET_FONTMETRIC:
+ addC2SCmd(new GDCmdItem.DoubleAnswer(requestId= io.readByte(),
+ devId, getGraphic(devId).computeFontMetric(
+ io.readInt() )));
+ return;
+ case GDCmdItem.C_GET_STRINGWIDTH:
+ addC2SCmd(new GDCmdItem.DoubleAnswer(requestId= io.readByte(),
+ devId, getGraphic(devId).computeStringWidth(
+ io.readString() )));
+ return;
+
+ case GDCmdItem.SET_CLIP:
+ getGraphic(devId).addSetClip(
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble() );
+ return;
+ case GDCmdItem.SET_COLOR:
+ getGraphic(devId).addSetColor(
+ io.readInt() );
+ return;
+ case GDCmdItem.SET_FILL:
+ getGraphic(devId).addSetFill(
+ io.readInt() );
+ return;
+ case GDCmdItem.SET_LINE:
+ getGraphic(devId).addSetLine(
+ io.readInt(),
+ io.readFloat(),
+ io.readByte(),
+ io.readByte(),
+ io.readFloat() );
+ return;
+ case GDCmdItem.SET_FONT:
+ getGraphic(devId).addSetFont(
+ io.readString(),
+ io.readInt(),
+ io.readFloat(),
+ io.readFloat() );
+ return;
+
+ case GDCmdItem.DRAW_LINE:
+ getGraphic(devId).addDrawLine(
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble() );
+ return;
+ case GDCmdItem.DRAW_RECTANGLE:
+ getGraphic(devId).addDrawRect(
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble() );
+ return;
+ case GDCmdItem.DRAW_POLYLINE:
+ getGraphic(devId).addDrawPolyline(
+ io.readDoubleArray(),
+ io.readDoubleArray2() );
+ return;
+ case GDCmdItem.DRAW_POLYGON:
+ getGraphic(devId).addDrawPolygon(
+ io.readDoubleArray(),
+ io.readDoubleArray2() );
+ return;
+ case GDCmdItem.DRAW_PATH:
+ getGraphic(devId).addDrawPath(
+ io.readIntArray(),
+ io.readDoubleArray(),
+ io.readDoubleArray2(),
+ io.readInt() );
+ return;
+ case GDCmdItem.DRAW_CIRCLE:
+ getGraphic(devId).addDrawCircle(
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble() );
+ return;
+ case GDCmdItem.DRAW_TEXT:
+ getGraphic(devId).addDrawText(
+ io.readString(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble() );
+ return;
+ case GDCmdItem.DRAW_RASTER:
+ getGraphic(devId).addDrawRaster(
+ io.readByteArray(),
+ io.readBoolean(),
+ io.readInt(),
+ io.readInt(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readDouble(),
+ io.readBoolean() );
+ return;
+
+ case GDCmdItem.CAPTURE:
+ addC2SCmd(new GDCmdItem.Answer(requestId= io.readByte(),
+ devId, getGraphic(devId).capture(
+ io.readInt(),
+ io.readInt() )));
+ return;
+
+ case GDCmdItem.U_LOCATOR: {
+ final byte fid= requestId= io.readByte();
+ processCmdDeferred(new Runnable() {
+ @Override
+ public void run() {
+ addC2SCmd(new GDCmdItem.DoubleAnswer(fid,
+ devId, getGraphic(devId).runRLocator(
+ AbstractRJComClient.this.rService,
+ AbstractRJComClient.this.progressMonitor )));
+ }
+ });
+ return; }
+
+ default:
+ if ((options & MainCmdItem.OV_WAITFORCLIENT) != 0) {
+ requestId= io.readByte();
+ }
+ throw new UnsupportedOperationException("Unknown GD command.");
+ }
+ }
+ catch (final IOException e) {
+ throw e;
+ }
+ catch (final Throwable e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing graphic command.", e));
+ if (requestId >= 0) {
+ addC2SCmd(new GDCmdItem.Answer(requestId, devId, new RjsStatus(RjsStatus.ERROR, 0)));
+ }
+// throw new RuntimeException(e);
+ }
+ }
+
+
+ private final void processMainCtrlCmd(final RJIO io) throws IOException {
+ try {
+ final MainCtrlCmdItem item= new MainCtrlCmdItem(io);
+ addDataAnswer(item);
+ }
+ catch (final IOException e) {
+ throw e;
+ }
+ catch (final Exception e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing control command answer.", e));
+ }
+ }
+
+ private final void processDataCmd(final RJIO io) throws IOException {
+ try {
+ final DataCmdItem item= new DataCmdItem(io);
+ addDataAnswer(item);
+ }
+ catch (final IOException e) {
+ throw e;
+ }
+ catch (final Exception e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing data command answer.", e));
+ }
+ }
+
+ private final void processGraphicsOpCmd(final RJIO io) throws IOException {
+ try {
+ final GraOpCmdItem item= new GraOpCmdItem(io);
+ addDataAnswer(item);
+ }
+ catch (final IOException e) {
+ throw e;
+ }
+ catch (final Exception e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when processing graphic operation answer.", e));
+ }
+ }
+
+ private final int newDataLevel() {
+ final int level= ++this.dataLevelRequest;
+ if (level >= this.dataAnswer.length) {
+ this.dataLevelRequest--;
+ throw new UnsupportedOperationException("too much nested operations");
+ }
+ this.dataLevelAnswer= 0;
+
+ return level;
+ }
+
+ private final MainCmdItem createDataRequestId(final int level, final MainCmdItem item) {
+ this.dataRequestId[level]= ((((0xff) & item.getCmdType()) << 24)
+ | ((0xff & item.getOp()) << 16)
+ | ((0xff & this.randomId << 8))
+ | ((0xff & ++this.dataRequestCounter)) );
+ item.requestId= (((0xff & level) << 24) | (0xffffff & this.dataRequestId[level]));
+ return item;
+ }
+
+ private final void addDataAnswer(final MainCmdItem item) throws RjException {
+ final int level= (((0xff000000) & item.requestId) >>> 24);
+ if (level > 0 && level <= this.dataLevelRequest
+ && this.dataRequestId[level] == (((0xff & item.getCmdType()) << 24)
+ | (0xffffff & item.requestId)) ) {
+ this.dataAnswer[level]= item;
+ this.dataLevelAnswer= level;
+ return;
+ }
+ if ((item.requestId & 0xff00 >>> 8) != (this.randomId & 0xff)) {
+ // other client
+// System.out.println("Other client: " + item);
+ return;
+ }
+ throw new RjException("Unexpected server answer: " + item);
+ }
+
+ private final void finalizeDataLevel() {
+ final int level= this.dataLevelRequest--;
+ this.dataAnswer[level]= null;
+ this.dataLevelAnswer= (this.dataAnswer[this.dataLevelRequest] != null) ? this.dataLevelRequest : 0;
+
+ this.runFinishTask= true;
+ }
+
+ public final int getDataLevel() {
+ return this.dataLevelRequest;
+ }
+
+
+ protected final void processDbgCmd(final RJIO io) throws IOException {
+ final DbgCmdItem item= new DbgCmdItem(io, this.dbgOpCustomReader);
+ if (item.getOp() > DbgCmdItem.OP_C2S_S2C) {
+ handleDbgEvent(item.getOp(), item.getData());
+ }
+ else if (this.dbgOpRequest) {
+ this.dbgOpAnswer= item;
+ }
+ }
+
+ protected void handleDbgEvent(final byte dbgOp, final Object event) {
+ }
+
+
+ protected abstract void log(IStatus status);
+
+ protected abstract void handleServerStatus(final RjsStatus serverStatus, final IProgressMonitor monitor) throws CoreException;
+
+ protected abstract void handleStatus(Status status, IProgressMonitor monitor);
+
+ protected void scheduleConnectionCheck() {
+ }
+
+
+ public final boolean runAsyncPing() {
+ try {
+ final RjsComObject answer= this.rjConsoleEngine.runAsync(RjsPing.INSTANCE);
+ if (answer instanceof RjsStatus) {
+ final RjsStatus status= (RjsStatus) answer;
+ if (status.getSeverity() == RjsStatus.OK) {
+ return true;
+ }
+ scheduleConnectionCheck();
+ }
+ }
+ catch (final ConnectException e) {
+ scheduleConnectionCheck();
+ }
+ catch (final RemoteException e) {
+ // TODO if (rmiregistry is available) scheduleCheck();
+ // no need to log here
+ }
+ catch (final Exception e) {
+ }
+ return false;
+ }
+
+ public final boolean runAsyncInterrupt() {
+ final Callable<Boolean>[] handlers= getCancelHandlers();
+ for (int i= handlers.length - 1; i >= 0; i--) {
+ try {
+ final Boolean done= handlers[i].call();
+ if (done != null && done.booleanValue()) {
+ return false;
+ }
+ }
+ catch (final Exception e) {
+ // handler failed
+ }
+ }
+ final IProgressMonitor monitor= this.progressMonitor;
+ if (monitor != null) {
+ monitor.setCanceled(true);
+ }
+ try {
+ runAsyncCtrl(CtrlCmdItem.REQUEST_CANCEL);
+ return true;
+ }
+ catch (final CoreException e) {
+ if (e.getStatus().getSeverity() != IStatus.CANCEL) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "An error occurred when trying to interrupt R.", e));
+ }
+ return false;
+ }
+ }
+
+ public final void runAsyncCtrl(final int id) throws CoreException {
+ final RjsStatus status= (RjsStatus) runAsync(new CtrlCmdItem(id));
+ if (status.getSeverity() != RjsStatus.OK) {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Executing CTRL command failed.", null));
+ }
+ }
+
+ public final RjsComObject runAsync(final RjsComObject com) throws CoreException {
+ if (this.closed) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0, this.closedMessage, null));
+ }
+ try {
+ return this.rjConsoleEngine.runAsync(com);
+ }
+ catch (final Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0, "Communication error.", e));
+ }
+ }
+
+ public final void runMainLoopPing(final IProgressMonitor monitor) throws CoreException {
+ try {
+ this.mainRunGC= false;
+ final RjsStatus status= (RjsStatus) this.rjConsoleEngine.runMainLoop(RjsPing.INSTANCE);
+ if (status.getSeverity() == RjsStatus.OK) {
+ return;
+ }
+ handleServerStatus(status, monitor);
+ }
+ catch (final ConnectException e) {
+ handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_DISCONNECTED), monitor);
+ }
+ catch (final Exception e) {
+ // no need to log here
+ handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_LOST), monitor);
+ }
+ }
+
+ public final void runMainLoop(RjsComObject sendCom, MainCmdItem sendItem, final IProgressMonitor monitor) throws CoreException {
+ if (this.closed) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0, this.closedMessage, null));
+ }
+ final boolean loopReadCallbackIgnore= !this.consoleReadCallbackRequired;
+ final int loopDataLevelIgnore= this.dataLevelIgnore;
+ try {
+ if ((this.extraModeRequested & EXTRA_BEFORE) != 0 && this.hotModeState < 1) {
+ this.extraModeRequested= 0;
+ this.dataLevelIgnore= this.dataLevelRequest;
+ processExtraMode(EXTRA_BEFORE);
+ }
+ while (this.hotModeRequested.get()
+ && this.hotModeState < 1 && !this.dbgOpRequest) {
+ this.dataLevelIgnore= this.dataLevelRequest;
+ startHotMode();
+ }
+ this.progressMonitor= monitor;
+ int ok= 0;
+ while (!this.closed) {
+ try {
+ RjsComObject receivedCom= null;
+ if (sendItem != null) {
+ if (sendItem.getCmdType() == MainCmdItem.T_CONSOLE_READ_ITEM) {
+ this.consoleReadCallback= null;
+ }
+ this.mainC2SList.setObjects(sendItem);
+ sendCom= this.mainC2SList;
+ sendItem= null;
+ }
+ // System.out.println("client *-> server: " + sendCom);
+ this.mainRunGC= false;
+ receivedCom= this.rjConsoleEngine.runMainLoop(sendCom);
+ this.mainC2SList.clear();
+ sendCom= null;
+ // System.out.println("client *<- server: " + receivedCom);
+ switch (receivedCom.getComType()) {
+ case RjsComObject.T_PING:
+ ok= 0;
+ sendCom= RjsStatus.OK_STATUS;
+ continue;
+ case RjsComObject.T_MAIN_LIST:
+ if (this.mainDeferredCmds.isNotEmpty()) {
+ final Runnable[] runnables= this.mainDeferredCmds.consume();
+ for (int i= 0; i < runnables.length; i++) {
+ if (runnables[i] != null) {
+ try {
+ runnables[i].run();
+ }
+ catch (final Exception e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0,
+ "An error occurred when running a deferred command.", e ));
+ }
+ }
+ }
+ }
+ ok= 0;
+ switch (this.hotModeState) {
+ case 1:
+ sendCom= this.mainC2SList; // repeat
+ continue;
+ case 2:
+ this.hotModeState= 3;
+ this.hotModeRequested.set(false);
+ this.dataLevelIgnore= this.dataLevelRequest;
+ try {
+ processHotMode();
+ continue;
+ }
+ finally {
+ this.progressMonitor= monitor;
+ this.hotModeState= 4;
+ this.consoleReadCallback.setAnswer(RjsStatus.OK_STATUS);
+ sendItem= this.consoleReadCallback;
+ }
+ default:
+ while ((sendItem= getC2SCmds()) == null
+ && (loopReadCallbackIgnore || this.consoleReadCallback != null)
+ && (this.dataLevelRequest <= loopDataLevelIgnore
+ || this.dataLevelRequest == this.dataLevelAnswer
+ || (this.extraModeRequested & EXTRA_NESTED) != 0 )
+ && (this.dbgOpRequest == (this.dbgOpAnswer != null))) {
+ if (this.mainRunGC) {
+ this.mainRunGC= false;
+ this.rjConsoleEngine.runMainLoop(RjsPing.INSTANCE);
+ }
+ if ((this.extraModeRequested & EXTRA_NESTED) != 0 && this.hotModeState < 1) {
+ this.extraModeRequested= 0;
+ this.dataLevelIgnore= this.dataLevelRequest;
+ try {
+ processExtraMode(EXTRA_NESTED);
+ continue; // validate again
+ }
+ finally {
+ this.progressMonitor= monitor;
+ }
+ }
+ else {
+ return; // finished
+ }
+ }
+ continue;
+ }
+ case RjsComObject.T_STATUS:
+ ok= 0;
+ processStatus((RjsStatus) receivedCom, monitor);
+ sendCom= this.mainC2SList;
+ continue;
+ }
+ }
+ catch (final ConnectException e) {
+ handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_DISCONNECTED), monitor);
+ return;
+ }
+ catch (final RemoteException e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "Communication error detail. Send:\n"+sendCom, e));
+ if (!this.closed && runAsyncPing()) { // async to avoid server gc
+ if (this.consoleReadCallback == null && ok == 0) {
+ ok++;
+ handleStatus(new Status(IStatus.ERROR, RJ_CLIENT_ID, "Communication error, see Eclipse log for detail."), monitor);
+ continue;
+ }
+ throw new CoreException(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1, "Communication error.", e));
+ }
+ handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_LOST), monitor);
+ return;
+ }
+ }
+
+ handleServerStatus(new RjsStatus(RjsStatus.INFO, Server.S_DISCONNECTED), monitor);
+ }
+ finally {
+ this.dataLevelIgnore= loopDataLevelIgnore;
+ }
+ }
+
+
+ protected final void addC2SCmd(final MainCmdItem item) {
+ if (this.mainC2SFirst == null) {
+ this.mainC2SFirst= item;
+ }
+ else {
+ item.next= this.mainC2SFirst;
+ this.mainC2SFirst= item;
+
+ // TODO
+ log(new Status(IStatus.INFO, RJ_CLIENT_ID, "Multiple C2S items:\\" + this.mainC2SFirst.toString() + "\n" + this.mainC2SFirst.next.toString()));
+ }
+ }
+
+ private final MainCmdItem getC2SCmds() {
+ final MainCmdItem item= this.mainC2SFirst;
+ this.mainC2SFirst= null;
+ return item;
+ }
+
+ private final void processStatus(final RjsStatus status, final IProgressMonitor monitor)
+ throws CoreException {
+ if ((status.getCode() & 0xffffff00) == 0) {
+ handleServerStatus(status, monitor);
+ return;
+ }
+ if (status.getSeverity() != RjsStatus.OK) {
+ // TODO
+// System.out.println(status);
+ }
+ }
+
+ private final void processPrompt(final ConsoleReadCmdItem item) {
+ switch (item.getCmdOption() & 0xf) {
+ case 2:
+ if (this.hotModeState < 2) {
+ this.hotModeState= 2;
+ this.hotModeReadCallbackBackup= this.consoleReadCallback;
+ this.hotModeC2SFirstBackup= this.mainC2SFirst;
+ this.mainC2SFirst= null;
+ }
+ this.consoleReadCallback= item;
+ return;
+ case RjsComObject.V_TRUE:
+ this.consoleReadCallback= item;
+ updatePrompt(item.getDataText(), true);
+ return;
+ default:
+ this.consoleReadCallback= item;
+ updatePrompt(item.getDataText(), false);
+ return;
+ }
+ }
+
+ public void requestHotMode(final boolean async) {
+ this.hotModeRequested.set(true);
+ if (async) {
+ RJHelper_EXECUTOR.schedule(this.hotModeRunnable, 100, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ public boolean startHotMode() {
+ if (this.hotModeState == 0) {
+ this.hotModeRequested.set(false);
+ final boolean savedCallbackRequired= this.consoleReadCallbackRequired;
+ this.consoleReadCallbackRequired= false;
+ try {
+ this.hotModeState= 1;
+ runMainLoop(new CtrlCmdItem(CtrlCmdItem.REQUEST_HOT_MODE), null, new NullProgressMonitor());
+ return true;
+ }
+ catch (final Throwable e) {
+ this.hotModeState= 0;
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, 0,
+ "An error occurred when running hot mode.", e ));
+ }
+ finally {
+ this.consoleReadCallbackRequired= savedCallbackRequired;
+ }
+ }
+ return false;
+ }
+
+ public void requestExtraMode(final int positions) {
+ this.extraModeRequested= positions;
+ }
+
+
+ protected void updateBusy(final boolean isBusy) {
+ }
+
+ protected void updatePrompt(final String text, final boolean addToHistory) {
+ }
+
+ protected void writeConsoleOutput(final byte streamId, final String text) {
+ }
+
+ protected void showMessage(final String text) {
+ }
+
+ protected void processHotMode() {
+ }
+
+ protected void processExtraMode(final int i) {
+ }
+
+ private void addGraphic(final int devId, final double w, final double h, final int canvasColor,
+ final boolean activate) throws RjException {
+ if (devId >= 0) {
+ if (devId >= this.graphics.length) {
+ final RClientGraphic[] newArray= new RClientGraphic[devId + 10];
+ System.arraycopy(this.graphics, 0, newArray, 0, this.graphics.length);
+ this.graphics= newArray;
+ }
+ final InitConfig config= new InitConfig();
+ config.canvasColor= canvasColor;
+ if (this.graphics[devId] != null) {
+ this.graphics[devId].reset(w, h, config);
+ this.graphics[devId].setActive(activate);
+ }
+ else {
+ this.graphics[devId]= this.lastGraphic= this.graphicFactory.newGraphic(devId,
+ w, h, config,
+ activate, this.graphicActions, this.currentGraphicOptions);
+ }
+ return;
+ }
+ throw new RjException("Invalid GD devId: " + devId);
+ }
+
+ private void removeGraphic(final int devId) {
+ if (devId >= 0 && devId < this.graphics.length) {
+ if (this.graphics[devId] != null) {
+ try {
+ this.graphicFactory.closeGraphic(this.graphics[devId]);
+ }
+ catch (final Exception e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1,
+ "An error occurred when closing R graphic (Device " + (devId+1) + ").", e ));
+ }
+ this.graphics[devId]= null;
+ }
+ }
+ }
+
+ protected RClientGraphic getGraphic(final int devId) {
+ if (devId >= 0 && devId < this.graphics.length) {
+ final RClientGraphic graphic= this.graphics[devId];
+ if (graphic != null) {
+ return graphic;
+ }
+ }
+ return this.graphicDummy;
+ }
+
+ public void disposeAllGraphics() {
+ for (int devId= 0; devId < this.graphics.length; devId++) {
+ removeGraphic(devId);
+ }
+ }
+
+
+ public final void activateConsole() {
+ if (this.rjConsoleEngine == null) {
+ throw new IllegalStateException("Missing REngine");
+ }
+ this.consoleReadCallbackRequired= true;
+ }
+
+ public final void answerConsole(final String input, final IProgressMonitor monitor) throws CoreException {
+ this.consoleReadCallback.setAnswer(input);
+ runMainLoop(null, this.consoleReadCallback, monitor);
+
+ this.runFinishTask= false;
+ }
+
+ public final boolean isConsoleReady() {
+ return (this.consoleReadCallback != null);
+ }
+
+
+ private Map<String, Object> getServerData() throws RemoteException {
+ if (this.platformData != null) {
+ return this.platformData;
+ }
+ final Map<String, Object> data= this.rjConsoleEngine.getPlatformData();
+ if (data != null && data.containsKey("version.string")) { //$NON-NLS-1$
+ this.platformData= data;
+ }
+ return data;
+ }
+
+ public final RPlatform getRPlatform() {
+ synchronized (this.platformLock) {
+ if (this.platformObj == null) {
+ try {
+ final Map<String, Object> data= getServerData();
+ if (data != null && data.containsKey("version.string")) {
+ this.platformObj= new RPlatform((String) this.platformData.get("os.type"),
+ (String) this.platformData.get("file.sep"),
+ (String) this.platformData.get("path.sep"),
+ (String) this.platformData.get("version.string"),
+ (String) this.platformData.get("os.name"),
+ (String) this.platformData.get("os.arch"),
+ (String) this.platformData.get("os.version") );
+ }
+ }
+ catch (final RemoteException e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID,
+ "An error occured when loading data for RPlatform information.", e));
+ }
+ }
+ return this.platformObj;
+ }
+ }
+
+ public final String getProperty(final String key) {
+ synchronized (this.platformLock) {
+ try {
+ final Map<String, Object> data= getServerData();
+ if (data != null) {
+ final Object value= data.get(key);
+ return (value instanceof String) ? (String) value : null;
+ }
+ }
+ catch (final RemoteException e) {
+ }
+ return null;
+ }
+ }
+
+
+ public final void finishTask(
+ final IProgressMonitor monitor) throws CoreException {
+ if (!this.runFinishTask) {
+ return;
+ }
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new MainCtrlCmdItem(MainCtrlCmdItem.OP_FINISH_TASK,
+ 0 )), monitor);
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ return;
+ }
+ finally {
+ finalizeDataLevel();
+ this.runFinishTask= false;
+ }
+ }
+
+
+ public boolean isValidEnvir(final RObject envir) {
+ switch (envir.getRObjectType()) {
+ case RObject.TYPE_REFERENCE:
+ return (((RReference) envir).getReferencedRObjectType() == RObject.TYPE_ENVIRONMENT);
+ case RObject.TYPE_LANGUAGE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public final void evalVoid(final String expression, final RObject envir,
+ final IProgressMonitor monitor) throws CoreException {
+ if (expression == null) {
+ throw new NullPointerException("expression");
+ }
+ if (envir != null && !isValidEnvir(envir)) {
+ throw new IllegalArgumentException("envir");
+ }
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID,
+ 0, expression, null, null, envir )), monitor);
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ return;
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public final void evalVoid(final String name, final RList args, final RObject envir,
+ final IProgressMonitor monitor) throws CoreException {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ if (args == null) {
+ throw new NullPointerException("args");
+ }
+ if (envir != null && !isValidEnvir(envir)) {
+ throw new IllegalArgumentException("envir");
+ }
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_FCALL_VOID,
+ 0, name, args, null, envir )), monitor );
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ return;
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public RObject evalData(final String expression, final RObject envir,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ if (expression == null) {
+ throw new NullPointerException("expression");
+ }
+ if (envir != null && !isValidEnvir(envir)) {
+ throw new IllegalArgumentException("envir");
+ }
+ final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_EXPR_DATA,
+ options, checkedDepth, expression, null, null, envir, factoryId )), monitor);
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ return ((DataCmdItem) this.dataAnswer[level]).getData();
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public RObject evalData(final String name, final RObject args, final RObject envir,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ if (args == null) {
+ throw new NullPointerException("args");
+ }
+ if (envir != null && !isValidEnvir(envir)) {
+ throw new IllegalArgumentException("envir");
+ }
+ final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.EVAL_FCALL_DATA,
+ options, checkedDepth, name, args, null, envir, factoryId )), monitor );
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ return ((DataCmdItem) this.dataAnswer[level]).getData();
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public final RObject evalData(final RReference reference,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+ final int level= newDataLevel();
+ try {
+ final long handle= reference.getHandle();
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.RESOLVE_DATA,
+ options, checkedDepth, Long.toString(handle), null, null, null, factoryId )), monitor );
+
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ return ((DataCmdItem) this.dataAnswer[level]).getData();
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public RObject evalData(final byte envType, final String name,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ final Operation operation;
+ switch (envType) {
+ case REnvironment.ENVTYPE_NAMESPACE:
+ operation= DataCmdItem.EVAL_NAMESPACE_DATA;
+ break;
+ case REnvironment.ENVTYPE_NAMESPACE_EXPORTS:
+ operation= DataCmdItem.EVAL_NAMESPACE_EXPORTS_DATA;
+ break;
+ default:
+ throw new IllegalArgumentException("envType= " + envType);
+ }
+
+ final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(operation,
+ options, checkedDepth,
+ name, null, null, null, factoryId )), monitor );
+
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ return ((DataCmdItem) this.dataAnswer[level]).getData();
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public final void assignData(final String expression, final RObject data, final RObject envir,
+ final IProgressMonitor monitor) throws CoreException {
+ if (expression == null) {
+ throw new NullPointerException("expression");
+ }
+ if (data == null) {
+ throw new NullPointerException("data");
+ }
+ if (envir != null && !isValidEnvir(envir)) {
+ throw new IllegalArgumentException("envir");
+ }
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.ASSIGN_DATA,
+ 0, null, data, expression, envir )), monitor );
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Assignment failed: " + status.getMessage(), null));
+ }
+ }
+ return;
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public final void assignData(final String name, final RObject args, final String expression,
+ final RObject envir,
+ final IProgressMonitor monitor) throws CoreException {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ if (args == null) {
+ throw new NullPointerException("args");
+ }
+ if (expression == null) {
+ throw new NullPointerException("expression");
+ }
+ if (envir != null && !isValidEnvir(envir)) {
+ throw new IllegalArgumentException("envir");
+ }
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.ASSIGN_FCALL,
+ 0, name, args, expression, envir )), monitor );
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Assignment failed: " + status.getMessage(), null));
+ }
+ }
+ return;
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public RObject[] findData(final String symbol, final RObject envir, final boolean inherits,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ if (symbol == null) {
+ throw new NullPointerException("symbol");
+ }
+ final byte checkedDepth= (depth < Byte.MAX_VALUE) ? (byte) depth : Byte.MAX_VALUE;
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new DataCmdItem(DataCmdItem.FIND_DATA,
+ (inherits) ? (options | 0x1000) : options, checkedDepth,
+ symbol, null, null, envir, factoryId )), monitor );
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Evaluation failed: " + status.getMessage(), null));
+ }
+ }
+ final DataCmdItem dataItem= (DataCmdItem) this.dataAnswer[level];
+ return (dataItem.getRho() != null) ?
+ new RObject[] { dataItem.getData(), dataItem.getRho() } :
+ null;
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+
+ public void downloadFile(final OutputStream out, final String fileName, final int options, final IProgressMonitor monitor) throws CoreException {
+ final BinExchange request= new BinExchange(out, fileName, this.rjConsoleEngine, options);
+ final BinExchange answer;
+ try {
+ answer= (BinExchange) runAsync(request);
+ }
+ finally {
+ request.clear();
+ }
+ if (answer == null || !answer.isOK()) {
+ final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Downloading file failed: " + status.getMessage(), null));
+ }
+ }
+ }
+
+ public byte[] downloadFile(final String fileName, final int options, final IProgressMonitor monitor) throws CoreException {
+ final BinExchange request= new BinExchange(fileName, this.rjConsoleEngine, options);
+ final BinExchange answer;
+ try {
+ answer= (BinExchange) runAsync(request);
+ }
+ finally {
+ request.clear();
+ }
+ if (answer == null || !answer.isOK()) {
+ final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Downloading file failed: " + status.getMessage(), null));
+ }
+ }
+ return answer.getBytes();
+ }
+
+ public void uploadFile(final InputStream in, final long length, final String fileName, final int options, final IProgressMonitor monitor) throws CoreException {
+ final BinExchange request= new BinExchange(in, length, fileName, this.rjConsoleEngine, options);
+ final BinExchange answer;
+ try {
+ answer= (BinExchange) runAsync(request);
+ }
+ finally {
+ request.clear();
+ }
+ if (answer == null || !answer.isOK()) {
+ final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Uploading file failed: " + status.getMessage(), null));
+ }
+ }
+ }
+
+
+ public Object execSyncDbgOp(final byte dbgOp, final RJIOExternalizable request,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.dbgOpRequest) {
+ throw new IllegalStateException();
+ }
+ this.dbgOpRequest= true;
+ try {
+ runMainLoop(null, new DbgCmdItem(dbgOp, 0, request), monitor);
+ if (this.dbgOpAnswer == null || !this.dbgOpAnswer.isOK()) {
+ final RjsStatus status= (this.dbgOpAnswer != null) ? this.dbgOpAnswer.getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Dbg operation failed: " + status.getMessage(), null));
+ }
+ }
+ { final Object data= this.dbgOpAnswer.getData();
+ if (data instanceof CtrlReport) {
+ final CtrlReport report= (CtrlReport) data;
+ if (!report.isEngineSuspended()) {
+ this.consoleReadCallback= null;
+ }
+ }
+ return data;
+ }
+ }
+ finally {
+ this.dbgOpRequest= false;
+ this.dbgOpAnswer= null;
+ }
+ }
+
+ public void execAsyncDbgOp(final byte op, final RJIOExternalizable request)
+ throws CoreException {
+ execAsync(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ runAsync(new DbgCmdItem(op, 0, request));
+ // in future check returned status if required
+ }
+ catch (final CoreException e) {
+ log(new Status(IStatus.ERROR, RJ_CLIENT_ID, -1,
+ "An error occurred when executing background dbg operation.", e));
+ }
+ }
+ });
+ }
+
+
+ public int getGraphicOptions() {
+ return this.currentGraphicOptions;
+ }
+
+ public void setGraphicOptions(final int options) {
+ this.currentGraphicOptions= options;
+ this.lastGraphic= null;
+ }
+
+ public RClientGraphic getLastGraphic() {
+ return this.lastGraphic;
+ }
+
+ public Object execSyncGraphicOp(final int devId, final byte op,
+ final IProgressMonitor monitor) throws CoreException {
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new GraOpCmdItem(devId, op)),
+ monitor );
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Graphics operation failed: " + status.getMessage(), null));
+ }
+ }
+ return ((GraOpCmdItem) this.dataAnswer[level]).getData();
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+ public Object execSyncGraphicOp(final int devId, final byte op, final RJIOExternalizable data,
+ final IProgressMonitor monitor) throws CoreException {
+ final int level= newDataLevel();
+ try {
+ runMainLoop(null, createDataRequestId(level, new GraOpCmdItem(devId, op, data)),
+ monitor );
+ if (this.dataAnswer[level] == null || !this.dataAnswer[level].isOK()) {
+ final RjsStatus status= (this.dataAnswer[level] != null) ? this.dataAnswer[level].getStatus() : MISSING_ANSWER_STATUS;
+ if (status.getSeverity() == RjsStatus.CANCEL) {
+ throw new CoreException(Status.CANCEL_STATUS);
+ }
+ else {
+ throw new CoreException(new Status(status.getSeverity(), RJ_CLIENT_ID, status.getCode(),
+ "Graphics operation failed: " + status.getMessage(), null));
+ }
+ }
+ return ((GraOpCmdItem) this.dataAnswer[level]).getData();
+ }
+ finally {
+ finalizeDataLevel();
+ }
+ }
+
+
+ public void addCancelHandler(final Callable<Boolean> handler) {
+ synchronized (this.cancelHandler) {
+ this.cancelHandler.add(handler);
+ }
+ }
+
+ public void removeCancelHandler(final Callable<Boolean> handler) {
+ synchronized (this.cancelHandler) {
+ final int idx= this.cancelHandler.lastIndexOf(handler);
+ if (idx >= 0) {
+ this.cancelHandler.remove(idx);
+ }
+ }
+ }
+
+ protected Callable<Boolean>[] getCancelHandlers() {
+ synchronized (this.cancelHandler) {
+ return this.cancelHandler.toArray(new Callable[this.cancelHandler.size()]);
+ }
+ }
+
+ public Lock getWaitLock() {
+ return this.clientWaitLock;
+ }
+
+ public void waitingForUser() {
+ if (this.hotModeRequested.get()) {
+ this.clientWaitLock.unlock();
+ try {
+ startHotMode();
+ }
+ finally {
+ this.clientWaitLock.lock();
+ }
+ return;
+ }
+
+ try {
+ this.clientWaitCondition.awaitNanos(1000 * 100);
+ }
+ catch (final InterruptedException e1) {
+ }
+ }
+
+ public void resume() {
+ this.clientWaitCondition.signal();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClientGraphicActions.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClientGraphicActions.java
new file mode 100644
index 0000000..729842d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/AbstractRJComClientGraphicActions.java
@@ -0,0 +1,109 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.server.gr.Coord;
+import org.eclipse.statet.rj.server.gr.GraOp;
+
+
+public abstract class AbstractRJComClientGraphicActions implements RClientGraphicActions {
+
+
+ public static interface Factory {
+
+
+ AbstractRJComClientGraphicActions create(AbstractRJComClient rjs, Object rHandle);
+
+ }
+
+
+ protected final AbstractRJComClient rjs;
+
+
+ protected AbstractRJComClientGraphicActions(final AbstractRJComClient rjs) {
+ if (rjs == null) {
+ throw new NullPointerException("rjs");
+ }
+ this.rjs= rjs;
+ }
+
+
+ public void doResizeGraphic(final int devId,
+ final IProgressMonitor monitor) throws CoreException {
+ this.rjs.execSyncGraphicOp(devId, GraOp.OP_REQUEST_RESIZE, monitor);
+ }
+
+ public void doCloseGraphic(final int devId,
+ final IProgressMonitor monitor) throws CoreException {
+ this.rjs.execSyncGraphicOp(devId, GraOp.OP_CLOSE, monitor);
+ }
+
+
+ @Override
+ public void copy(final int devId, final String toDev, final String toDevFile, final String toDevArgs,
+ final IProgressMonitor monitor) throws CoreException {
+ final StringBuilder sb= new StringBuilder(64);
+ sb.append("rj.gd::.rj.copyGD(");
+ sb.append("devNr=").append((devId + 1)).append("L,");
+ sb.append("device=").append(toDev).append(",");
+ if (toDevFile != null) {
+ sb.append("file=\"").append(toDevFile).append("\",");
+ }
+ if (toDevArgs != null && toDevArgs.length() > 0) {
+ sb.append(toDevArgs);
+ sb.append(",");
+ }
+ sb.replace(sb.length()-1, sb.length(), ")");
+ this.rjs.evalVoid(sb.toString(), null, monitor);
+ }
+
+ @Override
+ public double[] convertGraphic2User(final int devId, final double[] xy,
+ final IProgressMonitor monitor) throws CoreException {
+ if (xy == null) {
+ throw new NullPointerException("xy");
+ }
+ if (xy.length != 2) {
+ throw new IllegalArgumentException("length of xy");
+ }
+ final Coord coord= (Coord) this.rjs.execSyncGraphicOp(devId, GraOp.OP_CONVERT_DEV2USER,
+ new Coord(xy[0], xy[1]), monitor );
+ if (coord != null && !Double.isNaN(coord.getX()) && !Double.isNaN(coord.getY())) {
+ return new double[] { coord.getX(), coord.getY() };
+ }
+ return null;
+ }
+
+ @Override
+ public double[] convertUser2Graphic(final int devId, final double[] xy,
+ final IProgressMonitor monitor) throws CoreException {
+ if (xy == null) {
+ throw new NullPointerException("xy");
+ }
+ if (xy.length != 2) {
+ throw new IllegalArgumentException("length of xy");
+ }
+ final Coord coord= (Coord) this.rjs.execSyncGraphicOp(devId, GraOp.OP_CONVERT_USER2DEV,
+ new Coord(xy[0], xy[1]), monitor );
+ if (coord != null && !Double.isNaN(coord.getX()) && !Double.isNaN(coord.getY())) {
+ return new double[] { coord.getX(), coord.getY() };
+ }
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/DaemonThreadFactory.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/DaemonThreadFactory.java
new file mode 100644
index 0000000..fd28741
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/DaemonThreadFactory.java
@@ -0,0 +1,44 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+class DaemonThreadFactory implements ThreadFactory {
+
+
+ final AtomicInteger threadNumber= new AtomicInteger(1);
+ final String namePrefix;
+ final String nameSuffix= "]";
+
+
+ public DaemonThreadFactory(final String name) {
+ this.namePrefix= name + " [Thread-";
+ }
+
+
+ @Override
+ public Thread newThread(final Runnable r) {
+ final Thread t= new Thread(r,
+ this.namePrefix + this.threadNumber.getAndIncrement() + this.nameSuffix);
+
+ t.setDaemon(true);
+ t.setPriority(Thread.NORM_PRIORITY);
+ return t;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/FunctionCallImpl.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/FunctionCallImpl.java
new file mode 100644
index 0000000..3ca3cbb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/FunctionCallImpl.java
@@ -0,0 +1,242 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.impl.RLanguageImpl;
+import org.eclipse.statet.rj.data.impl.RNullImpl;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class FunctionCallImpl implements FunctionCall {
+
+
+ private final String name;
+
+ private final List<String> argNames= new ArrayList<>();
+ private final List<RObject> argValues= new ArrayList<>();
+
+ private final AbstractRJComClient rjs;
+ private final RObjectFactory rObjectFactory;
+
+
+ public FunctionCallImpl(final AbstractRJComClient client, final String name,
+ final RObjectFactory rObjectFactory) {
+ this.rjs= client;
+ this.rObjectFactory= rObjectFactory;
+ this.name= name;
+ }
+
+
+ @Override
+ public FunctionCall add(final String arg, final String expression) {
+ if (expression == null) {
+ throw new NullPointerException();
+ }
+ this.argNames.add(arg);
+ final RObject data= new RLanguageImpl((byte) 0, expression, null);
+ this.argValues.add(data);
+ return this;
+ }
+
+ @Override
+ public FunctionCall add(final String expression) {
+ return this.add(null, expression);
+ }
+
+ @Override
+ public FunctionCall add(final String arg, final RObject data) {
+ if (data == null) {
+ throw new NullPointerException();
+ }
+ this.argNames.add(arg);
+ this.argValues.add(data);
+ return this;
+ }
+
+ @Override
+ public FunctionCall add(final RObject data) {
+ return this.add(null, data);
+ }
+
+ @Override
+ public FunctionCall addLogi(final String arg, final boolean logical) {
+ final RObject data= this.rObjectFactory.createVector(
+ this.rObjectFactory.createLogiData(new boolean[] { logical }) );
+ this.argNames.add(arg);
+ this.argValues.add(data);
+ return this;
+ }
+
+ @Override
+ public FunctionCall addLogi(final boolean logical) {
+ return addLogi(null, logical);
+ }
+
+ @Override
+ public FunctionCall addInt(final String arg, final int integer) {
+ final RObject data= this.rObjectFactory.createVector(
+ this.rObjectFactory.createIntData(new int[] { integer }) );
+ this.argNames.add(arg);
+ this.argValues.add(data);
+ return this;
+ }
+
+ @Override
+ public FunctionCall addInt(final int integer) {
+ return addInt(null, integer);
+ }
+
+ @Override
+ public FunctionCall addNum(final String arg, final double numeric) {
+ final RObject data= this.rObjectFactory.createVector(
+ this.rObjectFactory.createNumData(new double[] { numeric }) );
+ this.argNames.add(arg);
+ this.argValues.add(data);
+ return this;
+ }
+
+ @Override
+ public FunctionCall addNum(final double numeric) {
+ return this.addNum(null, numeric);
+ }
+
+ @Override
+ public FunctionCall addChar(final String arg, final String character) {
+ final RObject data= this.rObjectFactory.createVector(
+ this.rObjectFactory.createCharData(new String[] { character }));
+ this.argNames.add(arg);
+ this.argValues.add(data);
+ return this;
+ }
+
+ @Override
+ public FunctionCall addChar(final String character) {
+ return this.addChar(null, character);
+ }
+
+ @Override
+ public FunctionCall addCplx(final String arg, final double real, final double imaginary) {
+ final RObject data= this.rObjectFactory.createVector(
+ this.rObjectFactory.createCplxData(new double[] { real }, new double[] {imaginary }) );
+ this.argNames.add(arg);
+ this.argValues.add(data);
+ return this;
+ }
+
+ @Override
+ public FunctionCall addCplx(final double real, final double imaginary) {
+ return addCplx(null, real, imaginary);
+ }
+
+ @Override
+ public FunctionCall addNull(final String arg) {
+ this.argNames.add(arg);
+ this.argValues.add(RNullImpl.INSTANCE);
+ return this;
+ }
+
+ @Override
+ public FunctionCall addNull() {
+ return this.addNull(null);
+ }
+
+
+ private RList prepareArgs(final IProgressMonitor monitor) throws CoreException {
+ // TODO step by step upload for large objects
+ final String[] names= this.argNames.toArray(new String[this.argNames.size()]);
+ final RObject[] values= this.argValues.toArray(new RObject[this.argValues.size()]);
+ assert (names.length == values.length);
+ return this.rObjectFactory.createList(values, names);
+ }
+
+ @Override
+ public void evalVoid(final IProgressMonitor monitor) throws CoreException {
+ final RList args= prepareArgs(monitor);
+ this.rjs.evalVoid(this.name, args, null, monitor);
+ }
+
+ @Override
+ public void evalVoid(final RObject envir, final IProgressMonitor monitor) throws CoreException {
+ final RList args= prepareArgs(monitor);
+ this.rjs.evalVoid(this.name, args, envir, monitor);
+ }
+
+ @Override
+ public RObject evalData(final IProgressMonitor monitor) throws CoreException {
+ final RList args= prepareArgs(monitor);
+ return this.rjs.evalData(this.name, args, null, null, 0, RService.DEPTH_INFINITE, monitor);
+ }
+
+ @Override
+ public RObject evalData(final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ final RList args= prepareArgs(monitor);
+ return this.rjs.evalData(this.name, args, null, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public RObject evalData(final RObject envir,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ final RList args= prepareArgs(monitor);
+ return this.rjs.evalData(this.name, args, envir, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public void evalAssign(final String target, final IProgressMonitor monitor) throws CoreException {
+ final RList args= prepareArgs(monitor);
+ this.rjs.assignData(this.name, args, target, null, monitor);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder call= new StringBuilder();
+ call.append(this.name);
+ call.append('(');
+ if (this.argNames.size() > 0) {
+ for (int i= 0; i < this.argNames.size(); i++) {
+ final String argName= this.argNames.get(i);
+ if (argName != null) {
+ call.append('\n');
+ call.append(argName);
+ call.append("= "); //$NON-NLS-1$
+ }
+ final Object value= this.argValues.get(i);
+ if (value instanceof String) {
+ call.append((String) value);
+ }
+ else if (value instanceof RObject) {
+ call.append("\n<DATA>\n"); //$NON-NLS-1$
+ call.append(value.toString());
+ call.append("\n</DATA>"); //$NON-NLS-1$
+ }
+ }
+ call.append("\n"); //$NON-NLS-1$
+ }
+ call.append(')');
+ return call.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphic.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphic.java
new file mode 100644
index 0000000..18beaab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphic.java
@@ -0,0 +1,182 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.graphic.core.RCircle;
+import org.eclipse.statet.rj.graphic.core.RClipSetting;
+import org.eclipse.statet.rj.graphic.core.RColorSetting;
+import org.eclipse.statet.rj.graphic.core.RFillSetting;
+import org.eclipse.statet.rj.graphic.core.RFontSetting;
+import org.eclipse.statet.rj.graphic.core.RLine;
+import org.eclipse.statet.rj.graphic.core.RLineSetting;
+import org.eclipse.statet.rj.graphic.core.RPath;
+import org.eclipse.statet.rj.graphic.core.RPolygon;
+import org.eclipse.statet.rj.graphic.core.RPolyline;
+import org.eclipse.statet.rj.graphic.core.RRaster;
+import org.eclipse.statet.rj.graphic.core.RRect;
+import org.eclipse.statet.rj.graphic.core.RText;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Interface for the R side of (RJ) graphics at client layer.
+ *
+ * The methods are called by the client protocol handler
+ * (e.g. {@link AbstractRJComClient}) and must not be called at
+ * another place.
+ */
+public interface RClientGraphic {
+
+
+ class InitConfig {
+
+ public int canvasColor;
+
+ }
+
+
+ /**
+ * Mask for fill rule
+ * <ul>
+ * <li>{@link #FILL_WIND_EVEN_ODD}</li>
+ * <li>{@link #FILL_WIND_NON_ZERO}</li>
+ * </ul>
+ *
+ * @since 2.0
+ */
+ int MASK_FILL_RULE= 0x3;
+
+ /**
+ * Constant for "even-odd" winding rule for filling elements
+ *
+ * @since 2.0
+ */
+ int FILL_WIND_EVEN_ODD= 0x0;
+
+ /**
+ * Constant for "non-zero" winding rule for filling elements
+ *
+ * @since 2.0
+ */
+ int FILL_WIND_NON_ZERO= 0x1;
+
+
+ /**
+ * Returns the device id of R
+ *
+ * @return the id
+ */
+ int getDevId();
+
+ /**
+ *
+ * @param w the width of the graphic
+ * @param h the height of the graphic
+ * @param config initialization configuration
+ */
+ void reset(double w, double h, InitConfig config);
+
+ /**
+ * Sets if the graphic is the active device in R.
+ *
+ * @param active <code>true</code> if active, otherwise <code>false</code>
+ */
+ void setActive(boolean active);
+
+ /**
+ * Returns if the graphic is the active device in R.
+ *
+ * @return <code>true</code> if active, otherwise <code>false</code>
+ */
+ boolean isActive();
+
+ /**
+ * Sets the current mode signaled by R.
+ * <p>
+ * Values:
+ * 0= R stopped drawing
+ * 1= R started drawing
+ * 2= graphical input exists
+ *
+ * @param mode the value constant
+ */
+ void setMode(int mode);
+
+ double[] computeSize();
+ double[] computeFontMetric(int ch);
+ double[] computeStringWidth(String txt);
+
+ /**
+ * @see RClipSetting#RClipSetting(double, double, double, double)
+ */
+ void addSetClip(double x0, double y0, double x1, double y1);
+ /**
+ * @see RColorSetting#RColorSetting(int)
+ */
+ void addSetColor(int color);
+ /**
+ * @see RFillSetting#RFillSetting(int)
+ */
+ void addSetFill(int color);
+ /**
+ * @see RLineSetting#RLineSetting(int, double, byte, byte, float)
+ */
+ void addSetLine(int type, float width, byte cap, byte join, float joinMiterLimit);
+ /**
+ * @see RFontSetting#RFontSetting(String, int, double, double, double)
+ */
+ void addSetFont(String family, int face, float pointSize, float lineHeight);
+ /**
+ * @see RLine#RLine(double, double, double, double)
+ */
+ void addDrawLine(double x0, double y0, double x1, double y1);
+ /**
+ * @see RRect#RRect(double, double, double, double)
+ */
+ void addDrawRect(double x0, double y0, double x1, double y1);
+ /**
+ * @see RPolyline
+ */
+ void addDrawPolyline(double[] x, double[] y);
+ /**
+ * @see RPolygon
+ */
+ void addDrawPolygon(double[] x, double[] y);
+ /**
+ * @see RPath
+ */
+ void addDrawPath(int[] n, double[] x, double[] y, int winding);
+ /**
+ * @see RCircle#RCircle(double, double, double)
+ */
+ void addDrawCircle(double x, double y, double r);
+ /**
+ * @see RText
+ */
+ void addDrawText(String txt, double x, double y, double rDeg, double hAdj);
+ /**
+ * @see RRaster
+ */
+ void addDrawRaster(byte[] imgData, boolean imgAlpha, int imgWidth, int imgHeight,
+ double x, double y, double w, double h, double rDeg, boolean interpolate);
+
+ byte[] capture(int width, int height);
+
+
+ double[] runRLocator(RService r, IProgressMonitor monitor);
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicActions.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicActions.java
new file mode 100644
index 0000000..f01d860
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicActions.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+
+/**
+ * Interface for (RJ) graphics offering actions which can be used
+ * in graphic views/windows.
+ */
+public interface RClientGraphicActions {
+
+
+ Object getRHandle();
+
+ String getRLabel();
+
+ IStatus resizeGraphic(int devId, Runnable beforeResize);
+
+ IStatus closeGraphic(int devId);
+
+
+ void copy(int devId, String toDev, String toDevFile, String toDevArgs,
+ IProgressMonitor monitor) throws CoreException;
+ double[] convertGraphic2User(int devId, double[] xy,
+ IProgressMonitor monitor) throws CoreException;
+ double[] convertUser2Graphic(int devId, double[] xy,
+ IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicDummy.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicDummy.java
new file mode 100644
index 0000000..67eb6ab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicDummy.java
@@ -0,0 +1,147 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * A minimal {@link RClientGraphic} implementation.
+ */
+public class RClientGraphicDummy implements RClientGraphic {
+
+
+ private final int devId;
+
+ private boolean isActive;
+
+ private double[] size;
+
+
+ public RClientGraphicDummy(final int devId, final double w, final double h) {
+ this.devId= devId;
+ this.size= new double[] { w, h };
+ }
+
+
+ @Override
+ public int getDevId() {
+ return this.devId;
+ }
+
+ @Override
+ public void reset(final double w, final double h, final InitConfig config) {
+ this.size= new double[] { w, h };
+ }
+
+ @Override
+ public void setMode(final int mode) {
+ }
+
+ @Override
+ public void setActive(final boolean active) {
+ this.isActive= active;
+ }
+
+ @Override
+ public boolean isActive() {
+ return this.isActive;
+ }
+
+ @Override
+ public double[] computeSize() {
+ return this.size;
+ }
+
+ @Override
+ public double[] computeFontMetric(final int ch) {
+ return null;
+ }
+
+ @Override
+ public double[] computeStringWidth(final String txt) {
+ return null;
+ }
+
+ @Override
+ public void addSetClip(final double x0, final double y0, final double x1, final double y1) {
+ }
+
+ @Override
+ public void addSetColor(final int color) {
+ }
+
+ @Override
+ public void addSetFill(final int color) {
+ }
+
+ @Override
+ public void addSetLine(final int type, final float width,
+ final byte cap, final byte join, final float joinMiterLimit) {
+ }
+
+ @Override
+ public void addSetFont(final String family, final int face, final float pointSize, final float lineHeight) {
+ }
+
+ @Override
+ public void addDrawLine(final double x0, final double y0, final double x1, final double y1) {
+ }
+
+ @Override
+ public void addDrawRect(final double x0, final double y0, final double x1, final double y1) {
+ }
+
+ @Override
+ public void addDrawPolyline(final double[] x, final double[] y) {
+ }
+
+ @Override
+ public void addDrawPolygon(final double[] x, final double[] y) {
+ }
+
+ @Override
+ public void addDrawPath(final int[] n, final double[] x, final double[] y, final int winding) {
+ }
+
+ @Override
+ public void addDrawCircle(final double x, final double y, final double r) {
+ }
+
+ @Override
+ public void addDrawText(final String text,
+ final double x, final double y, final double rDeg, final double hAdj) {
+ }
+
+ @Override
+ public void addDrawRaster(final byte[] imgData, final boolean imgAlpha, final int imgWidth, final int imgHeight,
+ final double x, final double y, final double w, final double h,
+ final double rDeg, final boolean interpolate) {
+ }
+
+ @Override
+ public byte[] capture(final int width, final int height) {
+ return null;
+ }
+
+
+ @Override
+ public double[] runRLocator(final RService r, final IProgressMonitor monitor) {
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicFactory.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicFactory.java
new file mode 100644
index 0000000..0009097
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RClientGraphicFactory.java
@@ -0,0 +1,87 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import java.util.Map;
+
+import org.eclipse.statet.rj.server.client.RClientGraphic.InitConfig;
+
+
+/**
+ * Factory interface used to create (and close) {@link RClientGraphic} objects.
+ *
+ * The methods are called by the client protocol handler
+ * ({@link AbstractRJComClient}) and must not be called at
+ * another place.
+ */
+public interface RClientGraphicFactory {
+
+
+ /**
+ * Indicates explicitly that the graphic will be added to a global graphic
+ * collection.
+ *
+ * Typically that means, the graphic is shown in the default graphic view/window.
+ */
+ int MANAGED_ON= 1 << 1;
+
+ /**
+ * Indicates that the graphic will not be added to a global graphic collection.
+ *
+ * Typically that means, the graphic isn't shown in the default graphic view/window.
+ */
+ int MANAGED_OFF= 1 << 2;
+
+ /**
+ * Indicates that the graphic will be disposed if closed in R.
+ */
+ int R_CLOSE_ON= 1 << 3;
+
+ /**
+ * Indicates that the graphic will not be disposed if closed in R.
+ */
+ int R_CLOSE_OFF= 1 << 4;
+
+ /**
+ * Returns a map with properties configuring the server
+ * The values must be serializable.
+ *
+ * @return a map with keys and values of the properties
+ */
+ Map<String, ? extends Object> getInitServerProperties();
+
+ /**
+ * Called if a new graphic is created in R (<code>dev.new()</code>).
+ *
+ * @param devId
+ * @param w
+ * @param h
+ * @param config initialization configuration
+ * @param active
+ * @param actions
+ * @return a new graphic object
+ */
+ RClientGraphic newGraphic(int devId, double w, double h, InitConfig config,
+ boolean active, RClientGraphicActions actions, int options);
+
+ /**
+ * Called if the graphic is closed by the R (<code>dev.off()</code>
+ * or R closed).
+ *
+ * @param graphic the closed graphic
+ */
+ void closeGraphic(RClientGraphic graphic);
+
+}
diff --git a/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RGraphicCreatorImpl.java b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RGraphicCreatorImpl.java
new file mode 100644
index 0000000..747f64e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/src/org/eclipse/statet/rj/server/client/RGraphicCreatorImpl.java
@@ -0,0 +1,107 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.client;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Default implementation for {@link RGraphicCreator}.
+ * <p>
+ * Requires R package <code>rj</code>.</p>
+ */
+public class RGraphicCreatorImpl implements RGraphicCreator {
+
+
+ private final RService service;
+ private final AbstractRJComClient rjs;
+
+ private int options;
+
+ private double width= -1;
+ private double height= -1;
+
+
+ public RGraphicCreatorImpl(final RService service, final AbstractRJComClient rjs, final int options) {
+ this.service= service;
+ this.rjs= rjs;
+ }
+
+
+ @Override
+ public void setSize(final double width, final double height) {
+ if (width == -1 && height == -1) {
+ this.width= -1;
+ this.height= -1;
+ return;
+ }
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.width= width;
+ this.height= height;
+ }
+
+ @Override
+ public RGraphic create(final String expression, final IProgressMonitor monitor) throws CoreException {
+ return create(expression, null, monitor);
+ }
+
+ @Override
+ public RGraphic create(final FunctionCall fcall, final IProgressMonitor monitor) throws CoreException {
+ return create(null, fcall, monitor);
+ }
+
+ private RGraphic create(final String expression, final FunctionCall fcall, final IProgressMonitor monitor) throws CoreException {
+ final int savedOptions= this.rjs.getGraphicOptions();
+ int graphicOptions= this.options;
+ if ((this.options & RClientGraphicFactory.MANAGED_ON) == 0) {
+ graphicOptions |= RClientGraphicFactory.MANAGED_OFF;
+ }
+ if ((this.options & RClientGraphicFactory.R_CLOSE_ON) == 0) {
+ graphicOptions |= RClientGraphicFactory.R_CLOSE_OFF;
+ }
+ this.rjs.setGraphicOptions(graphicOptions);
+ final RClientGraphic graphic;
+ try {
+ if (this.width < 0) {
+ this.service.evalVoid("rj.gd::rj.GD()", monitor);
+ }
+ else {
+ this.service.evalVoid("rj.gd::rj.GD(" +
+ "width= " + this.width + ", height= "+this.height+", size.unit= \"px\"" +
+ ")", monitor );
+ }
+ if (expression != null) {
+ this.service.evalData(expression, monitor);
+ }
+ else {
+ fcall.evalVoid(monitor);
+ }
+ graphic= this.rjs.getLastGraphic();
+ }
+ finally {
+ this.rjs.setGraphicOptions(savedOptions);
+ }
+ return ((graphic instanceof RGraphic) ? ((RGraphic) graphic) : null);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetup.java b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetup.java
new file mode 100644
index 0000000..e709f55
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetup.java
@@ -0,0 +1,168 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.rsetups;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * A single R setup loaded or created for a given OS/architecture.
+ */
+public class RSetup {
+
+
+ private final String id;
+
+ private String name;
+ private String version;
+
+ private String os;
+ private String arch;
+
+ private String rHome;
+
+ private final List<String> rLibsSite= new ArrayList<>(2);
+ private final List<String> rLibs= new ArrayList<>(2);
+ private final List<String> rLibsUser= new ArrayList<>(2);
+
+
+ public RSetup(final String id) {
+ this.id= id;
+ }
+
+
+ /**
+ * Returns the unique id of the setup.
+ *
+ * @return the id
+ */
+ public String getId() {
+ return this.id;
+ }
+
+ /**
+ * Sets the name of the setup.
+ *
+ * @param the new name
+ */
+ public void setName(final String name) {
+ this.name= name;
+ }
+
+ /**
+ * Returns the name of the setup.
+ *
+ * @return the name
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Sets the R version.
+ *
+ * @param the new name
+ */
+ public void setRVersion(final String version) {
+ this.version= version;
+ }
+
+ /**
+ * Returns the R version of the setup.
+ *
+ * @return the name
+ */
+ public String getRVersion() {
+ return this.version;
+ }
+
+ /**
+ * Sets the operation system and its architecture the setup is loaded or created for.
+ *
+ * @param os the os constant
+ * @param arch the arch constant
+ */
+ public void setOS(final String os, final String arch) {
+ this.os= os;
+ this.arch= arch;
+ }
+
+ /**
+ * Returns the operation system the setup is loaded for.
+ *
+ * @return the os constant
+ */
+ public String getOS() {
+ return this.os;
+ }
+
+ /**
+ * Returns the system architecture the setup is loaded for.
+ *
+ * @return the arch constant
+ */
+ public String getOSArch() {
+ return this.arch;
+ }
+
+
+ /**
+ * Sets the R home directory (R_HOME) for the setup.
+ *
+ * @param the R home directory
+ */
+ public void setRHome(final String directory) {
+ this.rHome= directory;
+ }
+
+ /**
+ * Returns the R home directory (R_HOME) for the loaded setup.
+ *
+ * @return the R home directory
+ */
+ public String getRHome() {
+ return this.rHome;
+ }
+
+
+ /**
+ * Returns the library directories for the R_LIBS_SITE group.
+ *
+ * @return the directories of the libraries
+ */
+ public List<String> getRLibsSite() {
+ return this.rLibsSite;
+ }
+
+ /**
+ * Returns the library directories for the R_LIBS group.
+ *
+ * @return the directories of the libraries
+ */
+ public List<String> getRLibs() {
+ return this.rLibs;
+ }
+
+ /**
+ * Returns the library directories for the R_LIBS_USER group.
+ *
+ * @return the directories of the libraries
+ */
+ public List<String> getRLibsUser() {
+ return this.rLibsUser;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetupUtil.java b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetupUtil.java
new file mode 100644
index 0000000..0457e7e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.client/srcRSetups/org/eclipse/statet/rj/rsetups/RSetupUtil.java
@@ -0,0 +1,220 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.rsetups;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.URIUtil;
+
+
+public class RSetupUtil {
+
+
+ public static final String EXTENSION_POINT_ID= "org.eclipse.statet.rj.RSetups"; //$NON-NLS-1$
+
+ private static final String BUNDLE_ID= "org.eclipse.statet.rj.server"; //$NON-NLS-1$
+
+
+ private static final ILog LOGGER= Platform.getLog(Platform.getBundle(BUNDLE_ID));
+
+
+ private static final String SETUP_ELEMENT_NAME= "setup"; //$NON-NLS-1$
+ private static final String BASE_ELEMENT_NAME= "base"; //$NON-NLS-1$
+ private static final String LIBRARY_ELEMENT_NAME= "library"; //$NON-NLS-1$
+
+ private static final String ID_ATTRIBUTE_NAME= "id"; //$NON-NLS-1$
+ private static final String SETUP_ID_ATTRIBUTE_NAME= "setupId"; //$NON-NLS-1$
+ private static final String NAME_ATTRIBUTE_NAME= "name"; //$NON-NLS-1$
+ private static final String INHERIT_BASE_ATTRIBUTE_NAME= "inheritBase"; //$NON-NLS-1$
+ private static final String LOCATION_ATTRIBUTE_NAME= "location"; //$NON-NLS-1$
+ private static final String GROUP_ATTRIBUTE_NAME= "group"; //$NON-NLS-1$
+
+
+ /**
+ * Loads all available R setups for the current or the specified platform.
+ *
+ * A filter map specifying a platform contains the arguments like <code>$os$</code> and
+ * <code>$arch$</code> as keys; its values must be set to the known constant of the desired.
+ * platform.
+ *
+ * @param filter a platform filter or <code>null</code> for the current platform
+ * @return a list with available R setups
+ */
+ public static List<RSetup> loadAvailableSetups(final Map<String, String> filter) {
+ final Set<String> ids= new HashSet<>();
+ final List<RSetup> setups= new ArrayList<>();
+ final IConfigurationElement[] configurationElements= Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
+ for (int i= 0; i < configurationElements.length; i++) {
+ if (configurationElements[i].getName().equals(SETUP_ELEMENT_NAME)) {
+ final String id= configurationElements[i].getAttribute(ID_ATTRIBUTE_NAME);
+ if (id != null && id.length() > 0 && !ids.contains(id)) {
+ ids.add(id);
+ final RSetup setup= loadSetup(id, filter, configurationElements);
+ if (setup != null) {
+ setups.add(setup);
+ }
+ }
+ }
+ }
+ return setups;
+ }
+
+ /**
+ * Loads the R setup with the specified id for the current or the specified platform.
+ *
+ * A filter map specifying a platform contains the arguments like <code>$os$</code> and
+ * <code>$arch$</code> as keys; its values must be set to the known constant of the desired.
+ * platform.
+ *
+ * @param id the id of the R setup
+ * @param filter a platform filter or <code>null</code> for the current platform
+ * @return the R setup or <code>null</code> if loading failed
+ */
+ public static RSetup loadSetup(final String id, final Map<String, String> filter) {
+ final IConfigurationElement[] configurationElements= Platform.getExtensionRegistry().getConfigurationElementsFor(EXTENSION_POINT_ID);
+ return loadSetup(id, filter, configurationElements);
+ }
+
+ private static RSetup loadSetup(final String id, final Map<String, String> filter,
+ final IConfigurationElement[] configurationElements) {
+ try {
+ for (int i= 0; i < configurationElements.length; i++) {
+ final IConfigurationElement element= configurationElements[i];
+ if (element.getName().equals(SETUP_ELEMENT_NAME)
+ && id.equals(element.getAttribute(ID_ATTRIBUTE_NAME)) ) {
+ final RSetup setup= new RSetup(id);
+ if (filter != null && filter.containsKey("$os$")) { //$NON-NLS-1$
+ setup.setOS(filter.get("$os$"), filter.get("$arch$")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ else {
+ setup.setOS(Platform.getOS(), Platform.getOSArch());
+ }
+ setup.setName(element.getAttribute(NAME_ATTRIBUTE_NAME));
+ loadSetupBase(id, filter, configurationElements, setup);
+ if (setup.getRHome() == null) {
+ log(IStatus.WARNING, "Incomplete R setup: Missing R home for setup '" + id + "', the setup is ignored.", element);
+ return null;
+ }
+ loadSetupLibraries(id, filter, configurationElements, setup);
+ return setup;
+ }
+ }
+ }
+ catch (final Exception e) {
+ LOGGER.log(new Status(IStatus.ERROR, BUNDLE_ID, "Error in R setup: Failed to load setup.", e));
+ }
+ return null;
+ }
+
+ private static void loadSetupBase(final String id, final Map<String, String> filter,
+ final IConfigurationElement[] configurationElements, final RSetup setup)
+ throws Exception {
+ for (int i= 0; i < configurationElements.length; i++) {
+ final IConfigurationElement element= configurationElements[i];
+ if (element.getName().equals(BASE_ELEMENT_NAME)
+ && id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) {
+ final String path= getLocation(element, filter);
+ setup.setRHome(path);
+ return;
+ }
+ }
+ for (int i= 0; i < configurationElements.length; i++) {
+ final IConfigurationElement element= configurationElements[i];
+ if (element.equals(SETUP_ELEMENT_NAME)
+ && id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) {
+ final String inheritId= element.getAttribute(INHERIT_BASE_ATTRIBUTE_NAME);
+ if (inheritId != null) {
+ loadSetupBase(inheritId, filter, configurationElements, setup);
+ }
+ return;
+ }
+ }
+ }
+
+ private static void loadSetupLibraries(final String id, final Map<String, String> filter,
+ final IConfigurationElement[] configurationElements, final RSetup setup)
+ throws Exception {
+ for (int i= 0; i < configurationElements.length; i++) {
+ final IConfigurationElement element= configurationElements[i];
+ if (element.getName().equals(LIBRARY_ELEMENT_NAME)
+ && id.equals(element.getAttribute(SETUP_ID_ATTRIBUTE_NAME)) ) {
+ final String path= getLocation(element, filter);
+ if (path == null) {
+ continue;
+ }
+ final String groupId= element.getAttribute(GROUP_ATTRIBUTE_NAME);
+ if (groupId == null || groupId.length() == 0 || groupId.equals("R_LIBS")) { //$NON-NLS-1$
+ setup.getRLibs().add(path);
+ }
+ else if (groupId.equals("R_LIBS_SITE")) { //$NON-NLS-1$
+ setup.getRLibsSite().add(path);
+ }
+ else if (groupId.equals("R_LIBS_USER")) { //$NON-NLS-1$
+ setup.getRLibsUser().add(path);
+ }
+ else {
+ log(IStatus.WARNING, "Invalid R setup element: " +
+ "Unknown library group '" + groupId + "', the library is ignored", element);
+ }
+ }
+ }
+ }
+
+ private static String getLocation(final IConfigurationElement element, final Map<String, String> filter) throws Exception {
+ final Bundle bundle= Platform.getBundle(element.getContributor().getName());
+ final String path= element.getAttribute(LOCATION_ATTRIBUTE_NAME);
+ if (bundle != null && path != null && path.length() > 0) {
+ final URL[] bundleURLs= FileLocator.findEntries(bundle, new Path(path), filter);
+ for (int i= 0; i < bundleURLs.length; i++) {
+ final URI fileURI= URIUtil.toURI(FileLocator.toFileURL(bundleURLs[i]));
+ if (fileURI.getScheme().equals("file")) { //$NON-NLS-1$
+ final File file= new File(fileURI);
+ if (file.exists() && file.isDirectory() && file.list().length > 0) {
+ return file.getAbsolutePath();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static void log(final int severity, final String message, final IConfigurationElement element) {
+ final StringBuilder info= new StringBuilder(message);
+ if (element != null) {
+ info.append(" (contributed by '");
+ info.append(element.getContributor().getName());
+ info.append("').");
+ }
+ LOGGER.log(new Status(IStatus.WARNING, BUNDLE_ID, info.toString()));
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/.classpath b/core/org.eclipse.statet.rj.data/.classpath
new file mode 100644
index 0000000..f4b5bd5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+ <attributes>
+ <attribute name="owner.project.facets" value="java"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.data/.gitignore b/core/org.eclipse.statet.rj.data/.gitignore
new file mode 100644
index 0000000..934e0e0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target
diff --git a/core/org.eclipse.statet.rj.data/.project b/core/org.eclipse.statet.rj.data/.project
new file mode 100644
index 0000000..d104406
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.project
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.data</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..e4dc2c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="org.eclipse.statet.rj.data">
+ <wb-resource deploy-path="/" source-path="/src"/>
+ </wb-module>
+</project-modules>
diff --git a/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f4ef8aa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.data/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.data/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..20033d3
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.data
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Data
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Export-Package: org.eclipse.statet.rj.data,
+ org.eclipse.statet.rj.data.impl
diff --git a/core/org.eclipse.statet.rj.data/about.html b/core/org.eclipse.statet.rj.data/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.data/about_files/LICENSE.txt b/core/org.eclipse.statet.rj.data/about_files/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/about_files/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/core/org.eclipse.statet.rj.data/build.properties b/core/org.eclipse.statet.rj.data/build.properties
new file mode 100644
index 0000000..9f02c9f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/build.properties
@@ -0,0 +1,8 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ .,\
+ about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RArray.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RArray.java
new file mode 100644
index 0000000..cbbe52e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RArray.java
@@ -0,0 +1,100 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_ARRAY array}, if it is an R
+ * data object of an "atomic" mode with a dimension attribute (<code>dim</code>).
+ * Such an R array object is represented by an instance of this interface.
+ * <p>
+ * The real data is stored in a {@link RStore} accessible by {@link #getData()}.
+ * An index for the one-dimensional data store can be computed from an
+ * index tuple relative to the dimension of the object using the methods
+ * {@link RDataUtils#getDataIdx(int[], int[])}.</p>
+ * <p>
+ * Also an S3 object based on a such a data object is of the type {@link RObject#TYPE_ARRAY array}.
+ * Whereas a S4 object is never directly of this type even the object simulates an
+ * array in R. Such an object is of the type {@link RObject#TYPE_S4OBJECT S4 object},
+ * and implements {@link RS4Object} with an object of the type {@link RObject#TYPE_ARRAY array}
+ * as data slot.</p>
+ * <p>
+ * The complementary type for objects without dimension attribute is the type
+ * {@link RObject#TYPE_VECTOR vector} and the interface {@link RVector}.</p>
+ *
+ * @see RDataUtils#getDataIdx(int[], int[])
+ * @see RDataUtils#getDataIdxs(int[], int, int)
+ * @param <TData> the type of the data store
+ */
+public interface RArray<TData extends RStore<?>> extends RObject {
+
+ /**
+ * Returns the length of the object. The length of an {@link RObject#TYPE_ARRAY array}
+ * is the count of all data values, the product of its dimensions.
+ *
+ * @return the length
+ */
+ @Override
+ long getLength();
+
+ /**
+ * Returns the dimension of this array. This corresponds to the R dimension
+ * attribute (<code>dim</dim>) respectively the R <code>dim</code> function.
+ *
+ * @return the dimension of this array
+ */
+ RIntegerStore getDim();
+
+ /**
+ * Returns the names for the dimensions of the array. This corresponds to
+ * the names of the R attribute <code>dimnames</code> respectively of the R function
+ * <code>dimnames(object)</code>. That means it is equivalent to the R command
+ * <code>names(dimnames(object))</code>. The names for the indexes in each dimension,
+ * the values of the R attribute <code>dimnames</code>, are accessible by {@link #getNames(int)}.
+ *
+ * The returned character data has the same length as the dimension data {@link #getDim()}.
+ * If the R element does not have names, the names are invalid, or names are disabled, the
+ * method returns <code>null</code>.
+ *
+ * @return a charater data store with the names of the dimensions or <code>null</code>
+ *
+ * @since de.walware.rj.data 0.5
+ */
+ RCharacterStore getDimNames();
+
+ /**
+ * Returns the names for the indexes in the given dimension of the array. This corresponds to
+ * the values of the R attribute <code>dimnames</code> respectively of the R function
+ * <code>dimnames(object)</code>. The names for the dimensions itself are accessible by
+ * {@link #getDimNames()}.
+ *
+ * @param dim the dimension index
+ * @return a data store with the names of the indexes in the given dimensions or <code>null</code>
+ * @throws IndexOutOfBoundsException if dim < 0 or dim ≥ getDim().getLength()
+ *
+ * @since de.walware.rj.data 0.5
+ */
+ RStore<?> getNames(int dim);
+
+
+ @Override
+ TData getData();
+
+// void setDim(int[] dim);
+// void setDimNames(RList list);
+// void insert(int dim, int idx);
+// void remove(int dim, int idx);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RCharacterStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RCharacterStore.java
new file mode 100644
index 0000000..d65fc7f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RCharacterStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#CHARACTER}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'character'.</p>
+ */
+public interface RCharacterStore extends RStore<String> {
+
+
+ @Override
+ String get(int idx);
+ @Override
+ String get(long idx);
+
+ @Override
+ String[] toArray();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RComplexStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RComplexStore.java
new file mode 100644
index 0000000..3b16a4c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RComplexStore.java
@@ -0,0 +1,93 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import org.eclipse.statet.rj.data.RComplexStore.Complex;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#COMPLEX}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'complex'.</p>
+ */
+public interface RComplexStore extends RStore<Complex> {
+
+
+ final class Complex {
+
+
+ private final double realValue;
+ private final double imaginaryValue;
+
+
+ public Complex(final double real, final double imaginary) {
+ this.realValue= real;
+ this.imaginaryValue= imaginary;
+ }
+
+
+ public double getRe() {
+ return this.realValue;
+ }
+
+ public double getIm() {
+ return this.imaginaryValue;
+ }
+
+
+ @Override
+ public int hashCode() {
+ final long realBits= Double.doubleToLongBits(this.realValue);
+ final long imaginaryBits= Double.doubleToLongBits(this.imaginaryValue) + 1;
+ return (int) ((realBits ^ (realBits >>> 32)) | (imaginaryBits ^ (imaginaryBits >>> 32)));
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof Complex)) {
+ return false;
+ }
+ final Complex other= (Complex) obj;
+ return (this.realValue == other.realValue && this.imaginaryValue == other.imaginaryValue);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(32);
+ sb.append(Double.toString(this.realValue));
+ if (this.imaginaryValue >= 0.0) {
+ sb.append('+');
+ }
+ sb.append(Double.toString(this.imaginaryValue));
+ sb.append('i');
+ return sb.toString();
+ }
+
+ }
+
+
+ boolean isNaN(int idx);
+ boolean isNaN(long idx);
+
+ @Override
+ Complex get(int idx);
+ @Override
+ Complex get(long idx);
+
+ @Override
+ Complex[] toArray();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataFrame.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataFrame.java
new file mode 100644
index 0000000..836dca6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataFrame.java
@@ -0,0 +1,178 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_DATAFRAME vector}, if it is an R list object
+ * inheriting the R class {@link #CLASSNAME_DATAFRAME data.frame} and compiling with the R rules for
+ * a data frame, especially its children are {@link RVector}s of the same length.
+ * <p>
+ * The methods {@link #getLength()}, {@link #getName(int)}, {@link #get(int)} and
+ * {@link #get(String)}, inherited by the RList interface, provides access to the columns using the
+ * uniform RList API. The methods {@link #getColumnCount()}, {@link #getColumnNames()},
+ * {@link #getColumn(int)} and {@link #getColumn(String)} are data frame specific methods with
+ * similar functionality with direct access to the data stores of the columns, bypassing the RVector
+ * objects.</p>
+ * <p>
+ * The row information of the data frame are accessible by {@link #getRowCount()} and
+ * {@link #getRowNames()}.</p>
+ */
+public interface RDataFrame extends RList, RObject {
+
+ /**
+ * Returns the number of columns of the data frame.
+ * <p>
+ * This method is synonymous to {@link #getColumnCount()}.</p>
+ *
+ * @return the number of columns
+ */
+ @Override
+ long getLength();
+
+ /**
+ * Returns the names of the columns of the data frame.
+ * <p>
+ * This method is synonymous to {@link #getColumnNames()}.</p>
+ *
+ * @return the column names
+ */
+ @Override
+ RCharacterStore getNames();
+
+ /**
+ * Returns the name of the specified column of the data frame.
+ *
+ * @param idx the index (zero-based) of the column
+ * @return the column name
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ column count
+ */
+ @Override
+ String getName(long idx);
+
+ /**
+ * Returns the RVector object of the specified column of the data frame.
+ *
+ * @param idx the index (zero-based) of the column
+ * @return the column vector
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ column count
+ */
+ @Override
+ RObject get(long idx);
+
+ /**
+ * Returns the RVector object of the column with the specified name of the data frame.
+ *
+ * @param name the name of the column
+ * @return the column vector or <code>null</code> (if no column with the specified name exists)
+ */
+ @Override
+ RObject get(String name);
+
+ /**
+ * For a data frame this method always returns <code>null</code>.
+ *
+ * @return <code>null</code>
+ */
+ @Override
+ RStore<?> getData();
+
+
+ /**
+ * Returns the number of columns of the data frame.
+ * <p>
+ * This method is synonymous to {@link #getLength()}.</p>
+ *
+ * @return the number of columns
+ */
+ long getColumnCount();
+
+ /**
+ * Returns the names of the columns of the data frame.
+ * <p>
+ * This method is synonymous to {@link #getNames()}.</p>
+ *
+ * @return the column names
+ */
+ public RCharacterStore getColumnNames();
+
+// String getColumnName(int idx);
+
+ /**
+ * Returns the data store for the specified column of the data frame.
+ * <p>
+ * This method is equivalent to <code>get(idx).getData()</code>.</p>
+ * <p>
+ * Each column data store has the length of {@link #getRowCount()}.</p>
+ *
+ * @param idx the index (zero-based) of the column
+ * @return the data store of the column
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ column count
+ */
+ public RStore<?> getColumn(int idx);
+
+ /**
+ * Returns the data store for the specified column of the data frame.
+ * <p>
+ * This method is equivalent to <code>get(idx).getData()</code>.</p>
+ * <p>
+ * Each column data store has the length of {@link #getRowCount()}.</p>
+ *
+ * @param idx the index (zero-based) of the column
+ * @return the data store of the column
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ column count
+ */
+ public RStore<?> getColumn(long idx);
+
+ /**
+ * Returns the data store for the column with the specified name of the data frame.
+ * <p>
+ * This method is equivalent to <code>get(name).getData()</code> (with additional <code>null</code>
+ * check, if no column with that name exists).</p>
+ * <p>
+ * Each column data store has the length of {@link #getRowCount()}.</p>
+ *
+ * @param name the name of the column
+ * @return the data store of the column or <code>null</code> (if no column with the specified name exists)
+ */
+ public RStore<?> getColumn(String name);
+
+ /**
+ * Returns the number of rows of the data frame.
+ * <p>
+ * Each data store of a column ({@link #getColumn(int)} has this length.
+ *
+ * @return the number of rows
+ */
+ long getRowCount();
+
+ /**
+ * Returns the names of the rows of the data frame.
+ * <p>
+ * This method is equivalent to the R command <code>row.names(obj)</code>.</p>
+ *
+ * @return the row names
+ */
+ RStore<?> getRowNames();
+
+
+// void setColumn(int idx, RStore<?> column);
+// void insertColumn(int idx, RStore<?> column);
+// void removeColumn(int idx);
+
+// void insertRow(int idx);
+// void removeRow(int idx);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataJConverter.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataJConverter.java
new file mode 100644
index 0000000..7e7bdcd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataJConverter.java
@@ -0,0 +1,94 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+
+/**
+ * Converts R data objects to classic Java objects and the other way around.
+ */
+public class RDataJConverter {
+
+
+ private boolean keepArray1;
+
+ private RObjectFactory rObjectFactory;
+
+
+ public void setKeepArray1(final boolean enable) {
+ this.keepArray1= enable;
+ }
+
+ public void setRObjectFactory(final RObjectFactory factory) {
+ this.rObjectFactory= factory;
+ }
+
+ public RObjectFactory getRObjectFactory() {
+ return this.rObjectFactory;
+ }
+
+
+ public Object toJava(final RObject rObject) {
+ switch (rObject.getRObjectType()) {
+ case RObject.TYPE_VECTOR:
+ return toJava(rObject.getData());
+ }
+ return null;
+ }
+
+ public Object toJava(final RStore<?> rData) {
+ final Object[] array= rData.toArray();
+ if (!this.keepArray1 && array != null && array.length == 1) {
+ return array[0];
+ }
+ return array;
+ }
+
+
+
+ public RObject toRJ(final Object javaObj) {
+ if (javaObj instanceof Boolean) {
+ return this.rObjectFactory.createVector(
+ this.rObjectFactory.createLogiData(new boolean[] {
+ ((Boolean) javaObj).booleanValue() }));
+ }
+ if (javaObj instanceof String) {
+ return this.rObjectFactory.createVector(
+ this.rObjectFactory.createCharData(new String[] {
+ (String) javaObj }));
+ }
+ if (javaObj instanceof String[]) {
+ return this.rObjectFactory.createVector(
+ this.rObjectFactory.createCharData((String[]) javaObj) );
+ }
+ if (javaObj instanceof Map) {
+ final Map<?, ?> map= (Map<?, ?>) javaObj;
+ final String[] names= new String[map.size()];
+ final RObject[] components= new RObject[map.size()];
+ int i= 0;
+ for (final Entry<?, ?> entry : map.entrySet()) {
+ names[i]= (String) entry.getKey();
+ components[i]= toRJ(entry.getValue());
+ i++;
+ }
+ return this.rObjectFactory.createList(components, names);
+ }
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataUtils.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataUtils.java
new file mode 100644
index 0000000..2015200
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RDataUtils.java
@@ -0,0 +1,995 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+public class RDataUtils {
+
+ /**
+ * Returns the common abbreviation for the type of the given data store.
+ * These are the abbreviations used by the R function <code>str(x)</code>.
+ * If there is no abbreviation for the given type, it return the class name
+ * of an R vector with data of this type.
+ *
+ * @param store the data store
+ * @return an abbreviation
+ */
+ public static final String getStoreAbbr(final RStore<?> store) {
+ switch (store.getStoreType()) {
+ case RStore.LOGICAL:
+ return "logi";
+ case RStore.INTEGER:
+ return "int";
+ case RStore.NUMERIC:
+ return "num";
+ case RStore.CHARACTER:
+ return "chr";
+ case RStore.COMPLEX:
+ return "cplx";
+ case RStore.RAW:
+ return "raw";
+ case RStore.FACTOR:
+ return ((RFactorStore) store).isOrdered() ? RObject.CLASSNAME_ORDERED : RObject.CLASSNAME_FACTOR;
+ default:
+ return "";
+ }
+ }
+
+ /**
+ * Returns the class name of an R vector with data of the type of the given data store.
+ *
+ * @param store the data store
+ * @return an class name
+ */
+ public static final String getStoreClass(final RStore<?> store) {
+ switch (store.getStoreType()) {
+ case RStore.LOGICAL:
+ return RObject.CLASSNAME_LOGICAL;
+ case RStore.INTEGER:
+ return RObject.CLASSNAME_INTEGER;
+ case RStore.NUMERIC:
+ return RObject.CLASSNAME_NUMERIC;
+ case RStore.CHARACTER:
+ return RObject.CLASSNAME_CHARACTER;
+ case RStore.COMPLEX:
+ return RObject.CLASSNAME_COMPLEX;
+ case RStore.RAW:
+ return RObject.CLASSNAME_RAW;
+ case RStore.FACTOR:
+ return ((RFactorStore) store).isOrdered() ? RObject.CLASSNAME_ORDERED : RObject.CLASSNAME_FACTOR;
+ default:
+ return "";
+ }
+ }
+
+ public static final String getStoreMode(final int storeType) {
+ switch (storeType) {
+ case RStore.LOGICAL:
+ return "logical";
+ case RStore.INTEGER:
+ case RStore.FACTOR:
+ return "integer";
+ case RStore.NUMERIC:
+ return "numeric";
+ case RStore.CHARACTER:
+ return "character";
+ case RStore.COMPLEX:
+ return "complex";
+ case RStore.RAW:
+ return "raw";
+ default:
+ return "";
+ }
+ }
+
+ public static final String getObjectTypeName(final byte type) {
+ switch (type) {
+ case RObject.TYPE_NULL:
+ return "RNullImpl";
+ case RObject.TYPE_VECTOR:
+ return "RVector";
+ case RObject.TYPE_ARRAY:
+ return "RArray";
+ case RObject.TYPE_LIST:
+ return "RList";
+ case RObject.TYPE_DATAFRAME:
+ return "RDataFrame";
+ case RObject.TYPE_S4OBJECT:
+ return "RS4Object";
+ case RObject.TYPE_ENVIRONMENT:
+ return "REnvironment";
+ case RObject.TYPE_LANGUAGE:
+ return "RLanguage";
+ case RObject.TYPE_FUNCTION:
+ return "RFunction";
+ case RObject.TYPE_REFERENCE:
+ return "RReference";
+ case RObject.TYPE_OTHER:
+ return "<other>";
+ case RObject.TYPE_MISSING:
+ return "RMissingImpl";
+ case RObject.TYPE_PROMISE:
+ return "RPromiseImpl";
+ default:
+ return "<unkown>";
+ }
+ }
+
+ public static final long computeLengthFromDim(final int[] dims) {
+ if (dims.length == 0) {
+ return 0;
+ }
+ long length= 1;
+ for (int i= 0; i < dims.length; i++) {
+ length *= dims[i];
+ }
+ return length;
+ }
+
+ public static final long getDataIdx(final int[] dims, final int... idxs) {
+ assert (dims.length > 0);
+ assert (dims.length == idxs.length);
+
+ long dataIdx= idxs[0];
+ long step= dims[0];
+ // alt: idx=0; step=1; i=0;
+ for (int i= 1; i < dims.length; i++) {
+ dataIdx+= step*idxs[i];
+ step *= dims[i];
+ }
+ return dataIdx;
+ }
+
+ public static final long getDataIdx(final RStore<?> dims, final int... idxs) {
+ assert (dims.getLength() > 0);
+ assert (dims.getLength() == idxs.length);
+
+ long dataIdx= idxs[0];
+ long step= dims.getInt(0);
+ // alt: idx=0; step=1; i=0;
+ for (int i= 1; i < dims.getLength(); i++) {
+ dataIdx+= step * idxs[i];
+ step *= dims.getInt(i);
+ }
+ return dataIdx;
+ }
+
+ /**
+ * Computes the index of a data value in a store of a matrix / 2 dimensional arrays
+ * specified by its column and row indexes.
+ *
+ * @param rowCount count of rows of the matrix
+ * @param rowIdx row index (zero-based) of the matrix
+ * @param columnIdx column index (zero-based) of the matrix
+ * @return the index in the data store
+ *
+ * @see #getDataIdx(int[], int...)
+ */
+ public static final long getDataIdx(final long rowCount, final long rowIdx, final long columnIdx) {
+ return rowIdx + rowCount * columnIdx;
+ }
+
+ public static final int[] getDataIdxs(final int[] dims, final int dim, final int idx) {
+ assert (dims.length > 0);
+ assert (0 <= dim && dim < dims.length);
+ assert (0 <= idx && idx < dims[dim]);
+
+ final int size;
+ final int dimsCount= dims.length;
+ if (dimsCount == 1) {
+ size= 1;
+ }
+ else if (dimsCount == 2) {
+ size= dims[(dim == 0) ? 1 : 0];
+ }
+ else {
+ int counter= 1;
+ for (int dimIdx= 0; dimIdx < dimsCount; dimIdx++) {
+ if (dimIdx != dim) {
+ counter *= dims[dimIdx];
+ }
+ }
+ size= counter;
+ }
+
+ final int[] dataIdxs= new int[size];
+ int step= 1;
+ int stepCount= 1;
+ for (int dimIdx= 0; dimIdx < dimsCount; dimIdx++) {
+ final int dimSize= dims[dimIdx];
+ if (dimIdx == dim) {
+ final int add= step*idx;
+ for (int i= 0; i < size; i++) {
+ dataIdxs[i]+= add;
+ }
+ }
+ else {
+ for (int i= 0, idxInDim= 0; i < size; idxInDim++) {
+ if (idxInDim == dimSize) {
+ idxInDim= 0;
+ }
+ final int add= step*idxInDim;
+ for (int j= 0; j < stepCount && i < size; i++,j++) {
+ dataIdxs[i]+= add;
+ }
+ }
+ stepCount *= dimSize;
+ }
+ step *= dimSize;
+ }
+ return dataIdxs;
+ }
+
+
+ public static final boolean isSingleString(final RObject obj) {
+ final RStore<?> data;
+ return (obj != null && (data= obj.getData()) != null
+ && data.getStoreType() == RStore.CHARACTER
+ && data.getLength() == 1 );
+ }
+
+
+ public static final RVector<?> checkRVector(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ return (RVector<?>) obj;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final RVector<RLogicalStore> checkRLogiVector(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ if (obj.getData().getStoreType() != RStore.LOGICAL) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+ }
+ return (RVector<RLogicalStore>) obj;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final RVector<RIntegerStore> checkRIntVector(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ if (obj.getData().getStoreType() != RStore.INTEGER) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+ }
+ return (RVector<RIntegerStore>) obj;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final RVector<RNumericStore> checkRNumVector(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ if (obj.getData().getStoreType() != RStore.NUMERIC) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+ }
+ return (RVector<RNumericStore>) obj;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final RVector<RCharacterStore> checkRCharVector(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_VECTOR) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ if (obj.getData().getStoreType() != RStore.CHARACTER) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getStoreAbbr(obj.getData()));
+ }
+ return (RVector<RCharacterStore>) obj;
+ }
+
+ public static final RArray<?> checkRArray(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ return (RArray<?>) obj;
+ }
+
+ public static final RArray<?> checkRArray(final RObject obj, final int dim) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ final RArray<?> array= (RArray<?>) obj;
+ if (dim > 0) {
+ if (dim != array.getDim().getLength()) {
+ throw new UnexpectedRDataException("Unexpected R array dimension: " + array.getDim().getLength());
+ }
+ }
+ return array;
+ }
+
+ public static final RArray<?> checkRArray(final RObject obj, final long dim) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ final RArray<?> array= (RArray<?>) obj;
+ if (dim > 0) {
+ if (dim != array.getDim().getLength()) {
+ throw new UnexpectedRDataException("Unexpected R array dimension: " + array.getDim().getLength());
+ }
+ }
+ return array;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final RArray<RCharacterStore> checkRCharArray(final RObject obj, final int dim) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_ARRAY) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ if (obj.getData().getStoreType() != RStore.CHARACTER) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(obj.getData()));
+ }
+ final RArray<RCharacterStore> array= (RArray<RCharacterStore>) obj;
+ if (dim > 0) {
+ if (dim != array.getDim().getLength()) {
+ throw new UnexpectedRDataException("Unexpected R array dimension: " + array.getDim().getLength());
+ }
+ }
+ return array;
+ }
+
+ public static final RList checkRList(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_LIST) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ return (RList) obj;
+ }
+
+ public static final RDataFrame checkRDataFrame(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_DATAFRAME) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ return (RDataFrame) obj;
+ }
+
+ public static final RDataFrame checkRDataFrame(final RObject obj, final long length) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_DATAFRAME) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ if (obj.getLength() != length) {
+ throw new UnexpectedRDataException("Unexpected R dataframe column count: " + obj.getLength());
+ }
+ return (RDataFrame) obj;
+ }
+
+ public static final RReference checkRReference(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_REFERENCE) {
+ throw new UnexpectedRDataException(
+ "Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) );
+ }
+ return (RReference) obj;
+ }
+
+ public static final RReference checkRReference(final RObject obj, final byte referencedObjectType)
+ throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_REFERENCE) {
+ throw new UnexpectedRDataException(
+ "Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) );
+ }
+ final RReference reference= (RReference) obj;
+ if (reference.getReferencedRObjectType() != referencedObjectType) {
+ throw new UnexpectedRDataException(
+ "Unexpected referenced R object type: " + getObjectTypeName(obj.getRObjectType()) +
+ ", but " + getObjectTypeName(referencedObjectType) + " expected." );
+ }
+ return (RReference) obj;
+ }
+
+ public static final RLanguage checkRLanguage(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != RObject.TYPE_LANGUAGE) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()));
+ }
+ return (RLanguage) obj;
+ }
+
+ public static final Boolean checkSingleLogi(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.LOGICAL) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ if (data.isNA(0)) {
+ return null;
+ }
+ return Boolean.valueOf(data.getLogi(0));
+ }
+
+ public static final boolean checkSingleLogiValue(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.LOGICAL) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ if (data.isNA(0)) {
+ throw new UnexpectedRDataException("Unexpected R data value: NA");
+ }
+ return data.getLogi(0);
+ }
+
+ public static final Integer checkSingleInt(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.INTEGER) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ if (data.isNA(0)) {
+ return null;
+ }
+ return Integer.valueOf(data.getInt(0));
+ }
+
+ public static final int checkSingleIntValue(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.INTEGER) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ if (data.isNA(0)) {
+ throw new UnexpectedRDataException("Unexpected R data value: NA");
+ }
+ return data.getInt(0);
+ }
+
+ public static final Double checkSingleNum(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.NUMERIC) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ if (data.isNA(0)) {
+ return null;
+ }
+ return Double.valueOf(data.getNum(0));
+ }
+
+ public static final double checkSingleNumValue(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.NUMERIC) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ if (data.isNA(0)) {
+ throw new UnexpectedRDataException("Unexpected R data value: NA");
+ }
+ return data.getNum(0);
+ }
+
+ public static final String checkSingleChar(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.CHARACTER) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ return data.getChar(0);
+ }
+
+ public static final String checkSingleCharValue(final RObject obj) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ final RStore<?> data= obj.getData();
+ if (data == null) {
+ throw new UnexpectedRDataException("Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) + " (without R data)");
+ }
+ if (data.getStoreType() != RStore.CHARACTER) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data));
+ }
+ if (data.getLength() != 1) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == 1 expected.");
+ }
+ if (data.isNA(0)) {
+ throw new UnexpectedRDataException("Unexpected R data value: NA");
+ }
+ return data.getChar(0);
+ }
+
+ public static final RObject checkType(final RObject obj, final byte objectType) throws UnexpectedRDataException {
+ if (obj == null) {
+ throw new UnexpectedRDataException("Missing R object.");
+ }
+ if (obj.getRObjectType() != objectType) {
+ throw new UnexpectedRDataException(
+ "Unexpected R object type: " + getObjectTypeName(obj.getRObjectType()) +
+ ", but " + getObjectTypeName(objectType) + " expected." );
+ }
+ return obj;
+ }
+
+ public static final RStore<?> checkData(final RStore<?> data, final byte storeType) throws UnexpectedRDataException {
+ if (data.getStoreType() != storeType) {
+ throw new UnexpectedRDataException("Unexpected R data type: " + getStoreAbbr(data) + ", but " + storeType + " expected.");
+ }
+ return data;
+ }
+
+
+ public static final int checkIntLength(final RObject obj) throws UnexpectedRDataException {
+ return checkIntLength(obj.getLength());
+ }
+
+ public static final int checkIntLength(final RStore<?> data) throws UnexpectedRDataException {
+ return checkIntLength(data.getLength());
+ }
+
+ public static final int checkIntLength(final long length) throws UnexpectedRDataException {
+ if (length < 0 || length > Integer.MAX_VALUE) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + length + ", but <= 2^31-1 expected.");
+ }
+ return (int) length;
+ }
+
+ public static final int checkIntIdx(final long idx) throws UnexpectedRDataException {
+ if (idx < 0 || idx >= Integer.MAX_VALUE) {
+ throw new UnexpectedRDataException("Unexpected R data index: " + idx + ", but < 2^31-1 expected.");
+ }
+ return (int) idx;
+ }
+
+ public static final <T extends RObject> T checkLengthEqual(final T obj, final long length) throws UnexpectedRDataException {
+ if (obj.getLength() != length) {
+ throw new UnexpectedRDataException("Unexpected R object length: " + obj.getLength() + ", but == " + length + " expected.");
+ }
+ return obj;
+ }
+
+ public static final <TData extends RStore<?>> TData checkLengthEqual(final TData data,
+ final long length)
+ throws UnexpectedRDataException {
+ if (data.getLength() != length) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but == " + length + " expected.");
+ }
+ return data;
+ }
+
+ public static final <TData extends RStore<?>> TData checkLengthGreaterOrEqual(final TData data,
+ final long length)
+ throws UnexpectedRDataException {
+ if (data.getLength() < length) {
+ throw new UnexpectedRDataException("Unexpected R data length: " + data.getLength() + ", but >= " + length + " expected.");
+ }
+ return data;
+ }
+
+ public static final <P> P checkValue(final RStore<P> data, final int idx) throws UnexpectedRDataException {
+ final P value= data.get(idx);
+ if (value == null) {
+ throw new UnexpectedRDataException("Unexpected R data value: NA");
+ }
+ return value;
+ }
+
+ public static final <P> P checkValue(final RStore<P> data, final long idx) throws UnexpectedRDataException {
+ final P value= data.get(idx);
+ if (value == null) {
+ throw new UnexpectedRDataException("Unexpected R data value: NA");
+ }
+ return value;
+ }
+
+ public static final <P> P getValue(final RStore<P> data, final int idx, final P na) {
+ final P value= data.get(idx);
+ return (value != null) ? value : na;
+ }
+
+ public static final <P> P getValue(final RStore<P> data, final long idx, final P na) {
+ final P value= data.get(idx);
+ return (value != null) ? value : na;
+ }
+
+
+ /*-- 2d --*/
+
+ public static final int getRowCount(final RArray<?> array) throws UnexpectedRDataException {
+ return array.getDim().getInt(0);
+ }
+
+ public static final void checkRowCountEqual(final RArray<?> array, final int count) throws UnexpectedRDataException {
+ if (array.getDim().getInt(0) != count) {
+ throw new UnexpectedRDataException("Unexpected R matrix row count: " + array.getDim().getInt(0) + ", but == " + count + " expected.");
+ }
+ }
+
+ public static final void checkRowCountEqual(final RDataFrame dataframe, final long count) throws UnexpectedRDataException {
+ if (dataframe.getRowCount() != count) {
+ throw new UnexpectedRDataException("Unexpected R dataframe row count: " + dataframe.getRowCount() + ", but == " + count + " expected.");
+ }
+ }
+
+ public static final int getColumnCount(final RArray<?> array) throws UnexpectedRDataException {
+ return array.getDim().getInt(1);
+ }
+
+ public static final void checkColumnCountEqual(final RArray<?> array, final int count) throws UnexpectedRDataException {
+ if (array.getDim().getInt(1) != count) {
+ throw new UnexpectedRDataException("Unexpected R matrix column count: " + array.getDim().getInt(1) + ", but == " + count + " expected.");
+ }
+ }
+
+ public static final long checkColumnName(final RArray<?> array, final String name) throws UnexpectedRDataException {
+ final long idx= array.getNames(1).indexOf(name);
+ if (idx < 0) {
+ throw new UnexpectedRDataException("Missing R matrix column: " + name);
+ }
+ return idx;
+ }
+
+ public static final void checkColumnCountEqual(final RDataFrame dataframe, final long count) throws UnexpectedRDataException {
+ if (dataframe.getColumnCount() != count) {
+ throw new UnexpectedRDataException("Unexpected R dataframe column count: " + dataframe.getColumnCount() + ", but == " + count + " expected.");
+ }
+ }
+
+
+ /*-- int --*/
+
+ public static final long binarySearch(final RVector<?> vector, final int value) {
+ final RStore<?> data= vector.getData();
+ return binarySearch(data, 0, data.getLength(), value);
+ }
+
+ public static final long binarySearch(final RStore<?> data, final int value) {
+ return binarySearch(data, 0, data.getLength(), value);
+ }
+
+ public static final int binarySearch(final RStore<?> data, final int fromIdx, final int toIdx, final int value) {
+ if (fromIdx < 0 || fromIdx > data.getLength()
+ || toIdx < 0 || toIdx > data.getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+ }
+ if (fromIdx > toIdx) {
+ throw new IllegalArgumentException();
+ }
+
+ return doBinarySearch(data, fromIdx, toIdx - 1, value);
+ }
+
+ private static int doBinarySearch(final RStore<?> data, int low, int high, final int value) {
+ while (low <= high) {
+ final int mid= (low + high) >>> 1;
+ final int midValue= data.getInt(mid);
+ if (midValue < value) {
+ low= mid + 1;
+ }
+ else if (midValue > value) {
+ high= mid - 1;
+ }
+ else {
+ return mid; // key found
+ }
+ }
+ return -(low + 1); // key not found.
+ }
+
+ public static final long binarySearch(final RStore<?> data, final long fromIdx, final long toIdx, final int value) {
+ if (fromIdx < 0 || fromIdx > data.getLength()
+ || toIdx < 0 || toIdx > data.getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+ }
+ if (fromIdx > toIdx) {
+ throw new IllegalArgumentException();
+ }
+ if (toIdx <= Integer.MAX_VALUE) {
+ return doBinarySearch(data, (int) fromIdx, (int) toIdx - 1, value);
+ }
+
+ return doBinarySearch(data, fromIdx, toIdx - 1, value);
+ }
+
+ private static long doBinarySearch(final RStore<?> data, long low, long high, final int value) {
+ while (low <= high) {
+ final long mid= (low + high) >>> 1;
+ final int midValue= data.getInt(mid);
+ if (midValue < value) {
+ low= mid + 1;
+ }
+ else if (midValue > value) {
+ high= mid - 1;
+ }
+ else {
+ return mid; // key found
+ }
+ }
+ return -(low + 1); // key not found.
+ }
+
+ public static final int binarySearch(final RStore<?> data,
+ final long[] fromIdxs, final int length, final int[] values) {
+ if (fromIdxs.length > values.length) {
+ throw new IllegalArgumentException();
+ }
+ if (length < 0 || length > data.getLength()) {
+ throw new IllegalArgumentException();
+ }
+ for (int i= 0; i < fromIdxs.length; i++) {
+ if (fromIdxs[i] < 0 || fromIdxs[i] + length > data.getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(fromIdxs[i]));
+ }
+ }
+
+ int low= 0;
+ int high= length - 1;
+ ITER_IDX: while (low <= high) {
+ final int mid= (low + high) >>> 1;
+ for (int i= 0; i < fromIdxs.length; i++) {
+ final int midValue= data.getInt(fromIdxs[i] + mid);
+ if (midValue < values[i]) {
+ low= mid + 1;
+ continue ITER_IDX;
+ }
+ if (midValue > values[i]) {
+ high= mid - 1;
+ continue ITER_IDX;
+ }
+ }
+ return mid; // key found
+ }
+ return -(low + 1); // key not found.
+ }
+
+ public static final int compare(final int[] values1, final int[] values2) {
+ for (int i= 0; i < values1.length; i++) {
+ if (values1[i] < values2[i]) {
+ return -1;
+ }
+ if (values1[i] > values2[i]) {
+ return +1;
+ }
+ }
+ return 0; // equal
+ }
+
+
+ /*-- long ~ num -- */
+
+ public static final long binarySearch(final RStore<?> data, final long value) {
+ return binarySearch(data, 0, data.getLength(), value);
+ }
+
+ public static final int binarySearch(final RStore<?> data, final int fromIdx, final int toIdx, final long value) {
+ if (fromIdx < 0 || fromIdx > data.getLength()
+ || toIdx < 0 || toIdx > data.getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+ }
+ if (fromIdx > toIdx) {
+ throw new IllegalArgumentException();
+ }
+
+ return doBinarySearch(data, fromIdx, toIdx - 1, value);
+ }
+
+ private static int doBinarySearch(final RStore<?> data, int low, int high, final long value) {
+ while (low <= high) {
+ final int mid= (low + high) >>> 1;
+ final double midValue= data.getNum(mid);
+ if (midValue < value) {
+ low= mid + 1;
+ }
+ else if (midValue > value) {
+ high= mid - 1;
+ }
+ else {
+ return mid; // key found
+ }
+ }
+ return -(low + 1); // key not found.
+ }
+
+ public static final long binarySearch(final RStore<?> data, final long fromIdx, final long toIdx, final long value) {
+ if (fromIdx < 0 || fromIdx > data.getLength()
+ || toIdx < 0 || toIdx > data.getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(fromIdx));
+ }
+ if (fromIdx > toIdx) {
+ throw new IllegalArgumentException();
+ }
+ if (toIdx <= Integer.MAX_VALUE) {
+ return doBinarySearch(data, (int) fromIdx, (int) toIdx - 1, value);
+ }
+
+ return doBinarySearch(data, fromIdx, toIdx - 1, value);
+ }
+
+ private static long doBinarySearch(final RStore<?> data, long low, long high, final long value) {
+ while (low <= high) {
+ final long mid= (low + high) >>> 1;
+ final double midValue= data.getNum(mid);
+ if (midValue < value) {
+ low= mid + 1;
+ }
+ else if (midValue > value) {
+ high= mid - 1;
+ }
+ else {
+ return mid; // key found
+ }
+ }
+ return -(low + 1); // key not found.
+ }
+
+ public static final int binarySearch(final RStore<?> data,
+ final long[] fromIdxs, final int length, final long[] values) {
+ if (fromIdxs.length > values.length) {
+ throw new IllegalArgumentException();
+ }
+ if (length < 0 || length > data.getLength()) {
+ throw new IllegalArgumentException();
+ }
+ for (int i= 0; i < fromIdxs.length; i++) {
+ if (fromIdxs[i] < 0 || fromIdxs[i] + length > data.getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(fromIdxs[i]));
+ }
+ }
+
+ int low= 0;
+ int high= length - 1;
+ ITER_IDX: while (low <= high) {
+ final int mid= (low + high) >>> 1;
+ for (int i= 0; i < fromIdxs.length; i++) {
+ final double midValue= data.getNum(fromIdxs[i] + mid);
+ if (midValue < values[i]) {
+ low= mid + 1;
+ continue ITER_IDX;
+ }
+ if (midValue > values[i]) {
+ high= mid - 1;
+ continue ITER_IDX;
+ }
+ }
+ return mid; // key found
+ }
+ return -(low + 1); // key not found.
+ }
+
+ public static final int compare(final long[] values1, final long[] values2) {
+ for (int i= 0; i < values1.length; i++) {
+ if (values1[i] < values2[i]) {
+ return -1;
+ }
+ if (values1[i] > values2[i]) {
+ return +1;
+ }
+ }
+ return 0; // equal
+ }
+
+
+ public static final byte[] encodeLongToRaw(final long id) {
+ final byte[] raw= new byte[8];
+ raw[0]= (byte) (id >>> 56);
+ raw[1]= (byte) (id >>> 48);
+ raw[2]= (byte) (id >>> 40);
+ raw[3]= (byte) (id >>> 32);
+ raw[4]= (byte) (id >>> 24);
+ raw[5]= (byte) (id >>> 16);
+ raw[6]= (byte) (id >>> 8);
+ raw[7]= (byte) (id);
+ return raw;
+ }
+
+ public static final long decodeLongFromRaw(final byte[] raw) {
+ return( ((long) (raw[0] & 0xff) << 56) |
+ ((long) (raw[1] & 0xff) << 48) |
+ ((long) (raw[2] & 0xff) << 40) |
+ ((long) (raw[3] & 0xff) << 32) |
+ ((long) (raw[4] & 0xff) << 24) |
+ ((raw[5] & 0xff) << 16) |
+ ((raw[6] & 0xff) << 8) |
+ ((raw[7] & 0xff)) );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/REnvironment.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/REnvironment.java
new file mode 100644
index 0000000..a0d0d2e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/REnvironment.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_ENVIRONMENT environment}, if the
+ * object is an R environment. Such an R environment object is represented
+ * by an instance of this interface.
+ * <p>
+ * The R function <code>typeof(object)</code> returns 'environment' for objects
+ * of this type.</p>
+ * <p>
+ * Even the interface extends {@link RList}, the objects are not a list in R!
+ * The inheritance is only for a uniform API.</p>
+ */
+public interface REnvironment extends RList {
+
+ /**
+ * Environment name of the global environment
+ * (<code>.GlobalEnv</code>)
+ *
+ * Name: {@value}
+ **/
+ String ENVNAME_GLOBAL= "R_GlobalEnv";
+
+ /**
+ * Environment name of the empty environment
+ * (<code>emptyenv()</code>)
+ *
+ * Name: {@value}
+ **/
+ String ENVNAME_EMPTY= "R_EmptyEnv";
+
+ /**
+ * Environment name of the base environment
+ * (<code>baseenv()</code>)
+ *
+ * Name: {@value}
+ **/
+ String ENVNAME_BASE= "base";
+
+ /**
+ * Environment name of the Autoloads environment
+ * (<code>.AutoloadEnv</code>)
+ *
+ * Name: {@value}
+ **/
+ String ENVNAME_AUTOLOADS= "Autoloads";
+
+
+ byte ENVTYPE_BASE= 0x01;
+ byte ENVTYPE_AUTOLOADS= 0x02;
+ byte ENVTYPE_PACKAGE= 0x05;
+ byte ENVTYPE_GLOBAL= 0x07;
+
+ byte ENVTYPE_EMTPY= 0x09;
+
+ /**
+ * @since de.walware.rj.data 2.1
+ */
+ byte ENVTYPE_NAMESPACE= 0x0B;
+ /**
+ * @since de.walware.rj.data 2.1
+ */
+ byte ENVTYPE_NAMESPACE_EXPORTS= 0x0C;
+
+
+ /**
+ * Returns the length of the object. The length of an {@link RObject#TYPE_ENVIRONMENT environment}
+ * is the count the objects in the environment.
+ *
+ * At moment, the length of an {@link RObject#TYPE_ENVIRONMENT environment} is always ≤ 2<sup>31</sup>-1
+ * (representable by Java int).
+ *
+ * @return the length
+ */
+ @Override
+ long getLength();
+
+ /**
+ * Indicates a special environment type (> 0)
+ * see <code>ENVTYPE_</code> constants defined in {@link REnvironment}.
+ *
+ * @return the type constant or <= 0
+ */
+ int getSpecialType();
+
+ /**
+ * Returns the environment name of the environment. This is the return value
+ * of the R command <code>environmentName(object)</code>.
+ *
+ * @return the environment name
+ */
+ String getEnvironmentName();
+
+ long getHandle();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFactorStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFactorStore.java
new file mode 100644
index 0000000..dade50e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFactorStore.java
@@ -0,0 +1,41 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#FACTOR}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>class(object)</code> returns 'factor'.</p>
+ */
+public interface RFactorStore extends RIntegerStore {
+
+ // TODO Docu && Constructors (-> 1-based codes)
+ // TODO getFactorName(code) for 1-based code
+
+ boolean isOrdered();
+
+ RCharacterStore getLevels();
+ int getLevelCount();
+
+// void addLevel(final String label);
+// void renameLevel(final String oldLabel, final String newLabel);
+// void insertLevel(final int position, final String label);
+// void removeLevel(final String label);
+
+ RCharacterStore toCharacterData();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFunction.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFunction.java
new file mode 100644
index 0000000..e42df51
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RFunction.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+public interface RFunction extends RObject {
+
+// RArgument getArgument(final int idx);
+// RArgument getArgument(final String name);
+// int getArgumentIdx(final String name);
+// Iterator<RArgument> getArgumentIterator();
+
+ // source based
+ String getHeaderSource();
+ String getBodySource();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RIntegerStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RIntegerStore.java
new file mode 100644
index 0000000..1a0174c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RIntegerStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#INTEGER}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'integer'.</p>
+ */
+public interface RIntegerStore extends RStore<Integer> {
+
+
+ @Override
+ Integer get(int idx);
+ @Override
+ Integer get(long idx);
+
+ @Override
+ Integer[] toArray();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIO.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIO.java
new file mode 100644
index 0000000..4a13d96
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIO.java
@@ -0,0 +1,1061 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.DoubleBuffer;
+import java.nio.IntBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ * IO implementation for RJ data serialization.
+ */
+public final class RJIO {
+
+
+ private static final ThreadLocal<RJIO> INSTANCES= new ThreadLocal<RJIO>() {
+
+ @Override
+ protected RJIO initialValue() {
+ return new RJIO();
+ }
+
+ };
+
+ public static RJIO get(final ObjectOutput out) {
+ final RJIO io= INSTANCES.get();
+ io.connect(out);
+ return io;
+ }
+
+ public static RJIO get(final ObjectInput in) {
+ final RJIO io= INSTANCES.get();
+ io.connect(in);
+ return io;
+ }
+
+
+ private static final int BB_LENGTH= 16384;
+ private static final int BA_LENGTH= BB_LENGTH;
+ private static final int BB_PART= BB_LENGTH / 4;
+ private static final int CB_LENGTH= BB_LENGTH / 2;
+ private static final int CA_LENGTH= BB_LENGTH * 4;
+ private static final int IB_LENGTH= BB_LENGTH / 4;
+ private static final int DB_LENGTH= BB_LENGTH / 8;
+
+ private static final int[] EMPTY_INT_ARRAY= new int[0];
+
+ private static final byte MODE_BBARRAY= 0;
+ private static final byte MODE_IPARRAY= 1;
+
+
+ private final ByteBuffer bb;
+ private final byte[] ba;
+ private final CharBuffer cb;
+ private final char[] ca;
+ private final IntBuffer ib;
+ private final DoubleBuffer db;
+ private final byte mode;
+
+ private ObjectInput in;
+
+ private ObjectOutput out;
+
+ private int temp;
+
+ public int flags;
+
+ private int serialKey;
+
+
+ public RJIO() {
+ this.bb= ByteBuffer.allocateDirect(BB_LENGTH);
+ if (this.bb.hasArray()) {
+ this.mode= MODE_BBARRAY;
+ this.ba= this.bb.array();
+ }
+ else {
+ this.mode= MODE_IPARRAY;
+ this.ba= new byte[BB_LENGTH];
+ }
+ this.cb= this.bb.asCharBuffer();
+ this.ca= new char[CA_LENGTH];
+ this.ib= this.bb.asIntBuffer();
+ this.db= this.bb.asDoubleBuffer();
+
+ this.serialKey= (int) System.currentTimeMillis();
+ }
+
+
+ public void connect(final ObjectOutput out) {
+ this.out= out;
+ }
+
+ public void connect(final ObjectInput in) {
+ this.in= in;
+ }
+
+ public void disconnect(final ObjectOutput out) throws IOException {
+ this.out.flush();
+ this.out= null;
+ }
+
+ public void disconnect(final ObjectInput in) throws IOException {
+ this.in= null;
+ }
+
+
+ private void writeFullyBB(final int bn) throws IOException {
+ switch (this.mode) {
+ case MODE_BBARRAY:
+ this.out.write(this.ba, 0, bn);
+ return;
+// case MODE_IPARRAY:
+ default:
+ this.bb.clear();
+ this.bb.get(this.ba, 0, bn);
+ this.out.write(this.ba, 0, bn);
+ return;
+ }
+ }
+
+ private void readFullyBB(final int bn) throws IOException {
+ switch (this.mode) {
+ case MODE_BBARRAY:
+ this.in.readFully(this.ba, 0, bn);
+ return;
+// case MODE_IPARRAY:
+ default:
+ this.in.readFully(this.ba, 0, bn);
+ this.bb.clear();
+ this.bb.put(this.ba, 0, bn);
+ return;
+ }
+ }
+
+ private void readFullyBB(final int pos, final int bn) throws IOException {
+ switch (this.mode) {
+ case MODE_BBARRAY:
+ this.in.readFully(this.ba, pos, bn);
+ return;
+// case MODE_IPARRAY:
+ default:
+ this.in.readFully(this.ba, pos, bn);
+ this.bb.clear();
+ this.bb.put(this.ba, 0, pos+bn);
+// this.bb.position(pos);
+// this.bb.put(this.ba, pos, bn);
+ return;
+ }
+ }
+
+
+ public void writeDirectly(final byte[] bytes, final int off, final int n) throws IOException {
+ this.out.write(bytes, off, n);
+ }
+
+
+ public void writeByte(final byte value) throws IOException {
+ this.out.writeByte(value);
+ }
+
+ public void writeByte(final int value) throws IOException {
+ this.out.writeByte(value);
+ }
+
+ public void writeBoolean(final boolean value) throws IOException {
+ this.out.writeByte(value ? 0x1 : 0x0);
+ }
+
+ public void writeInt(final int value) throws IOException {
+ this.out.writeInt(value);
+ }
+
+ public void writeIntArray(final int[] array, final int length) throws IOException {
+ final ObjectOutput out= this.out;
+ out.writeInt(length);
+ if (length <= 32) {
+ for (int i= 0; i < length; i++) {
+ out.writeInt(array[i]);
+ }
+ }
+ else if (length <= IB_LENGTH) {
+ this.ib.clear();
+ this.ib.put(array, 0, length);
+ writeFullyBB((length << 2));
+ }
+ else {
+ int iw= 0;
+ while (iw < length) {
+ final int icount= Math.min(length - iw, IB_LENGTH);
+ this.ib.clear();
+ this.ib.put(array, iw, icount);
+ writeFullyBB((icount << 2));
+ iw+= icount;
+ }
+ }
+ }
+
+ public void writeIntData(final int[] array, final int length) throws IOException {
+ final ObjectOutput out= this.out;
+ if (length <= 32) {
+ for (int i= 0; i < length; i++) {
+ out.writeInt(array[i]);
+ }
+ }
+ else if (length <= IB_LENGTH) {
+ this.ib.clear();
+ this.ib.put(array, 0, length);
+ writeFullyBB((length << 2));
+ }
+ else {
+ int iw= 0;
+ while (iw < length) {
+ final int icount= Math.min(length - iw, IB_LENGTH);
+ this.ib.clear();
+ this.ib.put(array, iw, icount);
+ writeFullyBB((icount << 2));
+ iw+= icount;
+ }
+ }
+ }
+
+ public void writeLong(final long value) throws IOException {
+ this.out.writeLong(value);
+ }
+
+ public byte getVULongGrade(final long value) {
+ if ((value & 0xffffffffffffff00L) == 0) {
+ return (byte) 0;
+ }
+ if ((value & 0xffffffffffff0000L) == 0) {
+ return (byte) 1;
+ }
+ if ((value & 0xffffffffff000000L) == 0) {
+ return (byte) 2;
+ }
+ if ((value & 0xffffffff00000000L) == 0) {
+ return (byte) 3;
+ }
+ if ((value & 0xffffff0000000000L) == 0) {
+ return (byte) 4;
+ }
+ if ((value & 0xffff000000000000L) == 0) {
+ return (byte) 5;
+ }
+ if ((value & 0xff00000000000000L) == 0) {
+ return (byte) 6;
+ }
+ return 7;
+ }
+
+ public void writeVULong(final byte grade, final long value) throws IOException {
+ if (grade == 0) {
+ this.out.writeByte((int) value);
+ return;
+ }
+ final byte[] ba= this.ba;
+ switch (grade) {
+// case 0:
+// ba[0]= (byte) (value);
+// this.out.write(ba, 0, 1);
+// return;
+ case 1:
+ ba[0]= (byte) (value >>> 8);
+ ba[1]= (byte) (value);
+ this.out.write(ba, 0, 2);
+ return;
+ case 2:
+ ba[0]= (byte) (value >>> 16);
+ ba[1]= (byte) (value >>> 8);
+ ba[2]= (byte) (value);
+ this.out.write(ba, 0, 3);
+ return;
+ case 3:
+ ba[0]= (byte) (value >>> 24);
+ ba[1]= (byte) (value >>> 16);
+ ba[2]= (byte) (value >>> 8);
+ ba[3]= (byte) (value);
+ this.out.write(ba, 0, 4);
+ return;
+ case 4:
+ ba[0]= (byte) (value >>> 32);
+ ba[1]= (byte) (value >>> 24);
+ ba[2]= (byte) (value >>> 16);
+ ba[3]= (byte) (value >>> 8);
+ ba[4]= (byte) (value);
+ this.out.write(ba, 0, 5);
+ return;
+ case 5:
+ ba[0]= (byte) (value >>> 40);
+ ba[1]= (byte) (value >>> 32);
+ ba[2]= (byte) (value >>> 24);
+ ba[3]= (byte) (value >>> 16);
+ ba[4]= (byte) (value >>> 8);
+ ba[5]= (byte) (value);
+ this.out.write(ba, 0, 6);
+ return;
+ case 6:
+ ba[0]= (byte) (value >>> 48);
+ ba[1]= (byte) (value >>> 40);
+ ba[2]= (byte) (value >>> 32);
+ ba[3]= (byte) (value >>> 24);
+ ba[4]= (byte) (value >>> 16);
+ ba[5]= (byte) (value >>> 8);
+ ba[6]= (byte) (value);
+ this.out.write(ba, 0, 7);
+ return;
+ case 7:
+ ba[0]= (byte) (value >>> 56);
+ ba[1]= (byte) (value >>> 48);
+ ba[2]= (byte) (value >>> 40);
+ ba[3]= (byte) (value >>> 32);
+ ba[4]= (byte) (value >>> 24);
+ ba[5]= (byte) (value >>> 16);
+ ba[6]= (byte) (value >>> 8);
+ ba[7]= (byte) (value);
+ this.out.write(ba, 0, 8);
+ return;
+ default:
+ throw new IOException("Unsupported data format (c= " + grade + ").");
+ }
+ }
+
+ public void writeDouble(final double value) throws IOException {
+ this.out.writeDouble(value);
+ }
+
+ public void writeDoubleData(final double[] array, final int length) throws IOException {
+ final ObjectOutput out= this.out;
+ if (length <= 16) {
+ for (int i= 0; i < length; i++) {
+ out.writeLong(Double.doubleToRawLongBits(array[i]));
+ }
+ }
+ else if (length <= DB_LENGTH) {
+ this.db.clear();
+ this.db.put(array, 0, length);
+ writeFullyBB((length << 3));
+ }
+ else {
+ int dw= 0;
+ while (dw < length) {
+ final int dcount= Math.min(length - dw, DB_LENGTH);
+ this.db.clear();
+ this.db.put(array, dw, dcount);
+ writeFullyBB((dcount << 3));
+ dw+= dcount;
+ }
+ }
+ }
+
+ public void writeFloat(final float value) throws IOException {
+ this.out.writeFloat(value);
+ }
+
+
+ public void writeByteData(final byte[] array, final int length) throws IOException {
+ final ObjectOutput out= this.out;
+ out.write(array, 0, length);
+ }
+
+ @SuppressWarnings("deprecation")
+ public void writeString(final String s) throws IOException {
+ final ObjectOutput out= this.out;
+ if (s != null) {
+ final int cn= s.length();
+ ASCII: if (cn <= BA_LENGTH) {
+ for (int ci= 0; ci < cn; ) {
+ if ((s.charAt(ci++) & 0xffffff00) != 0) {
+ break ASCII;
+ }
+ }
+ if (cn <= 8) {
+ out.writeInt(-cn);
+ out.writeBytes(s);
+ return;
+ }
+ else {
+ out.writeInt(-cn);
+ s.getBytes(0, cn, this.ba, 0);
+ out.write(this.ba, 0, cn);
+ return;
+ }
+ }
+ out.writeInt(cn);
+ out.writeChars(s);
+ return;
+ }
+ else {
+ out.writeInt(Integer.MIN_VALUE);
+ return;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void writeStringData(final String[] sa, final int length) throws IOException {
+ final ObjectOutput out= this.out;
+ ARRAY: for (int i= 0; i < length; i++) {
+ final String s= sa[i];
+ if (s != null) {
+ final int cn= s.length();
+ ASCII: if (cn <= BA_LENGTH) {
+ for (int ci= 0; ci < cn; ) {
+ if ((s.charAt(ci++) & 0xffffff00) != 0) {
+ break ASCII;
+ }
+ }
+ if (cn <= 8) {
+ out.writeInt(-cn);
+ out.writeBytes(s);
+ continue ARRAY;
+ }
+ else {
+ out.writeInt(-cn);
+ s.getBytes(0, cn, this.ba, 0);
+ out.write(this.ba, 0, cn);
+ continue ARRAY;
+ }
+ }
+ out.writeInt(cn);
+ out.writeChars(s);
+ continue ARRAY;
+ }
+ else {
+ out.writeInt(Integer.MIN_VALUE);
+ continue ARRAY;
+ }
+ }
+ }
+
+ public void writeStringKeyMap(final Map<String, Object> map) throws IOException {
+ final ObjectOutput out= this.out;
+ if (map == null) {
+ out.writeInt(-1);
+ return;
+ }
+ out.writeInt(map.size());
+ for (final Entry<String, Object> entry : map.entrySet()) {
+ writeString(entry.getKey());
+ out.writeObject(entry.getValue());
+ }
+ }
+
+
+ public byte readByte() throws IOException {
+ return this.in.readByte();
+ }
+
+ public boolean readBoolean() throws IOException {
+ return (this.in.readByte() == 0x1);
+ }
+
+ public int readInt() throws IOException {
+ return this.in.readInt();
+ }
+
+ public int[] readIntData(final int[] array, final int length) throws IOException {
+ final ObjectInput in= this.in;
+ if (length <= 256) {
+ switch (length) {
+ case 0:
+ return array;
+ case 1:
+ array[0]= in.readInt();
+ return array;
+ case 2:
+ array[0]= in.readInt();
+ array[1]= in.readInt();
+ return array;
+ case 3:
+ array[0]= in.readInt();
+ array[1]= in.readInt();
+ array[2]= in.readInt();
+ return array;
+ case 4:
+ array[0]= in.readInt();
+ array[1]= in.readInt();
+ array[2]= in.readInt();
+ array[3]= in.readInt();
+ return array;
+ default:
+ final int bn= length << 2;
+ in.readFully(this.ba, 0, bn);
+ for (int ib= 0; ib < bn; ib+= 4) {
+ array[ib >>> 2]= (
+ ((this.ba[ib] & 0xff) << 24) |
+ ((this.ba[ib+1] & 0xff) << 16) |
+ ((this.ba[ib+2] & 0xff) << 8) |
+ ((this.ba[ib+3] & 0xff)) );
+ }
+ return array;
+ }
+ }
+ else if (length <= IB_LENGTH) {
+ readFullyBB((length << 2));
+ this.ib.clear();
+ this.ib.get(array, 0, length);
+ return array;
+ }
+ else {
+ int ir= 0;
+ int position= 0;
+ final int bToComplete;
+ while (true) {
+ position+= in.read(this.ba, position, BA_LENGTH-position);
+ if (position >= BB_PART) {
+ final int icount= (position >>> 2);
+ final int bcount= (icount << 2);
+ if (this.mode != MODE_BBARRAY) {
+ this.bb.clear();
+ this.bb.put(this.ba, 0, bcount);
+ }
+ this.ib.clear();
+ this.ib.get(array, ir, icount);
+ ir+= icount;
+ switch (position - bcount) {
+ case 0:
+ position= 0;
+ break;
+ case 1:
+ this.ba[0]= this.ba[bcount];
+ position= 1;
+ break;
+ case 2:
+ this.ba[0]= this.ba[bcount];
+ this.ba[1]= this.ba[bcount+1];
+ position= 2;
+ break;
+ case 3:
+ array[ir++]= (
+ ((this.ba[bcount] & 0xff) << 24) |
+ ((this.ba[bcount+1] & 0xff) << 16) |
+ ((this.ba[bcount+2] & 0xff) << 8) |
+ ((in.read() & 0xff)) );
+ position= 0;
+ break;
+ }
+ if (length - ir <= IB_LENGTH) {
+ bToComplete= ((length - ir) << 2);
+ break;
+ }
+ }
+ }
+ if (bToComplete > 0) {
+ readFullyBB(position, bToComplete-position);
+ this.ib.clear();
+ this.ib.get(array, ir, bToComplete >>> 2);
+ }
+ return array;
+ }
+ }
+
+ public int[] readIntArray() throws IOException {
+ final ObjectInput in= this.in;
+ final int length= in.readInt();
+ if (length <= 256) {
+ switch (length) {
+ case -1:
+ return null;
+ case 0:
+ return EMPTY_INT_ARRAY;
+ case 1:
+ return new int[] { in.readInt() };
+ case 2:
+ return new int[] { in.readInt(), in.readInt() };
+ case 3:
+ return new int[] { in.readInt(), in.readInt(), in.readInt() };
+ case 4:
+ return new int[] { in.readInt(), in.readInt(), in.readInt(), in.readInt() };
+ default:
+ final int bn= length << 2;
+ in.readFully(this.ba, 0, bn);
+ final int[] array= new int[length];
+ for (int ib= 0; ib < bn; ib+= 4) {
+ array[ib >>> 2]= (
+ ((this.ba[ib] & 0xff) << 24) |
+ ((this.ba[ib+1] & 0xff) << 16) |
+ ((this.ba[ib+2] & 0xff) << 8) |
+ ((this.ba[ib+3] & 0xff)) );
+ }
+ return array;
+ }
+ }
+ else if (length <= IB_LENGTH) {
+ readFullyBB((length << 2));
+ final int[] array= new int[length];
+ this.ib.clear();
+ this.ib.get(array, 0, length);
+ return array;
+ }
+ else {
+ final int[] array= new int[length];
+ int ir= 0;
+ int position= 0;
+ final int bToComplete;
+ while (true) {
+ position+= in.read(this.ba, position, BA_LENGTH-position);
+ if (position >= BB_PART) {
+ final int icount= (position >>> 2);
+ final int bcount= (icount << 2);
+ if (this.mode != MODE_BBARRAY) {
+ this.bb.clear();
+ this.bb.put(this.ba, 0, bcount);
+ }
+ this.ib.clear();
+ this.ib.get(array, ir, icount);
+ ir+= icount;
+ switch (position - bcount) {
+ case 0:
+ position= 0;
+ break;
+ case 1:
+ this.ba[0]= this.ba[bcount];
+ position= 1;
+ break;
+ case 2:
+ this.ba[0]= this.ba[bcount];
+ this.ba[1]= this.ba[bcount+1];
+ position= 2;
+ break;
+ case 3:
+ array[ir++]= (
+ ((this.ba[bcount] & 0xff) << 24) |
+ ((this.ba[bcount+1] & 0xff) << 16) |
+ ((this.ba[bcount+2] & 0xff) << 8) |
+ ((in.read() & 0xff)) );
+ position= 0;
+ break;
+ }
+ if (length - ir <= IB_LENGTH) {
+ bToComplete= ((length - ir) << 2);
+ break;
+ }
+ }
+ }
+ if (bToComplete > 0) {
+ readFullyBB(position, bToComplete-position);
+ this.ib.clear();
+ this.ib.get(array, ir, bToComplete >>> 2);
+ }
+ return array;
+ }
+ }
+
+ public long readLong() throws IOException {
+ return this.in.readLong();
+ }
+
+ public long readVULong(final byte grade) throws IOException {
+ if (grade == 0) {
+ return this.in.readUnsignedByte();
+ }
+ final byte[] ba= this.ba;
+ switch (grade) {
+// case 0:
+// this.in.read(ba, 0, 1);
+// return (ba[0] & 0xff);
+ case 1:
+ this.in.read(ba, 0, 2);
+ return (((ba[0] & 0xff) << 8) |
+ (ba[1] & 0xff) );
+ case 2:
+ this.in.read(ba, 0, 3);
+ return (((ba[0] & 0xff) << 16) |
+ ((ba[1] & 0xff) << 8) |
+ (ba[2] & 0xff) );
+ case 3:
+ this.in.read(ba, 0, 4);
+ return (((long) (ba[0] & 0xff) << 24) |
+ ((ba[1] & 0xff) << 16) |
+ ((ba[2] & 0xff) << 8) |
+ (ba[3] & 0xff) );
+ case 4:
+ this.in.read(ba, 0, 5);
+ return (((long) (ba[0] & 0xff) << 32) |
+ ((long) (ba[1] & 0xff) << 24) |
+ ((ba[2] & 0xff) << 16) |
+ ((ba[3] & 0xff) << 8) |
+ (ba[4] & 0xff) );
+ case 5:
+ this.in.read(ba, 0, 6);
+ return (((long) (ba[0] & 0xff) << 40) |
+ ((long) (ba[1] & 0xff) << 32) |
+ ((long) (ba[2] & 0xff) << 24) |
+ ((ba[3] & 0xff) << 16) |
+ ((ba[4] & 0xff) << 8) |
+ (ba[5] & 0xff) );
+ case 6:
+ this.in.read(ba, 0, 7);
+ return (((long) (ba[0] & 0xff) << 48) |
+ ((long) (ba[1] & 0xff) << 40) |
+ ((long) (ba[2] & 0xff) << 32) |
+ ((long) (ba[3] & 0xff) << 24) |
+ ((ba[4] & 0xff) << 16) |
+ ((ba[5] & 0xff) << 8) |
+ (ba[6] & 0xff) );
+ case 7:
+ this.in.read(ba, 0, 8);
+ return (((long) (ba[0] & 0xff) << 56) |
+ ((long) (ba[1] & 0xff) << 48) |
+ ((long) (ba[2] & 0xff) << 40) |
+ ((long) (ba[3] & 0xff) << 32) |
+ ((long) (ba[4] & 0xff) << 24) |
+ ((ba[5] & 0xff) << 16) |
+ ((ba[6] & 0xff) << 8) |
+ (ba[7] & 0xff) );
+ default:
+ throw new IOException("Unsupported data format (c= " + grade + ").");
+ }
+ }
+
+ public double readDouble() throws IOException {
+ return this.in.readDouble();
+ }
+
+ public double[] readDoubleData(final double[] array, final int length) throws IOException {
+ final ObjectInput in= this.in;
+ if (length <= 32) {
+ switch (length) {
+ case 0:
+ return array;
+ case 1:
+ array[0]= Double.longBitsToDouble(in.readLong());
+ return array;
+ case 2:
+ array[0]= Double.longBitsToDouble(in.readLong());
+ array[1]= Double.longBitsToDouble(in.readLong());
+ return array;
+ default:
+ final int bn= length << 3;
+ in.readFully(this.ba, 0, bn);
+ for (int db= 0; db < bn; db+= 8) {
+ array[db >>> 3]= Double.longBitsToDouble(
+ ((long) (this.ba[db] & 0xff) << 56) |
+ ((long) (this.ba[db+1] & 0xff) << 48) |
+ ((long) (this.ba[db+2] & 0xff) << 40) |
+ ((long) (this.ba[db+3] & 0xff) << 32) |
+ ((long) (this.ba[db+4] & 0xff) << 24) |
+ ((this.ba[db+5] & 0xff) << 16) |
+ ((this.ba[db+6] & 0xff) << 8) |
+ ((this.ba[db+7] & 0xff)) );
+ }
+ return array;
+ }
+ }
+ else if (length <= DB_LENGTH) {
+ readFullyBB((length << 3));
+ this.db.clear();
+ this.db.get(array, 0, length);
+ return array;
+ }
+ else {
+ int dr= 0;
+ int position= 0;
+ final int bToComplete;
+ while (true) {
+ position+= in.read(this.ba, position, BA_LENGTH-position);
+ if (position >= BB_PART) {
+ final int dcount= (position >>> 3);
+ final int bcount= (dcount << 3);
+ if (this.mode != MODE_BBARRAY) {
+ this.bb.clear();
+ this.bb.put(this.ba, 0, bcount);
+ }
+ this.db.clear();
+ this.db.get(array, dr, dcount);
+ dr+= dcount;
+ switch (position - bcount) {
+ case 0:
+ position= 0;
+ break;
+ case 1:
+ this.ba[0]= this.ba[bcount];
+ position= 1;
+ break;
+ case 2:
+ this.ba[0]= this.ba[bcount];
+ this.ba[1]= this.ba[bcount+1];
+ position= 2;
+ break;
+ case 3:
+ this.ba[0]= this.ba[bcount];
+ this.ba[1]= this.ba[bcount+1];
+ this.ba[2]= this.ba[bcount+2];
+ position= 3;
+ break;
+ case 4:
+ this.ba[0]= this.ba[bcount];
+ this.ba[1]= this.ba[bcount+1];
+ this.ba[2]= this.ba[bcount+2];
+ this.ba[3]= this.ba[bcount+3];
+ position= 4;
+ break;
+ case 5:
+ this.ba[0]= this.ba[bcount];
+ this.ba[1]= this.ba[bcount+1];
+ this.ba[2]= this.ba[bcount+2];
+ this.ba[3]= this.ba[bcount+3];
+ this.ba[4]= this.ba[bcount+4];
+ position= 5;
+ break;
+ case 6:
+ array[dr++]= Double.longBitsToDouble(
+ ((long) (this.ba[bcount] & 0xff) << 56) |
+ ((long) (this.ba[bcount+1] & 0xff) << 48) |
+ ((long) (this.ba[bcount+2] & 0xff) << 40) |
+ ((long) (this.ba[bcount+3] & 0xff) << 32) |
+ ((long) (this.ba[bcount+4] & 0xff) << 24) |
+ ((this.ba[bcount+5] & 0xff) << 16) |
+ ((in.read() & 0xff) << 8) |
+ ((in.read() & 0xff)) );
+ position= 0;
+ break;
+ case 7:
+ array[dr++]= Double.longBitsToDouble(
+ ((long) (this.ba[bcount] & 0xff) << 56) |
+ ((long) (this.ba[bcount+1] & 0xff) << 48) |
+ ((long) (this.ba[bcount+2] & 0xff) << 40) |
+ ((long) (this.ba[bcount+3] & 0xff) << 32) |
+ ((long) (this.ba[bcount+4] & 0xff) << 24) |
+ ((this.ba[bcount+5] & 0xff) << 16) |
+ ((this.ba[bcount+6] & 0xff) << 8) |
+ ((in.read() & 0xff)) );
+ position= 0;
+ break;
+ }
+ if (length - dr <= DB_LENGTH) {
+ bToComplete= ((length - dr) << 3);
+ break;
+ }
+ }
+ }
+ if (bToComplete > 0) {
+ readFullyBB(position, bToComplete-position);
+ this.db.clear();
+ this.db.get(array, dr, bToComplete >>> 3);
+ }
+ return array;
+ }
+ }
+
+ public double[] readDoubleArray() throws IOException {
+ final int l= this.temp= this.in.readInt();
+ return readDoubleData(new double[l], l);
+ }
+
+ public double[] readDoubleArray2() throws IOException {
+ final int l= this.temp;
+ return readDoubleData(new double[l], l);
+ }
+
+ public float readFloat() throws IOException {
+ return this.in.readFloat();
+ }
+
+ public byte[] readByteData(final byte[] array, final int length) throws IOException {
+ this.in.readFully(array, 0, length);
+ return array;
+ }
+
+ public byte[] readByteArray() throws IOException {
+ final int l= this.temp= this.in.readInt();
+ return readByteData(new byte[l], l);
+ }
+
+ public byte[] readByteArray2() throws IOException {
+ final int l= this.temp;
+ return readByteData(new byte[l], l);
+ }
+
+ private String readString(final int cn, final char[] ca, final ObjectInput in) throws IOException {
+ int cr= 0;
+ int position= 0;
+ final int bToComplete;
+ while (true) {
+ position+= in.read(this.ba, position, BA_LENGTH-position);
+ if (position >= BB_PART) {
+ final int icount= (position >>> 1);
+ final int bcount= (icount << 1);
+ if (this.mode != MODE_BBARRAY) {
+ this.bb.clear();
+ this.bb.put(this.ba, 0, bcount);
+ }
+ this.cb.clear();
+ this.cb.get(ca, cr, icount);
+ cr+= icount;
+ if (position - bcount != 0) {
+ ca[cr++]= (char) (
+ ((this.ba[bcount] & 0xff) << 8) |
+ ((in.read() & 0xff)) );
+ }
+ position= 0;
+ if (cn - cr <= CB_LENGTH) {
+ bToComplete= (cn - cr) << 1;
+ break;
+ }
+ }
+ }
+ if (bToComplete > 0) {
+ readFullyBB(position, bToComplete-position);
+ this.cb.clear();
+ this.cb.get(ca, cr, bToComplete >>> 1);
+ }
+ return new String(ca, 0, cn);
+ }
+
+ @SuppressWarnings("deprecation")
+ public String readString() throws IOException {
+ final ObjectInput in= this.in;
+ final int cn= in.readInt();
+ if (cn >= 0) {
+ if (cn == 0) {
+ return "";
+ }
+ else if (cn <= 64) {
+ for (int ci= 0; ci < cn; ci++) {
+ this.ca[ci]= in.readChar();
+ }
+ return new String(this.ca, 0, cn);
+ }
+ else if (cn <= CB_LENGTH) {
+ readFullyBB((cn << 1));
+ this.cb.clear();
+ this.cb.get(this.ca, 0, cn);
+ return new String(this.ca, 0, cn);
+ }
+ else if (cn <= CA_LENGTH) {
+ return readString(cn, this.ca, in);
+ }
+ else {
+ return readString(cn, new char[cn], in);
+ }
+ }
+ else {
+ if (cn >= -BA_LENGTH) {
+ in.readFully(this.ba, 0, -cn);
+ return new String(this.ba, 0, 0, -cn);
+ }
+ else if (cn != Integer.MIN_VALUE) {
+ final byte[] bt= new byte[-cn];
+ in.readFully(bt, 0, -cn);
+ return new String(bt, 0, 0, -cn);
+ }
+ else { // cn == Integer.MIN_VALUE
+ return null;
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void readStringData(final String[] array, final int length) throws IOException {
+ final ObjectInput in= this.in;
+ ARRAY: for (int i= 0; i < length; i++) {
+ final int cn= in.readInt();
+ if (cn >= 0) {
+ if (cn == 0) {
+ array[i]= "";
+ continue ARRAY;
+ }
+ else if (cn <= 64) {
+ for (int ci= 0; ci < cn; ci++) {
+ this.ca[ci]= in.readChar();
+ }
+ array[i]= new String(this.ca, 0, cn);
+ continue ARRAY;
+ }
+ else if (cn <= CB_LENGTH) {
+ readFullyBB((cn << 1));
+ this.cb.clear();
+ this.cb.get(this.ca, 0, cn);
+ array[i]= new String(this.ca, 0, cn);
+ continue ARRAY;
+ }
+ else if (cn <= CA_LENGTH) {
+ array[i]= readString(cn, this.ca, in);
+ continue ARRAY;
+ }
+ else {
+ array[i]= readString(cn, new char[cn], in);
+ continue ARRAY;
+ }
+ }
+ else {
+ if (cn >= -BA_LENGTH) {
+ in.readFully(this.ba, 0, -cn);
+ array[i]= new String(this.ba, 0, 0, -cn);
+ continue ARRAY;
+ }
+ else if (cn != Integer.MIN_VALUE) {
+ final byte[] bt= new byte[-cn];
+ in.readFully(bt, 0, -cn);
+ array[i]= new String(bt, 0, 0, -cn);
+ continue ARRAY;
+ }
+ else { // cn == Integer.MIN_VALUE
+// array[i]= null;
+ continue ARRAY;
+ }
+ }
+ }
+ return;
+ }
+
+ public HashMap<String, Object> readStringKeyHashMap() throws IOException {
+ final ObjectInput in= this.in;
+ final int length= in.readInt();
+ if (length < 0) {
+ return null;
+ }
+ try {
+ final HashMap<String, Object> map= new HashMap<>(length);
+ for (int i= 0; i < length; i++) {
+ map.put(readString(), in.readObject());
+ }
+ return map;
+ }
+ catch (final ClassNotFoundException e) {
+ throw new IOException(e.getMessage());
+ }
+ }
+
+
+ public int writeCheck1() throws IOException {
+ this.out.writeInt(++this.serialKey);
+ return this.serialKey;
+ }
+
+ public void writeCheck2(final int check) throws IOException {
+ this.out.writeInt(check);
+ }
+
+ public int readCheck1() throws IOException {
+ return this.in.readInt();
+ }
+
+ public void readCheck2(final int check) throws IOException {
+ if (check != this.in.readInt()) {
+ throw new IOException("Corrupted stream detected.");
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIOExternalizable.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIOExternalizable.java
new file mode 100644
index 0000000..bd8a7a9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RJIOExternalizable.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.io.IOException;
+
+
+public interface RJIOExternalizable {
+
+
+ void writeExternal(RJIO out) throws IOException;
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLanguage.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLanguage.java
new file mode 100644
index 0000000..5531cbd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLanguage.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * R object of type call
+ */
+public interface RLanguage extends RObject {
+
+
+ byte NAME= 0x01;
+
+ byte EXPRESSION= 0x02;
+
+ byte CALL= 0x03;
+
+
+ byte getLanguageType();
+
+ String getSource();
+
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RList.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RList.java
new file mode 100644
index 0000000..2369efe
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RList.java
@@ -0,0 +1,118 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_LIST list}, if the object is
+ * an R list but not an R data frame (see {@link #TYPE_DATAFRAME}). Such an R
+ * list object is represented by an instance of this interface.
+ * <p>
+ * The R function <code>typeof(object)</code> returns 'list' or 'pairlist' for
+ * objects of this type.</p>
+ * <p>
+ * The interfaces for R objects of the type {@value RObject#TYPE_DATAFRAME} -
+ * {@link RDataFrame}, {@link RObject#TYPE_S4OBJECT} - {@link RS4Object} and
+ * {@link RObject#TYPE_ENVIRONMENT} - {@link REnvironment} extends this interface for the
+ * purpose of a uniform API.
+ * Objects of this type does not necessary provide the full functionality and the
+ * methods can have special meaning and conditions; see the documentation of these
+ * interfaces.</p>
+ * <p>
+ * Indexes are zero-based (as usual in Java) and not one-base like in R.</p>
+ */
+public interface RList extends RObject {
+
+ /**
+ * Returns the length of the object. The length of a {@link RObject#TYPE_LIST list}
+ * is the count of list items.
+ *
+ * @return the length
+ */
+ @Override
+ long getLength();
+
+ /**
+ * Returns the names of the list items.
+ *
+ * @return the item names
+ */
+ RCharacterStore getNames();
+
+ /**
+ * Returns the name of the item at the specified index.
+ * <p>
+ * This is equivalent to <code>getNames().getChar(idx)</code>.</p>
+ *
+ * @param idx the index (zero-based) of the item
+ * @return the slot names
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ length
+ */
+ String getName(int idx);
+
+ /**
+ * Returns the name of the item at the specified index.
+ * <p>
+ * This is equivalent to <code>getNames().getChar(idx)</code>.</p>
+ *
+ * @param idx the index (zero-based) of the item
+ * @return the slot names
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ length
+ */
+ String getName(long idx);
+
+ /**
+ * Returns the item at the specified index.
+ *
+ * @param idx the index (zero-based) of the item
+ * @return the item
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ length
+ */
+ RObject get(int idx);
+
+ /**
+ * Returns the item at the specified index.
+ *
+ * @param idx the index (zero-based) of the item
+ * @return the item
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ length
+ */
+ RObject get(long idx);
+
+ /**
+ * Returns the item with the specified name. If multiple items have that name,
+ * the first item with the given name is picked.
+ *
+ * @param name the name of the item
+ * @return the item or <code>null</code> (if no item with the specified name exists)
+ */
+ RObject get(String name);
+
+// /**
+// * Returns an array with the R object items of the list.
+// * <p>
+// * The array is newly created for each call of this method.</p>
+// *
+// * @return an array with the items of the list
+// */
+// RObject[] toArray();
+
+// void insert(int idx, String name, RObject item);
+// void add(String name, RObject item);
+// boolean set(int idx, RObject item);
+// boolean set(String name, RObject item);
+// void remove(int idx);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLogicalStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLogicalStore.java
new file mode 100644
index 0000000..ba30af7
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RLogicalStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#LOGICAL}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'logical'.</p>
+ */
+public interface RLogicalStore extends RStore<Boolean> {
+
+
+ @Override
+ Boolean get(int idx);
+ @Override
+ Boolean get(long idx);
+
+ @Override
+ Boolean[] toArray();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RNumericStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RNumericStore.java
new file mode 100644
index 0000000..10abf70
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RNumericStore.java
@@ -0,0 +1,38 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#NUMERIC}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'double'.</p>
+ */
+public interface RNumericStore extends RStore<Double> {
+
+
+ boolean isNaN(int idx);
+ boolean isNaN(long idx);
+
+ @Override
+ Double get(int idx);
+ @Override
+ Double get(long idx);
+
+ @Override
+ Double[] toArray();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObject.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObject.java
new file mode 100644
index 0000000..d21bb2a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObject.java
@@ -0,0 +1,205 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import org.eclipse.statet.rj.data.impl.RNullImpl;
+
+
+/**
+ * Basic interface of all R object.
+ * <p>
+ * To detect the type of an RObject instance, the method {@link #getRObjectType()}
+ * should be used, not the java class type (e.g. instanceof) of the object.</p>
+ */
+public interface RObject {
+
+ /**
+ * Constant indicating the RNullImpl object respectively the R NULL value.
+ * <p>
+ * The object is an instance of {@link RNullImpl}.</p>
+ */
+ byte TYPE_NULL= 0x01;
+
+ /**
+ * Constant indicating an {@link RVector} object. An R object is of this type
+ * if it is a R data object of an "atomic" mode without a dimension attribute
+ * (<code>dim</dim>).
+ * <p>
+ * The object is an instance of {@link RVector}.</p>
+ */
+ byte TYPE_VECTOR= 0x02;
+
+ /**
+ * Constant indicating an {@link RArray} object. An R object is of this type
+ * if it is a R data object of an "atomic" mode with a dimension attribute
+ * (<code>dim</dim>).
+ * <p>
+ * The object is an instance of {@link RArray}.</p>
+ */
+ byte TYPE_ARRAY= 0x03;
+
+ /**
+ * Constant indicating an RDataFrame object. An R object is of this type
+ * if it is an R list object inheriting the R class {@link #CLASSNAME_DATAFRAME data.frame}
+ * and compiling with the R rules for a data frame, especially its children
+ * are {@link RVector}s of the same length.
+ * <p>
+ * The object is an instance of {@link RDataFrame}.</p>
+ */
+ byte TYPE_DATAFRAME= 0x06;
+
+ /**
+ * Constant indicating an RList object. An R object is of this type if it is
+ * a list but not a data frame (see {@link #TYPE_DATAFRAME}).
+ * <p>
+ * The object is an instance of {@link RList}.</p>
+ */
+ byte TYPE_LIST= 0x07;
+
+ /**
+ * Constant indicating an R environment object.
+ * <p>
+ * The object is an instance of {@link REnvironment}.</p>
+ */
+ byte TYPE_ENVIRONMENT= 0x08;
+
+ /**
+ * Constant indicating an S4 object. An R object is of this type if the R
+ * command <code>isS4</code> returns true. This is criterion has priority
+ * above the criteria for the other data types. If an S4 object represents
+ * also a simple data type, this data is accessible by its data slot.
+ * <p>
+ * The object is an instance of {@link RS4Object}.</p>
+ */
+ byte TYPE_S4OBJECT= 0x0a;
+
+
+ /**
+ * Constant indicating an R language object.
+ * <p>
+ * The object is an instance of {@link RLanguage}.</p>
+ */
+ byte TYPE_LANGUAGE= 0x0c;
+
+ /**
+ * Constant indicating an R function object.
+ * <p>
+ * The object is an instance of {@link RFunction}.</p>
+ */
+ byte TYPE_FUNCTION= 0x0d;
+
+ /**
+ * Constant indicating a reference to a R object.
+ * <p>
+ * The object is an instance of {@link RReference}.</p>
+ */
+ byte TYPE_REFERENCE= 0x0e;
+
+ /**
+ * Constant indicating an R object not matching one of the other types.
+ */
+ byte TYPE_OTHER= 0x0f;
+
+ /**
+ * Constant indicating an R object is missing (e.g. missing argument, missing slot value).
+ *
+ * @since de.walware.rj.data 0.5
+ */
+ byte TYPE_MISSING= 0x11;
+
+ /**
+ * Constant indicating an R object is not yet evaluated.
+ *
+ * @since de.walware.rj.data 0.6
+ */
+ byte TYPE_PROMISE= 0x12;
+
+
+ //-- Common class names --//
+ String CLASSNAME_LOGICAL= "logical";
+ String CLASSNAME_INTEGER= "integer";
+ String CLASSNAME_NUMERIC= "numeric";
+ String CLASSNAME_CHARACTER= "character";
+ String CLASSNAME_COMPLEX= "complex";
+ String CLASSNAME_RAW= "raw";
+ String CLASSNAME_FACTOR= "factor";
+ String CLASSNAME_ORDERED= "ordered";
+
+ String CLASSNAME_ARRAY= "array";
+ String CLASSNAME_MATRIX= "matrix";
+ String CLASSNAME_DATAFRAME= "data.frame";
+ String CLASSNAME_LIST= "list";
+ String CLASSNAME_PAIRLIST= "pairlist";
+ String CLASSNAME_ENVIRONMENT= "environment";
+ String CLASSNAME_NAME= "name";
+ String CLASSNAME_EXPRESSION= "expression";
+ String CLASSNAME_CALL= "call";
+
+ String CLASSNAME_NULL= "NULL";
+
+ //-- Common attribute names --//
+ String ATTR_ROW_NAMES= "row.names";
+ String ATTR_NAMES= "names";
+
+
+ /**
+ * Returns the object type constant of this object
+ * <p>
+ * See the object type constants <code>TYPE_</code> defined in {@link RObject}.</p>
+ *
+ * @return the object type constant
+ */
+ byte getRObjectType();
+
+ /**
+ * Returns the class name of this object in R.
+ * <p>
+ * If the object has multiple S3 class names in R, it returns the first one.
+ * The analog R command is <code>class(x)[1]</code>.</p>
+ *
+ * @return the R class name
+ */
+ String getRClassName();
+
+ /**
+ * Returns the length of the object.
+ * <p>
+ * Its meaning depends on the R object type and is undefined for unknown types.</p>
+ *
+ * @return the length
+ */
+ long getLength();
+
+ /**
+ * Returns the data store containing object data in a one-dimensional structure.
+ * <p>
+ * This is supported by objects of {@link #TYPE_VECTOR}, {@link #TYPE_ARRAY} and
+ * of {@link #TYPE_S4OBJECT} with a data slot of a one of these types providing a data
+ * store.</p>
+ *
+ * @return the data store or <code>null</code>, if not supported by the object
+ */
+ RStore<?> getData();
+
+ /**
+ * Returns the attribute list of the object
+ * <p>
+ * Note that by default the attributes are not loaded.</p>
+ *
+ * @return the attribute list or <code>null</code>, if not available
+ */
+ RList getAttributes();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObjectFactory.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObjectFactory.java
new file mode 100644
index 0000000..0789edb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RObjectFactory.java
@@ -0,0 +1,79 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import java.io.IOException;
+
+
+
+public interface RObjectFactory {
+
+ /** Flag to fetch only the structure but not the data (store) of the objects */
+ int F_ONLY_STRUCT= 0x1;
+
+ /** XXX: Not yet implemented */
+ int F_WITH_ATTR= 0x2;
+
+ /** Flag to load environments directly instead of the reference only */
+ int F_LOAD_ENVIR= 0x10;
+
+ /** Flag to eval all promises directly */
+ int F_LOAD_PROMISE= 0x20;
+
+
+ int O_LENGTHGRADE_MASK= 7; // 3 bits
+
+ int O_WITH_ATTR= 1 << 3;
+
+ int O_CLASS_NAME= 1 << 4;
+
+ int O_NO_CHILDREN= 1 << 5;
+
+ int O_WITH_NAMES= 1 << 6;
+
+
+// RArgument createArgument(String name, String defaultSource);
+// RFunction createFunction(RArgument[] argument);
+//
+ <TData extends RStore<?>> RVector<TData> createVector(TData data);
+ <TData extends RStore<?>> RArray<TData> createArray(TData data, int[] dim);
+ <TData extends RStore<?>> RArray<TData> createMatrix(TData data, int dim1, int dim2);
+ RList createList(RObject[] components, String[] names);
+// RDataFrame createDataFrame(RData[] columns, String[] columnNames, String[] rowNames);
+
+ RLanguage createName(String name);
+ RLanguage createExpression(String expr);
+
+ RLogicalStore createLogiData(boolean[] logiValues);
+ RIntegerStore createIntData(int[] intValues);
+ RNumericStore createNumData(double[] numValues);
+ RComplexStore createCplxData(double[] reValues, double[] imValues);
+ RCharacterStore createCharData(String[] charValues);
+ RRawStore createRawData(byte[] values);
+ RFactorStore createFactorData(int[] codes, String[] levels);
+
+ void writeObject(RObject object, RJIO io) throws IOException;
+ RObject readObject(RJIO io) throws IOException;
+
+ void writeStore(RStore<?> data, RJIO io) throws IOException;
+ RStore<?> readStore(RJIO io, long length) throws IOException;
+
+ void writeAttributeList(RList list, RJIO io) throws IOException;
+ RList readAttributeList(RJIO io) throws IOException;
+
+ void writeNames(RStore<?> names, RJIO io) throws IOException;
+ RStore<?> readNames(RJIO io, long length) throws IOException;
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RRawStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RRawStore.java
new file mode 100644
index 0000000..fa474b5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RRawStore.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Interface for R data stores of type {@link RStore#RAW}.
+ * <p>
+ * An R data store implements this interface if the R function
+ * <code>typeof(object)</code> returns 'raw'.</p>
+ */
+public interface RRawStore extends RStore<Byte> {
+
+
+ @Override
+ Byte get(int idx);
+ @Override
+ Byte get(long idx);
+
+ @Override
+ Byte[] toArray();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RReference.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RReference.java
new file mode 100644
index 0000000..8871d9a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RReference.java
@@ -0,0 +1,33 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * A reference to an R object
+ */
+public interface RReference extends RObject {
+
+
+ /**
+ * Only for use of the object creator
+ */
+ long getHandle();
+
+ byte getReferencedRObjectType();
+
+ RObject getResolvedRObject();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RS4Object.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RS4Object.java
new file mode 100644
index 0000000..ae081c9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RS4Object.java
@@ -0,0 +1,126 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_S4OBJECT S4 object}, if the R
+ * command <code>isS4(object)</code> returns true. Such an R S4 object is
+ * represented by an instance of this interface.
+ * <p>
+ * Even the interface extends {@link RList}, the objects are not a list in R!
+ * The inheritance is only for a uniform API.</p>
+ * <p>
+ * If an S4 object in R simulates also a simple data type, this data is accessible
+ * by its data slot (<code>.Data</code>). For easier work with the data slot the
+ * class provides the methods {@link #hasDataSlot()} to test if there is such a
+ * slot, {@link #getDataSlot()} to get the R object in that slot and {@link #getData()}
+ * returns directly the data store by the data slot.</p>
+ * <p>
+ * The count of all slots, its names and value objects are accessible by the inherited
+ * methods {@link #getLength()}, {@link #getName(int)}, {@link #get(int)} and
+ * {@link #get(String)}.</p>
+ */
+public interface RS4Object extends RList {
+
+
+ /**
+ * Returns the S4 class name of this object in R.
+ *
+ * @return the R class name
+ */
+ @Override
+ String getRClassName();
+
+ /**
+ * Returns the length of the object. The length of an {@link RObject#TYPE_S4OBJECT S4 object}
+ * is the count of slots.
+ * <p>
+ * An equivalent command in R is for example <code>length(slotNames(obj))</code>, but
+ * not <code>length(obj)</code>.</p>
+ *
+ * At moment, the length of an {@link RObject#TYPE_S4OBJECT S4 object} is always ≤ 2<sup>31</sup>-1
+ * (representable by Java int).
+ *
+ * @return the slot count
+ */
+ @Override
+ long getLength();
+
+ /**
+ * Tests if the object respectively its class provides a data slot.
+ * <p>
+ * The data slot is the slot with the name <code>.Data</code>.</p>
+ *
+ * @return <code>true</code> if there is a data slot, otherwise <code>false</code>
+ */
+ boolean hasDataSlot();
+
+ /**
+ * Returns the data slot, if it exists.
+ *
+ * @return the object in the data slot
+ */
+ RObject getDataSlot();
+
+ /**
+ * Returns the data store of the data slot, if it exists.
+ *
+ * @return the data of the data slot
+ */
+ @Override
+ RStore<?> getData();
+
+ /**
+ * Returns the names of the slots.
+ *
+ * @return the slot names
+ */
+ @Override
+ RCharacterStore getNames();
+
+ /**
+ * Returns the name of the slot at the given index.
+ * <p>
+ * This is equivalent to <code>getNames().getChar(idx)</code>.</p>
+ *
+ * @param idx the index of the slot
+ * @return the slot names
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ slot count
+ */
+ @Override
+ String getName(int idx);
+
+ /**
+ * Returns the value of the slot at the given index.
+ *
+ * @param idx the index of the slot
+ * @return the value object of the slot
+ * @throws IndexOutOfBoundsException if <code>idx</code> < 0 or <code>idx</code> ≥ slot count
+ */
+ @Override
+ RObject get(int idx);
+
+ /**
+ * Returns the value of the slot with the given name.
+ *
+ * @param name the name of the slot
+ * @return the value of the slot with the given name
+ * @throws IllegalArgumentException if the S4 type doesn't have a slot with the given name
+ */
+ @Override
+ RObject get(String name);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RStore.java
new file mode 100644
index 0000000..c8d6285
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RStore.java
@@ -0,0 +1,744 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+import javax.naming.OperationNotSupportedException;
+
+
+/**
+ * This is the abstract one-dimensional data store for an R data type.
+ * <p>
+ * Data stores are not directly R objects but are used in the data objects
+ * {@link RVector} and {@link RArray}.</p>
+ * <p>
+ * There are store types for each atomic type of R (namely the types/modes
+ * numeric, complex, logical, character and raw) and a special
+ * type for factors. To get the type of a RStore the method {@link #getStoreType()}
+ * should be used. The available data types are:</p>
+ * <ul>
+ * <li>{@link #LOGICAL}</li>
+ * <li>{@link #INTEGER}</li>
+ * <li>{@link #NUMERIC}</li>
+ * <li>{@link #COMPLEX}</li>
+ * <li>{@link #CHARACTER}</li>
+ * <li>{@link #RAW}</li>
+ * <li>{@link #FACTOR}</li>
+ * </ul>
+ * <p>
+ * The Java value can be accessed by the getter methods for the different
+ * data types. The indexes are zero-based like in Java and not one-base like in R.
+ * Because Java doesn't provide NA for primitive data types directly,
+ * the data store provides the methods {@link #isNA(int)} and {@link #setNA(int)}
+ * to detect and set such values.
+ * If the value at an index of the store is NA, the return value of the other getter
+ * methods is undefined.</p>
+ * <p>
+ * Indexes are zero-based (as usual in Java) and not one-base like in R.</p>
+ */
+public interface RStore<P> {
+
+ /**
+ * Constant indicating a store for R data type <code>logical<code>.
+ *
+ * <p>The story object is an instance of {@link RLogicalStore}.
+ * The {@link #getBaseVectorRClassName() class name} is
+ * <code>{@link RObject#CLASSNAME_LOGICAL logical}</code>.</p>
+ *
+ * @see #getLogi(int)
+ * @see #setLogi(int, boolean)
+ */
+ byte LOGICAL= 0x00000001;
+
+ /**
+ * Constant indicating a store for R data type <code>integer<code>.
+ *
+ * <p>The story object is an instance of {@link RIntegerStore}.
+ * The {@link #getBaseVectorRClassName() class name} is
+ * <code>{@link RObject#CLASSNAME_INTEGER integer}</code>.</p>
+ *
+ * @see #getInt(int)
+ * @see #setInt(int, int)
+ */
+ byte INTEGER= 0x00000002;
+
+ /**
+ * Constant indicating a store for R data type <code>logical<code>.
+ *
+ * <p>The story object is an instance of {@link RNumericStore}.
+ * The {@link #getBaseVectorRClassName() class name} is
+ * <code>{@link RObject#CLASSNAME_NUMERIC numeric}</code>.</p>
+ *
+ * @see #getNum(int)
+ * @see #setNum(int, double)
+ */
+ byte NUMERIC= 0x00000003;
+
+ /**
+ * Constant indicating a store for R data type <code>complex<code>.
+ *
+ * <p>The story object is an instance of {@link RComplexStore}.
+ * The {@link #getBaseVectorRClassName() class name} is
+ * <code>{@link RObject#CLASSNAME_COMPLEX complex}</code>.</p>
+ *
+ * @see #getCplxRe(int)
+ * @see #getCplxIm(int)
+ * @see #setCplx(int, double, double)
+ */
+ byte COMPLEX= 0x00000004;
+
+ /**
+ * Constant indicating a store for R data type <code>character<code>.
+ *
+ * <p>The story object is an instance of {@link RCharacterStore}.
+ * The {@link #getBaseVectorRClassName() class name} is
+ * <code>{@link RObject#CLASSNAME_CHARACTER character}</code>.</p>
+ *
+ * @see #getChar(int)
+ * @see #setChar(int, String)
+ */
+ byte CHARACTER= 0x00000005;
+
+ /**
+ * Constant indicating a store for R data type <code>raw<code>.
+ *
+ * <p>Note that raw data doesn't support NAs.</p>
+ *
+ * <p>The story object is an instance of {@link RRawStore}.
+ * The {@link #getBaseVectorRClassName() class name} is
+ * <code>{@link RObject#CLASSNAME_RAW raw}</code>.</p>
+ *
+ * @see #getRaw(int)
+ * @see #setRaw(int, byte)
+ */
+ byte RAW= 0x00000006;
+
+ /**
+ * Constant indicating a special store extending the integer
+ * data type for R objects extending the R class <code>factor<code>.
+ *
+ * <p>The story object is an instance of {@link RFactorStore}.
+ * The {@link #getBaseVectorRClassName() class name} is
+ * <code>{@link RObject#CLASSNAME_FACTOR factor}</code> or
+ * <code>{@link RObject#CLASSNAME_ORDERED ordered}</code>.
+ *
+ * @see RFactorStore#getInt(int)
+ * @see RFactorStore#getChar(int)
+ * @see RFactorStore#setInt(int, int)
+ * @see RFactorStore#setChar(int, String)
+ **/
+ byte FACTOR= 0x0000000a;
+
+
+ /**
+ * Returns the constant indicating the type of this RStore.
+ *
+ * @return one of the constant defined in the {@link RStore} interface
+ */
+ byte getStoreType();
+
+ /**
+ * Returns the R class name a vector with this data store and no other
+ * class definitions will have.
+ *
+ * @return the class name
+ */
+ String getBaseVectorRClassName();
+
+ /**
+ * Returns the length of this data store.
+ *
+ * <p>If this is a data store dummy for structure only R objects in Java
+ * ({@link RObjectFactory#F_ONLY_STRUCT}), the value is <code>-1</code>.
+ *
+ * @return the length or <code>-1</code>
+ */
+ long getLength();
+
+ /**
+ * Tests if the value at the specified index is NA.
+ * <p>
+ * Note that the analogous method to the R function <code>is.na(x)</code>
+ * is {@link #isMissing(int)}; this method returns <code>false</code> for NaN values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return <code>true</code>, if the value at the specified index is NA, otherwise <code>false</code>
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ boolean isNA(int idx);
+
+ /**
+ * Tests if the value at the specified index is NA.
+ * <p>
+ * Note that the analogous method to the R function <code>is.na(x)</code>
+ * is {@link #isMissing(int)}; this method returns <code>false</code> for NaN values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return <code>true</code>, if the value at the specified index is NA, otherwise <code>false</code>
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ boolean isNA(long idx);
+
+ /**
+ * Tests if the value at the specified index is NA <b>or</b> NaN (if supported by data type).
+ * It works by analogy with the R function <code>is.na(x)</code>.
+ *
+ * @param idx the index (zero-based) of the value
+ * @return <code>true</code>, if the value at the specified index is NA or NaN, otherwise <code>false</code>
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ boolean isMissing(int idx);
+
+ /**
+ * Tests if the value at the specified index is NA <b>or</b> NaN (if supported by data type).
+ * It works by analogy with the R function <code>is.na(x)</code>.
+ *
+ * @param idx the index (zero-based) of the value
+ * @return <code>true</code>, if the value at the specified index is NA or NaN, otherwise <code>false</code>
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ boolean isMissing(long idx);
+
+ /**
+ * Sets the value at the specified index to NA.
+ * <p>
+ * Note that raw doesn't support NAs.</p>.
+ *
+ * @param idx the index (zero-based) of the value
+ * @param idx the index of the value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setNA(int idx);
+
+ /**
+ * Sets the value at the specified index to NA.
+ * <p>
+ * Note that raw doesn't support NAs.</p>.
+ *
+ * @param idx the index (zero-based) of the value
+ * @param idx the index of the value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setNA(long idx);
+
+ /**
+ * Return the logical/boolean value at the specified index.
+ * <p>
+ * Logical values in R matches exactly the Java boolean values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current logical value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ boolean getLogi(int idx);
+
+ /**
+ * Return the logical/boolean value at the specified index.
+ * <p>
+ * Logical values in R matches exactly the Java boolean values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current logical value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ boolean getLogi(long idx);
+
+ /**
+ * Sets the logical/boolean value at the specified index.
+ * <p>
+ * Logical values in R matches exactly the Java boolean values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param logical the logical value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setLogi(int idx, boolean logical);
+
+ /**
+ * Sets the logical/boolean value at the specified index.
+ * <p>
+ * Logical values in R matches exactly the Java boolean values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param logical the logical value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setLogi(long idx, boolean logical);
+
+ /**
+ * Return the integer/int value at the specified index.
+ * <p>
+ * Integer values in R matches exactly the Java int values, except
+ * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current integer value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ int getInt(int idx);
+
+ /**
+ * Return the integer/int value at the specified index.
+ * <p>
+ * Integer values in R matches exactly the Java int values, except
+ * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current integer value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ int getInt(long idx);
+
+ /**
+ * Sets the integer/int value at the specified index.
+ * <p>
+ * Integer values in R matches exactly the Java int values, except
+ * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param integer the integer value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setInt(int idx, int integer);
+
+ /**
+ * Sets the integer/int value at the specified index.
+ * <p>
+ * Integer values in R matches exactly the Java int values, except
+ * {@link Integer#MIN_VALUE} which doesn't exists in R and is mapped to NA.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param integer the integer value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setInt(long idx, int integer);
+
+ /**
+ * Return the numeric/real/double value at the specified index.
+ * <p>
+ * Numeric values in R matches exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {@link Double#isNaN(double)},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current real value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ double getNum(int idx);
+
+ /**
+ * Return the numeric/real/double value at the specified index.
+ * <p>
+ * Numeric values in R matches exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {@link Double#isNaN(double)},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current real value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ double getNum(long idx);
+
+ /**
+ * Sets the numeric/real/double value at the specified index.
+ * <p>
+ * Numeric values in R matches exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {@link Double#NaN},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param numeric the real value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setNum(int idx, double numeric);
+
+ /**
+ * Sets the numeric/real/double value at the specified index.
+ * <p>
+ * Numeric values in R matches exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {@link Double#NaN},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param numeric the real value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setNum(long idx, double numeric);
+
+ /**
+ * Returns the real part the complex number value at the specified index.
+ * <p>
+ * The numeric values of the parts of the complex number in R matches
+ * exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {Double#isNaN(double)},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current real part of the complex number value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ double getCplxRe(int idx);
+
+ /**
+ * Returns the real part the complex number value at the specified index.
+ * <p>
+ * The numeric values of the parts of the complex number in R matches
+ * exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {Double#isNaN(double)},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current real part of the complex number value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ double getCplxRe(long idx);
+
+ /**
+ * Returns the imaginary part the complex number value at the specified index.
+ * <p>
+ * The numeric values of the parts of the complex number in R matches
+ * exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {Double#isNaN(double)},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current imaginary part of the complex number value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ double getCplxIm(int idx);
+
+ /**
+ * Returns the imaginary part the complex number value at the specified index.
+ * <p>
+ * The numeric values of the parts of the complex number in R matches
+ * exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {Double#isNaN(double)},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current imaginary part of the complex number value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ double getCplxIm(long idx);
+
+ /**
+ * Sets the complex number value at the specified index.
+ * <p>
+ * The numeric values of the parts of the complex number in R matches
+ * exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {@link Double#NaN},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param real the real part of the complex number value
+ * @param imaginary the imaginary part of the complex number value
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setCplx(int idx, double real, double imaginary);
+
+ /**
+ * Sets the complex number value at the specified index.
+ * <p>
+ * The numeric values of the parts of the complex number in R matches
+ * exactly the Java double values.
+ * Also NaN, Inf and -Inf respectively {@link Double#NaN},
+ * {@link Double#POSITIVE_INFINITY} and {@link Double#NEGATIVE_INFINITY} are
+ * supported.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param real the real part of the complex number value
+ * @param imaginary the imaginary part of the complex number value
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setCplx(long idx, double real, double imaginary);
+
+ /**
+ * Returns the character value at the specified index.
+ * <p>
+ * R character values matches exactly Java string values, if R supports
+ * UTF encoding.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current character value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ String getChar(int idx);
+
+ /**
+ * Returns the character value at the specified index.
+ * <p>
+ * R character values matches exactly Java string values, if R supports
+ * UTF encoding.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current character value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ String getChar(long idx);
+
+ /**
+ * Sets the character/String value at the specified index.
+ * <p>
+ * R character values matches exactly Java string values, if R supports
+ * UTF encoding.</p>
+ * <p>
+ * No quoting or escaping is required. Quoting or escaping the value
+ * would change the real value.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param character the character value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setChar(int idx, String character);
+
+ /**
+ * Sets the character/String value at the specified index.
+ * <p>
+ * R character values matches exactly Java string values, if R supports
+ * UTF encoding.</p>
+ * <p>
+ * No quoting or escaping is required. Quoting or escaping the value
+ * would change the real value.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param character the character value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setChar(long idx, String character);
+
+ /**
+ * Returns the raw/byte value at the specified index.
+ * <p>
+ * R raw values matches exactly Java byte values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current raw value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ byte getRaw(int idx);
+
+ /**
+ * Returns the raw/byte value at the specified index.
+ * <p>
+ * R raw values matches exactly Java byte values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return the current raw value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ byte getRaw(long idx);
+
+ /**
+ * Sets the raw/byte value at the specified index.
+ * <p>
+ * R raw values matches exactly Java byte values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param raw the raw value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setRaw(int idx, byte raw);
+
+ /**
+ * Sets the raw/byte value at the specified index.
+ * <p>
+ * R raw values matches exactly Java byte values.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @param raw the raw value to set
+ * @throws OperationNotSupportedException if the store is not modifiable
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ void setRaw(long idx, byte raw);
+
+ /**
+ * Returns the value at the specified index as Java object. The subtypes of
+ * RStore defines more specific array types.
+ * <p>
+ * R NA values are represented as <code>null</code>. Java primitives are converted
+ * into its wrapper classes.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return an object for the current value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ P get(int idx);
+
+ /**
+ * Returns the value at the specified index as Java object. The subtypes of
+ * RStore defines more specific array types.
+ * <p>
+ * R NA values are represented as <code>null</code>. Java primitives are converted
+ * into its wrapper classes.</p>
+ *
+ * @param idx the index (zero-based) of the value
+ * @return an object for the current value
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (idx < 0 || idx >= length()).
+ */
+ P get(long idx);
+
+ /**
+ * Returns the values of the store as Java object array. The subtypes of
+ * RStore defines more specific array types.
+ * <p>
+ * The array is newly created for each call of this method. It has the
+ * length {@link #getLength()}. R NA values are represented as <code>null</code>
+ * in the array. Java primitives are converted into its wrapper classes.</p>
+ *
+ * @return a object array with the values of the store
+ */
+ P[] toArray();
+
+ boolean allEqual(RStore<?> other);
+
+
+ /**
+ * Returns if the store contains the a NA value.
+ *
+ * @return <code>true</code> if the store contains a NA value, otherwise false
+ *
+ * @since de.walware.rj.data 3.0
+ */
+ boolean containsNA();
+
+ /**
+ * Returns the index of the first NA value in the store.
+ *
+ * @return index (zero-base) of first equal value, otherwise <code>-1</code>
+ *
+ * @since de.walware.rj.data 3.0
+ */
+ long indexOfNA();
+
+ /**
+ * Returns the index of the first NA value in the store, starting from the specified index.
+ *
+ * @param fromIdx index (zero-based) from which to start the search
+ * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+ *
+ * @since de.walware.rj.data 3.0
+ */
+ long indexOfNA(long fromIdx);
+
+ /**
+ * Returns if the store contains the specified integer value.
+ *
+ * @param value the value to search for
+ * @return <code>true</code> if the store contains the value, otherwise false
+ */
+ boolean contains(final int integer);
+
+ /**
+ * Returns the index of the first value in the store equal to the of the specified integer
+ * value.
+ *
+ * @param integer the value to search for
+ * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+ */
+ long indexOf(int integer);
+
+ /**
+ * Returns the index of the first value in the store equal to the of the specified integer
+ * value, starting from the specified index.
+ *
+ * @param integer the value to search for
+ * @param fromIdx index (zero-based) from which to start the search
+ * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+ */
+ long indexOf(int integer, long fromIdx);
+
+ /**
+ * Returns if the store contains the specified character value.
+ *
+ * @param value the value to search for
+ * @return <code>true</code> if the store contains the value, otherwise false
+ */
+ boolean contains(final String value);
+
+ /**
+ * Returns the index of the first value in the store equal to the of the specified character
+ * value.
+ *
+ * @param character the value to search for
+ * @return index (zero-base) of first equal value, otherwise <code>-1</code>
+ */
+ long indexOf(String character);
+
+ /**
+ * Returns the index of the first value in the store equal to the of the specified character
+ * value, starting from the specified index.
+ *
+ * @param character the value to search for
+ * @param fromIdx index (zero-based) from which to start the search
+ * @return index (zero-based) of first equal value, otherwise <code>-1</code>
+ */
+ long indexOf(String character, long fromIdx);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RVector.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RVector.java
new file mode 100644
index 0000000..7626963
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/RVector.java
@@ -0,0 +1,74 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * An R object is of the type {@link RObject#TYPE_VECTOR vector}, if it is an R
+ * data object of an "atomic" mode without a dimension attribute (<code>dim</code>).
+ * Such an R vector object is represented by an instance of this interface.
+ * <p>
+ * The real data is stored in a {@link RStore} accessible by {@link #getData()}.</p>
+ * <p>
+ * The type {@link RObject#TYPE_VECTOR vector} equates not the R command
+ * <code>is.vector(object)</code>, mainly because all attributes except the dimension
+ * are allowed (in the R function only the names attribute is allowed). Especially
+ * an R factor object is of the type {@link RObject#TYPE_VECTOR vector}, implements
+ * RVector and has a data store of the type {@link RStore#FACTOR}. Also another S3
+ * object based on a such a data object is of the type {@link RObject#TYPE_VECTOR vector}.
+ * Whereas a S4 object is never directly of this type even the object simulates such
+ * a data object in R. Such an object is of the type {@link RObject#TYPE_S4OBJECT S4 object},
+ * and implements {@link RS4Object} with an object of the type {@link RObject#TYPE_VECTOR vector}
+ * as data slot.</p>
+ * <p>
+ * The complementary type for objects with dimension attribute is the type
+ * {@link RObject#TYPE_ARRAY array} and the interface {@link RArray}.
+ * The data structure for multiple R objects is represented by the type
+ * {@link RObject#TYPE_LIST list} respectively the interface {@link RList}.</p>
+ *
+ * @param <TData> the type of the data store
+ */
+public interface RVector<TData extends RStore<?>> extends RObject {
+
+ /**
+ * Returns the length of the object. The length of an {@link RObject#TYPE_VECTOR vector}
+ * is the count of all data values.
+ *
+ * @return the length
+ */
+ @Override
+ long getLength();
+
+ /**
+ * Returns the names for the indexes of the vector. This corresponds to the values of the
+ * R attribute (<code>names</code>) respectively the R function <code>names(object)</code>.
+ *
+ * The returned character data has the same length the vector. If the R element does not have
+ * names, the names are invalid, or names are disabled, the method returns <code>null</code>.
+ *
+ * @return a data store with the names of the indexes or <code>null</code>
+ *
+ * @since de.walware.rj.data 0.5
+ */
+ RStore<?> getNames();
+
+
+ @Override
+ TData getData();
+
+// void insert(int idx);
+// void remove(int idx);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/UnexpectedRDataException.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/UnexpectedRDataException.java
new file mode 100644
index 0000000..3a795e7
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/UnexpectedRDataException.java
@@ -0,0 +1,30 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data;
+
+
+/**
+ * Exception indicating that the R data (object or store) is missing or not of the expected type.
+ */
+public class UnexpectedRDataException extends Exception {
+
+ private static final long serialVersionUID= 1L;
+
+
+ public UnexpectedRDataException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractCharacterStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractCharacterStore.java
new file mode 100644
index 0000000..ef64b11
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractCharacterStore.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractCharacterStore extends AbstractRStore<String>
+ implements RCharacterStore {
+
+
+ protected static final boolean toLogi(final String character) {
+ switch (character.length()) {
+ case 1:
+ switch (character.charAt(0)) {
+ case 'F':
+ return false;
+ case 'T':
+ return true;
+ default:
+ break;
+ }
+ break;
+ case 4:
+ if ("true".regionMatches(0, character, 0, 4)) {
+ return true;
+ }
+ break;
+ case 5:
+ if ("false".regionMatches(0, character, 0, 5)) {
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ throw new NumberFormatException(character);
+ }
+
+
+ @Override
+ public final byte getStoreType() {
+ return RStore.CHARACTER;
+ }
+
+ @Override
+ public final String getBaseVectorRClassName() {
+ return RObject.CLASSNAME_CHARACTER;
+ }
+
+
+ @Override
+ public void setLogi(final int idx, final boolean logi) {
+ setChar(idx, AbstractLogicalStore.toChar(logi));
+ }
+
+ @Override
+ public void setLogi(final long idx, final boolean logi) {
+ setChar(idx, AbstractLogicalStore.toChar(logi));
+ }
+
+ @Override
+ public boolean getLogi(final int idx) {
+ return toLogi(getChar(idx));
+ }
+
+ @Override
+ public boolean getLogi(final long idx) {
+ return toLogi(getChar(idx));
+ }
+
+ @Override
+ public final void setInt(final int idx, final int integer) {
+ setChar(idx, Integer.toString(integer));
+ }
+
+ @Override
+ public final void setInt(final long idx, final int integer) {
+ setChar(idx, Integer.toString(integer));
+ }
+
+ @Override
+ public void setCplx(final int idx, final double real, final double imaginary) {
+ setChar(idx, AbstractComplexStore.toChar(real, imaginary));
+ }
+
+ @Override
+ public void setCplx(final long idx, final double real, final double imaginary) {
+ setChar(idx, AbstractComplexStore.toChar(real, imaginary));
+ }
+
+ @Override
+ public final void setRaw(final int idx, final byte raw) {
+ setChar(idx, AbstractRawStore.toChar(raw));
+ }
+
+ @Override
+ public final void setRaw(final long idx, final byte raw) {
+ setChar(idx, AbstractRawStore.toChar(raw));
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ return indexOf(Integer.toString(integer), fromIdx);
+ }
+
+
+ @Override
+ public abstract String[] toArray();
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ final long length= getLength();
+ if (CHARACTER != other.getStoreType() || length != other.getLength()) {
+ return false;
+ }
+ if (length < 0) {
+ return true;
+ }
+ else if (length <= Integer.MAX_VALUE) {
+ final int ilength= (int) length;
+ for (int idx= 0; idx < ilength; idx++) {
+ if (!(isNA(idx) ? other.isNA(idx) :
+ getChar(idx).equals(other.getChar(idx)) )) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (long idx= 0; idx < length; idx++) {
+ if (!(isNA(idx) ? other.isNA(idx) :
+ getChar(idx).equals(other.getChar(idx)) )) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractComplexStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractComplexStore.java
new file mode 100644
index 0000000..3137a75
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractComplexStore.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RComplexStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractComplexStore extends AbstractRStore<RComplexStore.Complex>
+ implements RComplexStore {
+
+
+ protected static final String toChar(final double real, final double imaginary) {
+ final StringBuilder sb= new StringBuilder();
+ sb.append(AbstractNumericStore.toChar(real));
+ { final String imStr= AbstractNumericStore.toChar(imaginary);
+ if (imStr.charAt(0) != '-') {
+ sb.append('+');
+ }
+ sb.append(imStr);
+ }
+ sb.append('i');
+ return sb.toString();
+ }
+
+
+ @Override
+ public final byte getStoreType() {
+ return RStore.COMPLEX;
+ }
+
+ @Override
+ public final String getBaseVectorRClassName() {
+ return RObject.CLASSNAME_COMPLEX;
+ }
+
+
+ @Override
+ public final String getChar(final int idx) {
+ return toChar(getCplxRe(idx), getCplxIm(idx));
+ }
+
+ @Override
+ public final String getChar(final long idx) {
+ return toChar(getCplxRe(idx), getCplxIm(idx));
+ }
+
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public abstract Complex[] toArray();
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractFactorStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractFactorStore.java
new file mode 100644
index 0000000..c888196
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractFactorStore.java
@@ -0,0 +1,90 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RFactorStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractFactorStore extends AbstractRStore<Integer>
+ implements RFactorStore {
+
+
+ protected boolean isOrdered;
+
+
+ @Override
+ public final byte getStoreType() {
+ return RStore.FACTOR;
+ }
+
+ @Override
+ public final String getBaseVectorRClassName() {
+ return (this.isOrdered) ? RObject.CLASSNAME_ORDERED : RObject.CLASSNAME_FACTOR;
+ }
+
+ @Override
+ public final boolean isOrdered() {
+ return this.isOrdered;
+ }
+
+
+ @Override
+ public final boolean getLogi(final int idx) {
+ return (getInt(idx) != 0);
+ }
+
+ @Override
+ public final boolean getLogi(final long idx) {
+ return (getInt(idx) != 0);
+ }
+
+ @Override
+ public final void setLogi(final int idx, final boolean logi) {
+ setInt(idx, logi ? 1 : 0);
+ }
+
+ @Override
+ public final void setLogi(final long idx, final boolean logi) {
+ setInt(idx, logi ? 1 : 0);
+ }
+
+ @Override
+ public final double getNum(final int idx) {
+ return getInt(idx);
+ }
+
+ @Override
+ public final double getNum(final long idx) {
+ return getInt(idx);
+ }
+
+ @Override
+ public final void setNum(final int idx, final double real) {
+ setInt(idx, (int) real);
+ }
+
+ @Override
+ public final void setNum(final long idx, final double real) {
+ setInt(idx, (int) real);
+ }
+
+
+ @Override
+ public abstract Integer[] toArray();
+
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractIntegerStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractIntegerStore.java
new file mode 100644
index 0000000..d2f339d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractIntegerStore.java
@@ -0,0 +1,150 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractIntegerStore extends AbstractRStore<Integer>
+ implements RIntegerStore {
+
+
+ protected static final byte toRaw(final int integer) {
+ if ((integer & 0xffffff00) == 0) {
+ return (byte) (integer & 0xff);
+ }
+ throw new NumberFormatException(Integer.toString(integer));
+ }
+
+
+ @Override
+ public final byte getStoreType() {
+ return RStore.INTEGER;
+ }
+
+ @Override
+ public final String getBaseVectorRClassName() {
+ return RObject.CLASSNAME_INTEGER;
+ }
+
+
+ @Override
+ public final boolean getLogi(final int idx) {
+ return (getInt(idx) != 0);
+ }
+
+ @Override
+ public final boolean getLogi(final long idx) {
+ return (getInt(idx) != 0);
+ }
+
+ @Override
+ public final void setLogi(final int idx, final boolean logi) {
+ setInt(idx, logi ? 1 : 0);
+ }
+
+ @Override
+ public final void setLogi(final long idx, final boolean logi) {
+ setInt(idx, logi ? 1 : 0);
+ }
+
+ @Override
+ public final double getNum(final int idx) {
+ return getInt(idx);
+ }
+
+ @Override
+ public final double getNum(final long idx) {
+ return getInt(idx);
+ }
+
+ @Override
+ public final void setNum(final int idx, final double real) {
+ setInt(idx, (int) real);
+ }
+
+ @Override
+ public final void setNum(final long idx, final double real) {
+ setInt(idx, (int) real);
+ }
+
+ @Override
+ public final String getChar(final int idx) {
+ return Integer.toString(getInt(idx));
+ }
+
+ @Override
+ public final String getChar(final long idx) {
+ return Integer.toString(getInt(idx));
+ }
+
+ @Override
+ public byte getRaw(final int idx) {
+ return toRaw(getInt(idx));
+ }
+
+ @Override
+ public byte getRaw(final long idx) {
+ return toRaw(getInt(idx));
+ }
+
+
+ @Override
+ public abstract Integer[] toArray();
+
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ try {
+ return indexOf(Integer.parseInt(character), fromIdx);
+ }
+ catch (final NumberFormatException e) {
+ return -1;
+ }
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ final long length= getLength();
+ if (INTEGER != other.getStoreType() || length != other.getLength()) {
+ return false;
+ }
+ if (length < 0) {
+ return true;
+ }
+ else if (length <= Integer.MAX_VALUE) {
+ final int ilength= (int) length;
+ for (int idx= 0; idx < ilength; idx++) {
+ if (!(isNA(idx) ? other.isNA(idx) :
+ getInt(idx) == other.getInt(idx) )) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (long idx= 0; idx < length; idx++) {
+ if (!(isNA(idx) ? other.isNA(idx) :
+ getInt(idx) == other.getInt(idx) )) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractLogicalStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractLogicalStore.java
new file mode 100644
index 0000000..c1f6151
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractLogicalStore.java
@@ -0,0 +1,149 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RLogicalStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractLogicalStore extends AbstractRStore<Boolean>
+ implements RLogicalStore {
+
+
+ protected static final String toChar(final boolean logi) {
+ return (logi) ? "TRUE" : "FALSE";
+ }
+
+
+ @Override
+ public final byte getStoreType() {
+ return RStore.LOGICAL;
+ }
+
+ @Override
+ public final String getBaseVectorRClassName() {
+ return RObject.CLASSNAME_LOGICAL;
+ }
+
+
+ @Override
+ public final int getInt(final int idx) {
+ return getLogi(idx) ? 1 : 0;
+ }
+
+ @Override
+ public final int getInt(final long idx) {
+ return getLogi(idx) ? 1 : 0;
+ }
+
+ @Override
+ public final void setInt(final int idx, final int integer) {
+ setLogi(idx, integer != 0);
+ }
+
+ @Override
+ public final void setInt(final long idx, final int integer) {
+ setLogi(idx, integer != 0);
+ }
+
+ @Override
+ public final String getChar(final int idx) {
+ return toChar(getLogi(idx));
+ }
+
+ @Override
+ public final String getChar(final long idx) {
+ return toChar(getLogi(idx));
+ }
+
+ @Override
+ public void setChar(final int idx, final String character) {
+ setLogi(idx, AbstractCharacterStore.toLogi(character));
+ }
+
+ @Override
+ public void setChar(final long idx, final String character) {
+ setLogi(idx, AbstractCharacterStore.toLogi(character));
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ if (character == null) {
+ throw new NullPointerException();
+ }
+ try {
+ return indexOf(AbstractCharacterStore.toLogi(character) ? 1 : 0, fromIdx);
+ }
+ catch (final NumberFormatException e) {
+ return -1;
+ }
+ }
+
+ @Override
+ public byte getRaw(final int idx) {
+ return getLogi(idx) ? (byte) 1 : (byte) 0;
+ }
+
+ @Override
+ public byte getRaw(final long idx) {
+ return getLogi(idx) ? (byte) 1 : (byte) 0;
+ }
+
+ @Override
+ public void setRaw(final int idx, final byte raw) {
+ setLogi(idx, raw != 0);
+ }
+
+ @Override
+ public void setRaw(final long idx, final byte raw) {
+ setLogi(idx, raw != 0);
+ }
+
+
+ @Override
+ public abstract Boolean[] toArray();
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ final long length= getLength();
+ if (LOGICAL != other.getStoreType() || length != other.getLength()) {
+ return false;
+ }
+ if (length < 0) {
+ return true;
+ }
+ else if (length <= Integer.MAX_VALUE) {
+ final int ilength= (int) length;
+ for (int idx= 0; idx < ilength; idx++) {
+ if (!(isNA(idx) ? other.isNA(idx) :
+ getLogi(idx) == other.getLogi(idx) )) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (long idx= 0; idx < length; idx++) {
+ if (!(isNA(idx) ? other.isNA(idx) :
+ getLogi(idx) == other.getLogi(idx) )) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractNumericStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractNumericStore.java
new file mode 100644
index 0000000..0ff0a97
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractNumericStore.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RNumericStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractNumericStore extends AbstractRStore<Double>
+ implements RNumericStore {
+
+
+ protected static final String toChar(final double num) {
+ if (num == Double.POSITIVE_INFINITY) {
+ return "Inf"; //$NON-NLS-1$
+ }
+ else if (num == Double.NEGATIVE_INFINITY) {
+ return "-Inf"; //$NON-NLS-1$
+ }
+ return Double.toString(num);
+ }
+
+
+ @Override
+ public final byte getStoreType() {
+ return RStore.NUMERIC;
+ }
+
+ @Override
+ public final String getBaseVectorRClassName() {
+ return RObject.CLASSNAME_NUMERIC;
+ }
+
+
+ @Override
+ public boolean getLogi(final int idx) {
+ return getNum(idx) != 0.0;
+ }
+
+ @Override
+ public final boolean getLogi(final long idx) {
+ return getNum(idx) != 0.0;
+ }
+
+ @Override
+ public final void setLogi(final int idx, final boolean logi) {
+ setNum(idx, (logi) ? 1.0 : 0.0);
+ }
+
+ @Override
+ public final void setLogi(final long idx, final boolean logi) {
+ setNum(idx, (logi) ? 1.0 : 0.0);
+ }
+
+ @Override
+ public final int getInt(final int idx) {
+ return (int) getNum(idx);
+ }
+
+ @Override
+ public final int getInt(final long idx) {
+ return (int) getNum(idx);
+ }
+
+ @Override
+ public final void setInt(final int idx, final int integer) {
+ setNum(idx, integer);
+ }
+
+ @Override
+ public final void setInt(final long idx, final int integer) {
+ setNum(idx, integer);
+ }
+
+ @Override
+ public final double getCplxRe(final int idx) {
+ return getNum(idx);
+ }
+
+ @Override
+ public final double getCplxRe(final long idx) {
+ return getNum(idx);
+ }
+
+ @Override
+ public final double getCplxIm(final int idx) {
+ return 0.0;
+ }
+
+ @Override
+ public final double getCplxIm(final long idx) {
+ return 0.0;
+ }
+
+ @Override
+ public final String getChar(final int idx) {
+ return toChar(getNum(idx));
+ }
+
+ @Override
+ public String getChar(final long idx) {
+ return toChar(getNum(idx));
+ }
+
+
+ @Override
+ public abstract Double[] toArray();
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ final long length= getLength();
+ if (NUMERIC != other.getStoreType() || length != other.getLength()) {
+ return false;
+ }
+ if (length < 0) {
+ return true;
+ }
+ else if (length <= Integer.MAX_VALUE) {
+ final int ilength= (int) length;
+ for (int idx= 0; idx < ilength; idx++) {
+ if (!(isMissing(idx) ?
+ (isNA(idx) ? other.isNA(idx) : other.isMissing(idx)) :
+ (Math.abs(getNum(idx) - other.getNum(idx)) < 2.220446e-16 )) ) {
+ return false;
+ }
+ }
+ }
+ else {
+ for (long idx= 0; idx < length; idx++) {
+ if (!(isMissing(idx) ?
+ (isNA(idx) ? other.isNA(idx) : other.isMissing(idx)) :
+ (Math.abs(getNum(idx) - other.getNum(idx)) < 2.220446e-16 )) ) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRObject.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRObject.java
new file mode 100644
index 0000000..3970287
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRObject.java
@@ -0,0 +1,159 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractRObject implements RObject {
+
+
+ protected static final RObject[] EMPTY_ROBJECT_ARRAY= new RObject[0];
+ protected static final RObject[][] EMPTY_ROBJECT_2dARRAY= new RObject[0][];
+
+
+ protected static final long check2dArrayLength(final RObject[][] array, final int segmentLength) {
+ long length= 0;
+ if (array.length > 0) {
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ if (array[i].length != segmentLength) {
+ throw new IllegalArgumentException("Unexpected list segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+ }
+ }
+ length= last * (long) segmentLength;
+ if (array[last].length > segmentLength) {
+ throw new IllegalArgumentException("Unexpected list segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+ }
+ length+= array[last].length;
+ }
+ return length;
+ }
+
+ protected static final RObject[][] new2dRObjectArray(final long length, final int segmentLength) {
+ if (length == 0) {
+ return EMPTY_ROBJECT_2dARRAY;
+ }
+ final RObject[][] array= new RObject[1 + (int) ((length - 1) / segmentLength)][];
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ array[i]= new RObject[segmentLength];
+ }
+ { final int restLength= (int) (length % segmentLength);
+ array[last]= new RObject[(restLength == 0) ? segmentLength : restLength];
+ }
+ return array;
+ }
+
+
+ protected static final int checkShortLength(final long length) throws IOException {
+ if (length >= Integer.MAX_VALUE) {
+ throw new IOException("Long length (" + length + ") not supported by this implementation.");
+ }
+ return (int) length;
+ }
+
+
+ protected static final int getNewArraySize(final int length) {
+ if (length >= 0xfffffff) {
+ return Integer.MAX_VALUE;
+ }
+ return ((length+0x7) | 0xf) + 1;
+ }
+
+ protected static final RObject[] ensureCapacity(final RObject[] currentValues, final int length) {
+ if (currentValues.length >= length) {
+ return currentValues;
+ }
+ return new RObject[getNewArraySize(length)];
+ }
+
+ protected static final RStore<?>[] ensureCapacity(final RStore<?>[] currentValues, final int length) {
+ if (currentValues.length >= length) {
+ return currentValues;
+ }
+ return new RStore[getNewArraySize(length)];
+ }
+
+ protected static final RObject[] prepareInsert(final RObject[] currentValues, final int currentLength, final int[] idxs) {
+ final RObject[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+ int i= idxs.length-1;
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+ for (i--; i >= 0; i--) {
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+ }
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ return newValues;
+ }
+
+ protected static final RStore<?>[] prepareInsert(final RStore<?>[] currentValues, final int currentLength, final int[] idxs) {
+ final RStore<?>[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+ int i= idxs.length-1;
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+ for (i--; i >= 0; i--) {
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+ }
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ return newValues;
+ }
+
+ protected static final RObject[] remove(final RObject[] currentValues, final int currentLength, final int[] idxs) {
+ final RObject[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ int i= 0;
+ for (; i < idxs.length-1; i++) {
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+ }
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+ return newValues;
+ }
+
+ protected static final RStore<?>[] remove(final RStore<?>[] currentValues, final int currentLength, final int[] idxs) {
+ final RStore<?>[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ int i= 0;
+ for (; i < idxs.length-1; i++) {
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+ }
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+ return newValues;
+ }
+
+
+ private RList attributes;
+
+
+ protected void setAttributes(final RList attributes) {
+ this.attributes= attributes;
+ }
+
+ @Override
+ public final RList getAttributes() {
+ return this.attributes;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRStore.java
new file mode 100644
index 0000000..fbec4af
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRStore.java
@@ -0,0 +1,760 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractRStore<P> implements RStore<P> {
+
+
+ protected static final long NA_numeric_LONG= 0x7ff80000000007a2L;
+ protected static final long NA_numeric_LONG_MASK= 0x7ff00000ffffffffL;
+ protected static final long NA_numeric_LONG_MATCH= 0x7ff00000000007a2L;
+ protected static final int NA_numeric_INT_MATCH= 0x000007a2;
+ protected static final double NA_numeric_DOUBLE= Double.longBitsToDouble(NA_numeric_LONG);
+ protected static final long NaN_numeric_LONG= Double.doubleToLongBits(Double.NaN);
+ protected static final double NaN_numeric_DOUBLE= Double.NaN;
+
+ protected static final int NA_integer_INT= Integer.MIN_VALUE;
+
+ protected static final byte NA_byte_BYTE= 0x0; // no real NA, used e.g. for new values
+
+ protected static final byte FALSE_BYTE= 0;
+ protected static final byte TRUE_BYTE= 1;
+ protected static final byte NA_logical_BYTE= 2;
+
+ protected static final int FALSE_INT= 0;
+ protected static final int TRUE_INT= 1;
+ protected static final int NA_logical_INT= Integer.MIN_VALUE;
+
+ protected static final int WITH_NAMES= 0x1;
+
+ protected static final byte[] EMPTY_BYTE_ARRAY= new byte[0];
+ protected static final byte[][] EMPTY_BYTE_2dARRAY= new byte[0][];
+ protected static final int[] EMPTY_INT_ARRAY= new int[0];
+ protected static final int[][] EMPTY_INT_2dARRAY= new int[0][];
+ protected static final double[] EMPTY_DOUBLE_ARRAY= new double[0];
+ protected static final double[][] EMPTY_DOUBLE_2dARRAY= new double[0][];
+ protected static final String[] EMPTY_STRING_ARRAY= new String[0];
+ protected static final String[][] EMPTY_STRING_2dARRAY= new String[0][];
+
+ protected static final int DEFAULT_LONG_DATA_SEGMENT_LENGTH= 1 << 28;
+
+
+ private final static boolean gIsBSupported;
+ static {
+ gIsBSupported= checkIsBSupported();
+ }
+
+ public static boolean isBforNASupported() {
+ return gIsBSupported;
+ }
+
+ private static boolean checkIsBSupported() {
+ double d= 0;
+ long l= 0;
+
+ d= NA_numeric_DOUBLE;
+ l= Double.doubleToRawLongBits(d);
+ if (l != NA_numeric_LONG) {
+ return false;
+ }
+
+ d= Double.longBitsToDouble(l);
+ l= Double.doubleToRawLongBits(d);
+ if (l != NA_numeric_LONG) {
+ return false;
+ }
+ return true;
+ }
+
+
+ protected static final long check2dArrayLength(final int[][] array, final int segmentLength) {
+ long length= 0;
+ if (array.length > 0) {
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ if (array[i].length != segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+ }
+ }
+ length= last * (long) segmentLength;
+ if (array[last].length > segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+ }
+ length+= array[last].length;
+ }
+ return length;
+ }
+
+ protected static final long check2dArrayLength(final double[][] array, final int segmentLength) {
+ long length= 0;
+ if (array.length > 0) {
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ if (array[i].length != segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+ }
+ }
+ length= last * (long) segmentLength;
+ if (array[last].length > segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+ }
+ length+= array[last].length;
+ }
+ return length;
+ }
+
+ protected static final long check2dArrayLength(final byte[][] array, final int segmentLength) {
+ long length= 0;
+ if (array.length > 0) {
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ if (array[i].length != segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+ }
+ }
+ length= last * (long) segmentLength;
+ if (array[last].length > segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+ }
+ length+= array[last].length;
+ }
+ return length;
+ }
+
+ protected static final long check2dArrayLength(final Object[][] array, final int segmentLength) {
+ long length= 0;
+ if (array.length > 0) {
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ if (array[i].length != segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[i].length + ", but " + segmentLength + " expected)");
+ }
+ }
+ length= last * (long) segmentLength;
+ if (array[last].length > segmentLength) {
+ throw new IllegalArgumentException("Unexpected data segment length (" + array[last].length + ", but max " + segmentLength + " expected)");
+ }
+ length+= array[last].length;
+ }
+ return length;
+ }
+
+ protected static final int[][] new2dIntArray(final long length, final int segmentLength) {
+ if (length == 0) {
+ return EMPTY_INT_2dARRAY;
+ }
+ final int[][] array= new int[1 + (int) ((length - 1) / segmentLength)][];
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ array[i]= new int[segmentLength];
+ }
+ { final int restLength= (int) (length % segmentLength);
+ array[last]= new int[(restLength == 0) ? segmentLength : restLength];
+ }
+ return array;
+ }
+
+ protected static final double[][] new2dDoubleArray(final long length, final int segmentLength) {
+ if (length == 0) {
+ return EMPTY_DOUBLE_2dARRAY;
+ }
+ final double[][] array= new double[1 + (int) ((length - 1) / segmentLength)][];
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ array[i]= new double[segmentLength];
+ }
+ { final int restLength= (int) (length % segmentLength);
+ array[last]= new double[(restLength == 0) ? segmentLength : restLength];
+ }
+ return array;
+ }
+
+ protected static final String[][] new2dStringArray(final long length, final int segmentLength) {
+ if (length == 0) {
+ return EMPTY_STRING_2dARRAY;
+ }
+ final String[][] array= new String[1 + (int) ((length - 1) / segmentLength)][];
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ array[i]= new String[segmentLength];
+ }
+ { final int restLength= (int) (length % segmentLength);
+ array[last]= new String[(restLength == 0) ? segmentLength : restLength];
+ }
+ return array;
+ }
+
+ protected static final byte[][] new2dByteArray(final long length, final int segmentLength) {
+ if (length == 0) {
+ return EMPTY_BYTE_2dARRAY;
+ }
+ final byte[][] array= new byte[1 + (int) ((length - 1) / segmentLength)][];
+ final int last= array.length - 1;
+ for (int i= 0; i < last; i++) {
+ array[i]= new byte[segmentLength];
+ }
+ { final int restLength= (int) (length % segmentLength);
+ array[last]= new byte[(restLength == 0) ? segmentLength : restLength];
+ }
+ return array;
+ }
+
+
+ protected static final int[] addIdx(final int[] idxs, final int newIdx) {
+ int i= Arrays.binarySearch(idxs, newIdx);
+ if (i >= 0) {
+ return idxs;
+ }
+ final int[] newIdxs= new int[idxs.length+1];
+ i= -1-i;
+ System.arraycopy(idxs, 0, newIdxs, 0, i);
+ newIdxs[i]= newIdx;
+ System.arraycopy(idxs, i, newIdxs, i+1, idxs.length-i);
+ return newIdxs;
+ }
+
+ protected static final int[] insertIdx(final int[] currentIdxs, final int[] insertedIdxs) {
+ final int[] pos= new int[insertedIdxs.length];
+ for (int i= 0; i < pos.length; i++) {
+ pos[i]= Arrays.binarySearch(currentIdxs, insertedIdxs[i]);
+ if (pos[i] < 0) {
+ pos[i]= -1-pos[i];
+ }
+ }
+ final int[] newIdxs= new int[currentIdxs.length+insertedIdxs.length];
+ int l= pos.length;
+ int ci= currentIdxs.length-1;
+ while(l > 1) {
+ final int stop= pos[l-1];
+ for (; ci >= stop; ci--) {
+ newIdxs[ci+l]= currentIdxs[ci] + l;
+ }
+ l--;
+ newIdxs[ci+l]= insertedIdxs[l] + l;
+ }
+ System.arraycopy(currentIdxs, 0, newIdxs, 0, pos[0]);
+ return newIdxs;
+ }
+
+ protected static final void updateIdxInserted(final int[] currentIdxs, final int[] insertedIdxs) {
+ int pos= Arrays.binarySearch(currentIdxs, insertedIdxs[0]);
+ if (pos < 0) {
+ pos= -1-pos;
+ }
+ for (int i= 0; i < insertedIdxs.length; ) {
+ i++;
+ int stop= (i < insertedIdxs.length) ? Arrays.binarySearch(currentIdxs, insertedIdxs[i]) : currentIdxs.length;
+ if (stop < 0) {
+ stop= -1-stop;
+ }
+ while (pos < stop) {
+ currentIdxs[pos]+= i;
+ }
+ pos= stop;
+ }
+ }
+
+ protected static final int[] updateIdxRemoved(final int[] currentIdxs, final int[] removedIdxs) {
+ final int[] pos= new int[removedIdxs.length];
+ int naCount= 0;
+ for (int i= 0; i < pos.length; i++) {
+ pos[i]= Arrays.binarySearch(currentIdxs, removedIdxs[i]);
+ if (pos[i] < 0) {
+ pos[i]= -1-pos[i];
+ }
+ else {
+ naCount++;
+ }
+ }
+ final int[] newIdxs= (naCount == 0) ? currentIdxs : new int[currentIdxs.length-naCount];
+ int l= 0;
+ int ci= 0;
+ int ni= 0;
+ if (newIdxs != currentIdxs) {
+ System.arraycopy(currentIdxs, 0, newIdxs, 0, pos[0]);
+ }
+ while(l < removedIdxs.length) {
+ if (currentIdxs[pos[l]] == removedIdxs[l]) {
+ ci++;
+ }
+ l++;
+ final int stop= (l < removedIdxs.length) ? pos[l] : currentIdxs.length;
+ for (; ci < stop; ci++, ni++) {
+ newIdxs[ni]= currentIdxs[ci] - l;
+ }
+ }
+ return newIdxs;
+ }
+
+ protected static final int[] deleteIdx(final int[] idxs, final int removeIdx) {
+ final int i= Arrays.binarySearch(idxs, removeIdx);
+ if (i < 0) {
+ return idxs;
+ }
+ final int[] newIdxs= new int[idxs.length-1];
+ System.arraycopy(idxs, 0, newIdxs, 0, i);
+ System.arraycopy(idxs, i+1, newIdxs, i, idxs.length-i-1);
+ return newIdxs;
+ }
+
+ protected static final int getNewArraySize(final int length) {
+ if (length >= 0xfffffff) {
+ return Integer.MAX_VALUE;
+ }
+ return ((length+0x7) | 0xf) + 1;
+ }
+
+ protected static final double[] ensureCapacity(final double[] currentValues, final int length) {
+ if (currentValues.length >= length) {
+ return currentValues;
+ }
+ return new double[getNewArraySize(length)];
+ }
+
+ protected static final int[] ensureCapacity(final int[] currentValues, final int length) {
+ final int diff= currentValues.length - length;
+ if (diff >= 0 && diff <= 512) {
+ return currentValues;
+ }
+ return new int[getNewArraySize(length)];
+ }
+
+ protected static final byte[] ensureCapacity(final byte[] currentValues, final int length) {
+ if (currentValues.length >= length) {
+ return currentValues;
+ }
+ return new byte[getNewArraySize(length)];
+ }
+
+ protected static final String[] ensureCapacity(final String[] currentValues, final int length) {
+ if (currentValues.length >= length) {
+ return currentValues;
+ }
+ return new String[getNewArraySize(length)];
+ }
+
+ protected static final double[] prepareInsert(final double[] currentValues, final int currentLength, final int[] idxs) {
+ final double[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+ int i= idxs.length-1;
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+ for (i--; i >= 0; i--) {
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+ }
+ if (newValues != currentValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ return newValues;
+ }
+
+ protected static final int[] prepareInsert(final int[] currentValues, final int currentLength, final int[] idxs) {
+ final int[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+ int i= idxs.length-1;
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+ for (i--; i >= 0; i--) {
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+ }
+ if (newValues != currentValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ return newValues;
+ }
+
+ protected static final byte[] prepareInsert(final byte[] currentValues, final int currentLength, final int[] idxs) {
+ final byte[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+ int i= idxs.length-1;
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+ for (i--; i >= 0; i--) {
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+ }
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ return newValues;
+ }
+
+ protected static final String[] prepareInsert(final String[] currentValues, final int currentLength, final int[] idxs) {
+ final String[] newValues= ensureCapacity(currentValues, currentLength+idxs.length);
+ int i= idxs.length-1;
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, currentLength-idxs[i]);
+ for (i--; i >= 0; i--) {
+ System.arraycopy(currentValues, idxs[i], newValues, idxs[i]+i+1, idxs[i+1]-idxs[i]);
+ }
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ return newValues;
+ }
+
+ protected static final double[] remove(final double[] currentValues, final int currentLength, final int[] idxs) {
+ final double[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ int i= 0;
+ for (; i < idxs.length-1; i++) {
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+ }
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+ return newValues;
+ }
+
+ protected static final int[] remove(final int[] currentValues, final int currentLength, final int[] idxs) {
+ final int[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ int i= 0;
+ for (; i < idxs.length-1; i++) {
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+ }
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+ return newValues;
+ }
+
+ protected static final byte[] remove(final byte[] currentValues, final int currentLength, final int[] idxs) {
+ final byte[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ int i= 0;
+ for (; i < idxs.length-1; i++) {
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+ }
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+ return newValues;
+ }
+
+ protected static final String[] remove(final String[] currentValues, final int currentLength, final int[] idxs) {
+ final String[] newValues= ensureCapacity(currentValues, currentLength-idxs.length);
+ if (currentValues != newValues) {
+ System.arraycopy(currentValues, 0, newValues, 0, idxs[0]);
+ }
+ int i= 0;
+ for (; i < idxs.length-1; i++) {
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, idxs[i+1]-idxs[i]);
+ }
+ System.arraycopy(currentValues, idxs[i]+1, newValues, idxs[i]-i, currentLength-idxs[i]-1);
+ return newValues;
+ }
+
+
+ @Override
+ public void setNA(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getLogi(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getLogi(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setLogi(final int idx, final boolean logi) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setLogi(final long idx, final boolean logi) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getInt(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getInt(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setInt(final int idx, final int integer) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setInt(final long idx, final int integer) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getNum(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getNum(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNum(final int idx, final double real) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNum(final long idx, final double real) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getChar(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getChar(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setChar(final int idx, final String character) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setChar(final long idx, final String character) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte getRaw(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte getRaw(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setRaw(final int idx, final byte raw) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setRaw(final long idx, final byte raw) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getCplxIm(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getCplxIm(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getCplxRe(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getCplxRe(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setCplx(final int idx, final double real, final double imaginary) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setCplx(final long idx, final double real, final double imaginary) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ protected abstract boolean isStructOnly();
+
+
+ @Override
+ public boolean containsNA() {
+ return (indexOfNA(0) >= 0);
+ }
+
+ @Override
+ public long indexOfNA() {
+ return indexOfNA(0);
+ }
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final long length= getLength();
+ while (fromIdx < length) {
+ if (isNA(fromIdx)) {
+ return fromIdx;
+ }
+ fromIdx++;
+ }
+ return -1;
+ }
+
+ @Override
+ public boolean contains(final int integer) {
+ return (indexOf(integer, 0) >= 0);
+ }
+
+ @Override
+ public final long indexOf(final int integer) {
+ return indexOf(integer, 0);
+ }
+
+ @Override
+ public long indexOf(final int integer, long fromIdx) {
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final long l= getLength();
+ while (fromIdx < l) {
+ if (!isNA(fromIdx) && integer == getInt(fromIdx)) {
+ return fromIdx;
+ }
+ fromIdx++;
+ }
+ return -1;
+ }
+
+ @Override
+ public boolean contains(final String character) {
+ return (indexOf(character, 0) >= 0);
+ }
+
+ @Override
+ public final long indexOf(final String character) {
+ return indexOf(character, 0);
+ }
+
+ @Override
+ public long indexOf(final String character, long fromIdx) {
+ if (character == null) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final long l= getLength();
+ while (fromIdx < l) {
+ if (!isNA(fromIdx) && character.equals(getChar(fromIdx))) {
+ return fromIdx;
+ }
+ fromIdx++;
+ }
+ return -1;
+ }
+
+
+ protected int checkToArrayLength() {
+ final long length= getLength();
+ if (length > Integer.MAX_VALUE) {
+ throw new UnsupportedOperationException("Not supported for long data");
+ }
+ return (int) length;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append(RDataUtils.getStoreAbbr(this));
+ sb.append(' ');
+ final long length;
+ if (isStructOnly()) {
+ sb.append("<struct only>");
+ }
+ else if ((length= getLength()) > 0) {
+ long end= (length <= 25) ? length : 10;
+ if (getStoreType() == CHARACTER) {
+ for (long idx= 0; true;) {
+ if (isNA(idx)) {
+ sb.append("NA");
+ }
+ else {
+ sb.append('"');
+ sb.append(getChar(idx));
+ sb.append('"');
+ }
+ idx++;
+ if (idx < end) {
+ sb.append(", ");
+ continue;
+ }
+ else {
+ if (end == length) {
+ break;
+ }
+ else {
+ sb.append(", .., ");
+ idx= length - 10;
+ end= length;
+ continue;
+ }
+ }
+ }
+ }
+ else {
+ for (long idx= 0; true;) {
+ if (isNA(idx)) {
+ sb.append("NA");
+ }
+ else {
+ sb.append(getChar(idx));
+ }
+ idx++;
+ if (idx < end) {
+ sb.append(", ");
+ continue;
+ }
+ else {
+ if (end == length) {
+ break;
+ }
+ else {
+ sb.append(", .., ");
+ idx= length - 10;
+ end= length;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRawStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRawStore.java
new file mode 100644
index 0000000..0a8bb44
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/AbstractRawStore.java
@@ -0,0 +1,102 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RRawStore;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public abstract class AbstractRawStore extends AbstractRStore<Byte>
+ implements RRawStore {
+
+
+ private static final char[] HEX_CHARS= new char[] {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ protected static final String toChar(final byte raw) {
+ return new String(new char[] { HEX_CHARS[(raw >>> 4) & 0x0F], HEX_CHARS[(raw & 0x0F)] });
+ }
+
+
+ @Override
+ public final byte getStoreType() {
+ return RStore.RAW;
+ }
+
+ @Override
+ public final String getBaseVectorRClassName() {
+ return RObject.CLASSNAME_RAW;
+ }
+
+
+ @Override
+ public final boolean isNA(final int idx) {
+ return false;
+ }
+
+ @Override
+ public final boolean isNA(final long idx) {
+ return false;
+ }
+
+ @Override
+ public final boolean isMissing(final int idx) {
+ return false;
+ }
+
+ @Override
+ public final boolean isMissing(final long idx) {
+ return false;
+ }
+
+ @Override
+ public int getInt(final int idx) {
+ return (getRaw(idx) & 0xff);
+ }
+
+ @Override
+ public int getInt(final long idx) {
+ return (getRaw(idx) & 0xff);
+ }
+
+ @Override
+ public void setInt(final long idx, final int integer) {
+ setRaw(idx, AbstractIntegerStore.toRaw(integer));
+ }
+
+ @Override
+ public void setInt(final int idx, final int integer) {
+ setRaw(idx, AbstractIntegerStore.toRaw(integer));
+ }
+
+ @Override
+ public final String getChar(final int idx) {
+ return toChar(getRaw(idx));
+ }
+
+ @Override
+ public final String getChar(final long idx) {
+ return toChar(getRaw(idx));
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ return -1;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/DefaultRObjectFactory.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/DefaultRObjectFactory.java
new file mode 100644
index 0000000..b14c3b8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/DefaultRObjectFactory.java
@@ -0,0 +1,731 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RComplexStore;
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RFactorStore;
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RLogicalStore;
+import org.eclipse.statet.rj.data.RNumericStore;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RRawStore;
+import org.eclipse.statet.rj.data.RStore;
+import org.eclipse.statet.rj.data.RVector;
+
+
+public class DefaultRObjectFactory implements RObjectFactory {
+
+
+ public static final DefaultRObjectFactory INSTANCE= new DefaultRObjectFactory();
+
+ public static final RNumericStore NUM_STRUCT_DUMMY= new RNumericStructStore();
+ public static final RComplexStructStore CPLX_STRUCT_DUMMY= new RComplexStructStore();
+ public static final RIntegerStructStore INT_STRUCT_DUMMY= new RIntegerStructStore();
+ public static final RLogicalStructStore LOGI_STRUCT_DUMMY= new RLogicalStructStore();
+ public static final RRawStructStore RAW_STRUCT_DUMMY= new RRawStructStore();
+ public static final RCharacterStructStore CHR_STRUCT_DUMMY= new RCharacterStructStore();
+
+
+ private final long storeLengthFixLong= AbstractRStore.DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ public DefaultRObjectFactory() {
+ }
+
+
+ /*-- Vector --*/
+
+ /**
+ * Creates an R vector with the given R data store and R class name.
+ *
+ * @param data the data store
+ * @param classname the R class name
+ * @return the R vector
+ */
+ public <TData extends RStore<?>> RVector<TData> createVector(final TData data, final String classname) {
+ return new RVectorImpl<>(data, classname);
+ }
+
+ /**
+ * Creates an R vector with the given R data store.
+ * <p>
+ * The vector has the default R class name for data type of the given store.</p>
+ *
+ * @param data the data store
+ * @return the R vector
+ */
+ @Override
+ public <TData extends RStore<?>> RVector<TData> createVector(final TData data) {
+ return createVector(data, data.getBaseVectorRClassName());
+ }
+
+
+ /**
+ * Creates an R logical vector with values from a Java boolean array.
+ * <p>
+ * The vector has the default R class name 'logical'.</p>
+ * <p>
+ * Note that the R vector may use the array directly. For values
+ * see {@link RStore#setLogi(int, boolean)}.</p>
+ *
+ * @param logicals the logical values
+ * @return the R logical vector
+ */
+ public RVector<RLogicalStore> createLogiVector(final boolean[] logicals) {
+ return createVector(createLogiData(logicals), RObject.CLASSNAME_LOGICAL);
+ }
+
+ /**
+ * Creates an R logical vector of the given length.
+ * <p>
+ * The vector has the default R class name 'logical'.</p>
+ * <p>
+ * The function works analog to the R function <code>logical(length)</code>;
+ * the vector is initialized with FALSE values.</p>
+ *
+ * @param length the length of the vector
+ * @return the R logical vector
+ */
+ public RVector<RLogicalStore> createLogiVector(final int length) {
+ return createVector(createLogiData(length), RObject.CLASSNAME_LOGICAL);
+ }
+
+ /**
+ * Creates an R integer vector with values from a Java integer array.
+ * <p>
+ * The vector has the default R class name 'integer'.</p>
+ * <p>
+ * Note that the R vector may use the array directly. For values
+ * see {@link RStore#setInt(int, int)}.</p>
+ *
+ * @param integers the integer values
+ * @return the R integer vector
+ */
+ public RVector<RIntegerStore> createIntVector(final int[] integers) {
+ return createVector(createIntData(integers), RObject.CLASSNAME_INTEGER);
+ }
+
+ /**
+ * Creates an R integer vector of the given length.
+ * <p>
+ * The vector has the default R class name 'integer'.</p>
+ * <p>
+ * The function works analog to the R function <code>integer(length)</code>;
+ * the vector is initialized with 0 values.</p>
+ *
+ * @param length the length of the vector
+ * @return the R integer vector
+ */
+ public RVector<RIntegerStore> createIntVector(final int length) {
+ return createVector(createIntData(length), RObject.CLASSNAME_INTEGER);
+ }
+
+ /**
+ * Creates an R numeric vector with values from a Java double array.
+ * <p>
+ * The vector has the default R class name 'numeric'.</p>
+ * <p>
+ * Note that the R vector may use the array directly. For values
+ * see {@link RStore#setNum(int, double)}.</p>
+ *
+ * @param numerics the numerics values
+ * @return the R numeric vector
+ */
+ public RVector<RNumericStore> createNumVector(final double[] numerics) {
+ return createVector(createNumData(numerics), RObject.CLASSNAME_NUMERIC);
+ }
+
+ /**
+ * Creates an R numeric vector of the given length.
+ * <p>
+ * The vector has the default R class name 'numeric'.</p>
+ * <p>
+ * The function works analog to the R function <code>numeric(length)</code>;
+ * the vector is initialized with 0.0 values.</p>
+ *
+ * @param length the length of the vector
+ * @return the R numeric vector
+ */
+ public RVector<RNumericStore> createNumVector(final int length) {
+ return createVector(createNumData(length), RObject.CLASSNAME_NUMERIC);
+ }
+
+ /**
+ * Creates an R complex vector of the given length.
+ * <p>
+ * The vector has the default R class name 'complex'.</p>
+ * <p>
+ * The function works analog to the R function <code>complex(length)</code>;
+ * the vector is initialized with 0.0 values.</p>
+ *
+ * @param length the length of the vector
+ * @return the R complex vector
+ */
+ public RVector<RComplexStore> createCplxVector(final int length) {
+ return createVector(createCplxData(length), RObject.CLASSNAME_COMPLEX);
+ }
+
+ /**
+ * Creates an R character vector with values from a Java String array.
+ * <p>
+ * The vector has the default R class name 'character'.</p>
+ * <p>
+ * Note that the R vector may use the array directly. For values
+ * see {@link RStore#setChar(int, String)}.</p>
+ *
+ * @param characters the characters values
+ * @return the R character vector
+ */
+ public RVector<RCharacterStore> createCharVector(final String[] characters) {
+ return createVector(createCharData(characters), RObject.CLASSNAME_CHARACTER);
+ }
+
+ /**
+ * Creates an R character vector of the given length.
+ * <p>
+ * The vector has the default R class name 'character'.</p>
+ * <p>
+ * The function works analog to the R function <code>character(length)</code>;
+ * the vector is initialized with "" (empty String) values.</p>
+ *
+ * @param length the length of the vector
+ * @return the R charcter vector
+ */
+ public RVector<RCharacterStore> createCharVector(final int length) {
+ return createVector(createCharData(length), RObject.CLASSNAME_CHARACTER);
+ }
+
+ /**
+ * Creates an R raw vector of the specified length.
+ * <p>
+ * The vector has the default R class name 'raw'.</p>
+ * <p>
+ * The function works analog to the R function <code>raw(length)</code>;
+ * the vector is initialized with 0.0 values.</p>
+ *
+ * @param length the length of the vector
+ * @return the R complex vector
+ */
+ public RVector<RRawStore> createRawVector(final int length) {
+ return createVector(createRawData(length), RObject.CLASSNAME_RAW);
+ }
+
+ /**
+ * Creates an R (unordered) factor vector with level codes from a Java integer array.
+ * <p>
+ * The vector has the default R class name 'factor'.</p>
+ * <p>
+ * Note that the R vector may use the array directly.</p>
+ *
+ * @param codes the coded levels
+ * @param levels the labels of the levels
+ * @return the R factor vector
+ */
+ public RVector<RFactorStore> createFactorVector(final int[] codes, final String[] levels) {
+ return createVector(createFactorData(codes, levels), RObject.CLASSNAME_FACTOR);
+ }
+
+ /**
+ * Creates an R (unordered) factor vector of the specified length.
+ * <p>
+ * The vector has the default R class name 'factor'.</p>
+ *
+ * @param length the length of the vector
+ * @param levels the labels of the levels
+ * @return the R factor vector
+ */
+ public RVector<RFactorStore> createFactorVector(final int length, final String[] levels) {
+ return createVector(createFactorData(length, levels), RObject.CLASSNAME_FACTOR);
+ }
+
+ /**
+ * Creates an R ordered factor vector with level codes from a Java integer array.
+ * <p>
+ * The vector has the default R class name 'ordered'.</p>
+ * <p>
+ * Note that the R vector may use the array directly.</p>
+ *
+ * @param codes the coded levels
+ * @param levels the labels of the levels
+ * @return the R factor vector
+ */
+ public RVector<RFactorStore> createOrderedVector(final int[] codes, final String[] levels) {
+ return createVector(createOrderedData(codes, levels), RObject.CLASSNAME_ORDERED);
+ }
+
+ /**
+ * Creates an R ordered factor vector of the specified length.
+ * <p>
+ * The vector has the default R class name 'factor'.</p>
+ *
+ * @param length the length of the vector
+ * @param levels the labels of the levels
+ * @return the R factor vector
+ */
+ public RVector<RFactorStore> createOrderedVector(final int length, final String[] levels) {
+ return createVector(createOrderedData(length, levels), RObject.CLASSNAME_ORDERED);
+ }
+
+
+ /*-- Array/Matrix --*/
+
+ public <TData extends RStore<?>> RArray<TData> createArray(final TData data, final int[] dim,
+ final String classname) {
+ return new RArrayImpl<>(data, classname, dim);
+ }
+
+ @Override
+ public <TData extends RStore<?>> RArray<TData> createArray(final TData data, final int[] dim) {
+ return createArray(data, dim, (dim.length == 2) ? RObject.CLASSNAME_MATRIX :RObject.CLASSNAME_ARRAY);
+ }
+
+ @Override
+ public <TData extends RStore<?>> RArray<TData> createMatrix(final TData data, final int dim1, final int dim2) {
+ return createArray(data, new int[] { dim1, dim2 }, RObject.CLASSNAME_MATRIX);
+ }
+
+
+ public RArray<RLogicalStore> createLogiArray(final boolean[] logicals, final int[] dim) {
+ return createArray(createLogiData(logicals), dim);
+ }
+
+ public RArray<RLogicalStore> createLogiArray(final int[] dim) {
+ return createArray(createLogiData(RDataUtils.computeLengthFromDim(dim)), dim);
+ }
+
+ public RArray<RIntegerStore> createIntArray(final int[] integers, final int[] dim) {
+ return createArray(createIntData(integers), dim);
+ }
+
+ public RArray<RIntegerStore> createIntArray(final int[] dim) {
+ return createArray(createIntData(RDataUtils.computeLengthFromDim(dim)), dim);
+ }
+
+ public RArray<RNumericStore> createNumArray(final double[] numerics, final int[] dim) {
+ return createArray(createNumData(numerics), dim);
+ }
+
+ public RArray<RNumericStore> createNumArray(final int[] dim) {
+ return createArray(createNumData(RDataUtils.computeLengthFromDim(dim)), dim);
+ }
+
+ public RArray<RCharacterStore> createCharArray(final String[] characters, final int[] dim) {
+ return createArray(createCharData(characters), dim);
+ }
+
+ public RArray<RCharacterStore> createCharArray(final int[] dim) {
+ return createArray(createCharData(RDataUtils.computeLengthFromDim(dim)), dim);
+ }
+
+
+ public RArray<RLogicalStore> createLogiMatrix(final boolean[] logicals, final int dim1, final int dim2) {
+ return createMatrix(createLogiData(logicals), dim1, dim2);
+ }
+
+ public RArray<RLogicalStore> createLogiMatrix(final int dim1, final int dim2) {
+ return createMatrix(createLogiData(dim1*dim2), dim1, dim2);
+ }
+
+ public RArray<RIntegerStore> createIntMatrix(final int[] integers, final int dim1, final int dim2) {
+ return createMatrix(createIntData(integers), dim1, dim2);
+ }
+
+ public RArray<RIntegerStore> createIntMatrix(final int dim1, final int dim2) {
+ return createMatrix(createIntData(dim1*dim2), dim1, dim2);
+ }
+
+ public RArray<RNumericStore> createNumMatrix(final double[] numerics, final int dim1, final int dim2) {
+ return createMatrix(createNumData(numerics), dim1, dim2);
+ }
+
+ public RArray<RNumericStore> createNumMatrix(final int dim1, final int dim2) {
+ return createMatrix(createNumData(dim1*dim2), dim1, dim2);
+ }
+
+ public RArray<RCharacterStore> createCharMatrix(final String[] characters, final int dim1, final int dim2) {
+ return createMatrix(createCharData(characters), dim1, dim2);
+ }
+
+ public RArray<RCharacterStore> createCharMatrix(final int dim1, final int dim2) {
+ return createMatrix(createCharData(dim1*dim2), dim1, dim2);
+ }
+
+
+ /*-- DataFrame --*/
+
+ public RDataFrame createDataFrame(final RStore<?>[] colDatas, final String[] colNames) {
+ return createDataFrame(colDatas, colNames, null);
+ }
+
+ public RDataFrame createDataFrame(final RStore<?>[] colDatas, final String[] colNames, final String[] rowNames) {
+ final RObject[] colVectors= new RObject[colDatas.length];
+ for (int i= 0; i < colVectors.length; i++) {
+ colVectors[i]= createVector(colDatas[i]);
+ }
+ return createDataFrame(colVectors, colNames, rowNames);
+ }
+
+ public RDataFrame createDataFrame(final RObject[] colVectors,
+ final String[] colNames, final String[] rowNames) {
+ return new RDataFrame32Impl(colVectors, RObject.CLASSNAME_DATAFRAME, colNames, rowNames);
+ }
+
+
+ public RList createList(final RObject[] components, final String[] names, final String classname) {
+ return new RList32Impl(components, classname, names);
+ }
+
+ @Override
+ public RList createList(final RObject[] components, final String[] names) {
+ return createList(components, names, RObject.CLASSNAME_LIST);
+ }
+
+
+ /*-- Language --*/
+
+ @Override
+ public RLanguage createName(final String name) {
+ return new RLanguageImpl(RLanguage.NAME, name, RObject.CLASSNAME_NAME);
+ }
+
+ @Override
+ public RLanguage createExpression(final String expr) {
+ return new RLanguageImpl(RLanguage.EXPRESSION, expr, RObject.CLASSNAME_EXPRESSION);
+ }
+
+
+ /*-- Data/RStore --*/
+
+ @Override
+ public RLogicalStore createLogiData(final boolean[] logiValues) {
+ return new RLogicalByte32Store(logiValues);
+ }
+
+ public RLogicalStore createLogiData(final long length) {
+ return (length <= this.storeLengthFixLong) ?
+ new RLogicalByte32Store((int) length) :
+ new RLogicalByteFix64Store(length);
+ }
+
+ @Override
+ public RIntegerStore createIntData(final int[] intValues) {
+ return new RInteger32Store(intValues);
+ }
+
+ public RIntegerStore createIntData(final long length) {
+ return (length <= this.storeLengthFixLong) ?
+ new RInteger32Store((int) length) :
+ new RIntegerFix64Store(length);
+ }
+
+ @Override
+ public RNumericStore createNumData(final double[] numValues) {
+ return new RNumericB32Store(numValues);
+ }
+
+ public RNumericStore createNumData(final long length) {
+ return (length <= this.storeLengthFixLong) ?
+ new RNumericB32Store((int) length) :
+ new RNumericBFix64Store(length);
+ }
+
+ @Override
+ public RComplexStore createCplxData(final double[] reValues, final double[] imValues) {
+ return new RComplexB32Store(reValues, imValues, null);
+ }
+
+ public RComplexStore createCplxData(final long length) {
+ return (length <= this.storeLengthFixLong) ?
+ new RComplexB32Store((int) length) :
+ new RComplexBFix64Store(length);
+ }
+
+ @Override
+ public RCharacterStore createCharData(final String[] charValues) {
+ return new RCharacter32Store(charValues);
+ }
+
+ public RCharacterStore createCharData(final long length) {
+ return (length <= this.storeLengthFixLong) ?
+ new RCharacter32Store((int) length) :
+ new RCharacterFix64Store(length);
+ }
+
+ @Override
+ public RRawStore createRawData(final byte[] rawValues) {
+ return new RRaw32Store(rawValues);
+ }
+
+ public RRawStore createRawData(final long length) {
+ return (length <= this.storeLengthFixLong) ?
+ new RRaw32Store((int) length) :
+ new RRawFix64Store(length);
+ }
+
+ @Override
+ public RFactorStore createFactorData(final int[] codes, final String[] levels) {
+ return new RFactor32Store(codes, false, levels);
+ }
+
+ public RFactorStore createFactorData(final int length, final String[] levels) {
+ return new RFactor32Store(length, false, levels);
+ }
+
+ public RFactorStore createOrderedData(final int[] codes, final String[] levels) {
+ return new RFactor32Store(codes, true, levels);
+ }
+
+ public RFactorStore createOrderedData(final int length, final String[] levels) {
+ return new RFactor32Store(length, true, levels);
+ }
+
+
+ /*-- Streaming --*/
+
+ @Override
+ public RObject readObject(final RJIO io) throws IOException {
+ final byte type= io.readByte();
+ int options;
+ switch (type) {
+ case -1:
+ return null;
+ case RObject.TYPE_NULL:
+ return RNullImpl.INSTANCE;
+ case RObject.TYPE_VECTOR: {
+ return new RVectorImpl(io, this); }
+ case RObject.TYPE_ARRAY:
+ return new RArrayImpl(io, this);
+ case RObject.TYPE_LIST:
+ options= io.readInt();
+ return ((options & O_LENGTHGRADE_MASK) <= 3) ?
+ new RList32Impl(io, this, options) :
+ new RListFix64Impl(io, this, options);
+ case RObject.TYPE_DATAFRAME:
+ options= io.readInt();
+ return ((options & O_LENGTHGRADE_MASK) <= 3) ?
+ new RDataFrame32Impl(io, this, options) :
+ new RListFix64Impl(io, this, options);
+ case RObject.TYPE_ENVIRONMENT:
+ return new REnvironmentImpl(io, this);
+ case RObject.TYPE_LANGUAGE:
+ return new RLanguageImpl(io, this);
+ case RObject.TYPE_FUNCTION:
+ return new RFunctionImpl(io, this);
+ case RObject.TYPE_REFERENCE:
+ return new RReferenceImpl(io, this);
+ case RObject.TYPE_S4OBJECT:
+ return new RS4ObjectImpl(io, this);
+ case RObject.TYPE_OTHER:
+ return new ROtherImpl(io, this);
+ case RObject.TYPE_MISSING:
+ return RMissingImpl.INSTANCE;
+ case RObject.TYPE_PROMISE:
+ return RPromiseImpl.INSTANCE;
+ default:
+ throw new IOException("object type= " + type);
+ }
+ }
+
+ @Override
+ public void writeObject(final RObject robject, final RJIO io) throws IOException {
+ if (robject == null) {
+ io.writeByte(-1);
+ return;
+ }
+ final byte type= robject.getRObjectType();
+ io.writeByte(type);
+ switch (type) {
+ case RObject.TYPE_NULL:
+ case RObject.TYPE_MISSING:
+ case RObject.TYPE_PROMISE:
+ return;
+ case RObject.TYPE_VECTOR:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_ARRAY:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_LIST:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_DATAFRAME:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_ENVIRONMENT:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_LANGUAGE:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_FUNCTION:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_REFERENCE:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_S4OBJECT:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ case RObject.TYPE_OTHER:
+ ((ExternalizableRObject) robject).writeExternal(io, this);
+ return;
+ default:
+ throw new IOException("object type= " + type);
+ }
+ }
+
+ @Override
+ public RStore<?> readStore(final RJIO io, final long length) throws IOException {
+ if ((io.flags & F_ONLY_STRUCT) == 0) {
+ final byte storeType= io.readByte();
+ if (length <= Integer.MAX_VALUE) {
+ switch (storeType) {
+ case RStore.LOGICAL:
+ return new RLogicalByte32Store(io, (int) length);
+ case RStore.INTEGER:
+ return new RInteger32Store(io, (int) length);
+ case RStore.NUMERIC:
+ return new RNumericB32Store(io, (int) length);
+ case RStore.COMPLEX:
+ return new RComplexB32Store(io, (int) length);
+ case RStore.CHARACTER:
+ return new RCharacter32Store(io, (int) length);
+ case RStore.RAW:
+ return new RRaw32Store(io, (int) length);
+ case RStore.FACTOR:
+ return new RFactor32Store(io, (int) length);
+ default:
+ throw new IOException("store type= " + storeType);
+ }
+ }
+ else {
+ switch (storeType) {
+ case RStore.LOGICAL:
+ return new RLogicalByteFix64Store(io, length);
+ case RStore.INTEGER:
+ return new RIntegerFix64Store(io, length);
+ case RStore.NUMERIC:
+ return new RNumericBFix64Store(io, length);
+ case RStore.COMPLEX:
+ return new RComplexBFix64Store(io, length);
+ case RStore.CHARACTER:
+ return new RCharacterFix64Store(io, length);
+ case RStore.RAW:
+ return new RRawFix64Store(io, length);
+ case RStore.FACTOR:
+ return new RFactorFix64Store(io, length);
+ default:
+ throw new IOException("store type= " + storeType);
+ }
+ }
+ }
+ else {
+ final byte storeType= io.readByte();
+ switch (storeType) {
+ case RStore.LOGICAL:
+ return LOGI_STRUCT_DUMMY;
+ case RStore.INTEGER:
+ return INT_STRUCT_DUMMY;
+ case RStore.NUMERIC:
+ return NUM_STRUCT_DUMMY;
+ case RStore.COMPLEX:
+ return CPLX_STRUCT_DUMMY;
+ case RStore.CHARACTER:
+ return CHR_STRUCT_DUMMY;
+ case RStore.RAW:
+ return RAW_STRUCT_DUMMY;
+ case RStore.FACTOR:
+ return new RFactorStructStore(io.readBoolean(), io.readInt());
+ default:
+ throw new IOException("store type= " + storeType);
+ }
+ }
+ }
+
+ @Override
+ public void writeStore(final RStore<?> data, final RJIO io) throws IOException {
+ if ((io.flags & F_ONLY_STRUCT) == 0) {
+ io.writeByte(data.getStoreType());
+ ((ExternalizableRStore) data).writeExternal(io);
+ }
+ else {
+ final byte storeType= data.getStoreType();
+ io.writeByte(storeType);
+ if (storeType == RStore.FACTOR) {
+ final RFactorStore factor= (RFactorStore) data;
+ io.writeBoolean(factor.isOrdered());
+ io.writeInt(factor.getLevelCount());
+ }
+ }
+ }
+
+ @Override
+ public RList readAttributeList(final RJIO io) throws IOException {
+ return new RList32Impl(io, this, io.readInt());
+ }
+
+ @Override
+ public void writeAttributeList(final RList list, final RJIO io) throws IOException {
+ ((ExternalizableRObject) list).writeExternal(io, this);
+ }
+
+ protected final int[] readDim(final ObjectInput in) throws IOException {
+ final int length= in.readInt();
+ final int[] dim= new int[length];
+ for (int i= 0; i < length; i++) {
+ dim[i]= in.readInt();
+ }
+ return dim;
+ }
+
+ @Override
+ public RStore<?> readNames(final RJIO io, final long length) throws IOException {
+ final byte type= io.readByte();
+ if (type == RStore.CHARACTER) {
+ return (length <= Integer.MAX_VALUE) ?
+ new RCharacter32Store(io, (int) length) :
+ new RCharacterFix64Store(io, length);
+ }
+ if (type == 0) {
+ return null;
+ }
+ throw new IOException();
+ }
+
+ @Override
+ public void writeNames(final RStore<?> names, final RJIO io) throws IOException {
+ if (names != null) {
+ final byte type= names.getStoreType();
+ if (type == RStore.CHARACTER) {
+ io.writeByte(type);
+ ((ExternalizableRStore) names).writeExternal(io);
+ return;
+ }
+ }
+ io.writeByte(0);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRObject.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRObject.java
new file mode 100644
index 0000000..917de25
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRObject.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObjectFactory;
+
+
+public interface ExternalizableRObject {
+
+
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException;
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRStore.java
new file mode 100644
index 0000000..c14ef89
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ExternalizableRStore.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public interface ExternalizableRStore {
+
+
+ void writeExternal(RJIO io) throws IOException;
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RArrayImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RArrayImpl.java
new file mode 100644
index 0000000..dd6b478
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RArrayImpl.java
@@ -0,0 +1,251 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RArrayImpl<TData extends RStore<?>> extends AbstractRObject
+ implements RArray<TData>, ExternalizableRObject {
+
+
+ private long length;
+ private TData data;
+
+ private String className1;
+ private RInteger32Store dimAttribute;
+ private SimpleRList<RStore<?>> dimnamesAttribute;
+
+
+ public RArrayImpl(final TData data, final String className1, final int[] dim) {
+ if (data == null || className1 == null || dim == null) {
+ throw new NullPointerException();
+ }
+ this.length= RDataUtils.computeLengthFromDim(dim);
+ if (data.getLength() >= 0 && data.getLength() != this.length) {
+ throw new IllegalArgumentException("dim");
+ }
+ this.className1= className1;
+ this.dimAttribute= new RInteger32Store(dim);
+ this.data= data;
+ }
+
+ public RArrayImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ //-- options
+ final int options= io.readInt();
+ //-- special attributes
+ if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+ this.className1= io.readString();
+ }
+ this.length= io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+ final int[] dim= io.readIntArray();
+ this.dimAttribute= new RInteger32Store(dim);
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ final RCharacter32Store names0= new RCharacter32Store(io, dim.length);
+ final RStore<?>[] names1= new RStore[dim.length];
+ for (int i= 0; i < dim.length; i++) {
+ names1[i]= factory.readNames(io, dim[i]);
+ }
+ this.dimnamesAttribute= new SimpleRList<>(names1, names0);
+ }
+ //-- data
+ this.data= (TData) factory.readStore(io, this.length);
+
+ if ((options & RObjectFactory.O_CLASS_NAME) == 0) {
+ this.className1= (dim.length == 2) ? RObject.CLASSNAME_MATRIX : RObject.CLASSNAME_ARRAY;
+ }
+ //-- attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ setAttributes(factory.readAttributeList(io));
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ final int n= this.dimAttribute.length();
+ //-- options
+ int options= io.getVULongGrade(this.length);
+ if (!this.className1.equals((n == 2) ?
+ RObject.CLASSNAME_MATRIX : RObject.CLASSNAME_ARRAY )) {
+ options |= RObjectFactory.O_CLASS_NAME;
+ }
+ if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.dimnamesAttribute != null) {
+ options |= RObjectFactory.O_WITH_NAMES;
+ }
+ final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+ if (attributes != null) {
+ options |= RObjectFactory.O_WITH_ATTR;
+ }
+ io.writeInt(options);
+ //-- special attributes
+ if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+ io.writeString(this.className1);
+ }
+ io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), this.length);
+ io.writeInt(n);
+ this.dimAttribute.writeExternal(io);
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ ((ExternalizableRStore) this.dimnamesAttribute.getNames()).writeExternal(io);
+ for (int i= 0; i < n; i++) {
+ factory.writeNames(this.dimnamesAttribute.get(i), io);
+ }
+ }
+ //-- data
+ factory.writeStore(this.data, io);
+ //-- attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ factory.writeAttributeList(attributes, io);
+ }
+ }
+
+
+ @Override
+ public final byte getRObjectType() {
+ return TYPE_ARRAY;
+ }
+
+ @Override
+ public String getRClassName() {
+ return this.className1;
+ }
+
+ @Override
+ public long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public RIntegerStore getDim() {
+ return this.dimAttribute;
+ }
+
+ @Override
+ public RCharacterStore getDimNames() {
+ if (this.dimnamesAttribute != null) {
+ return this.dimnamesAttribute.getNames();
+ }
+ return null;
+ }
+
+ @Override
+ public RStore<?> getNames(final int dim) {
+ if (this.dimnamesAttribute != null) {
+ return this.dimnamesAttribute.get(dim);
+ }
+ return null;
+ }
+
+
+ @Override
+ public TData getData() {
+ return this.data;
+ }
+
+
+// protected int[] getDataInsertIdxs(final int dim, final int idx) {
+// if (dim >= this.dimAttribute.length || idx >= this.dimAttribute.intValues[dim]) {
+// throw new IllegalArgumentException();
+// }
+// final int size= this.data.getLength() / this.dimAttribute.intValues[dim];
+// final int[] dataIdxs= new int[size];
+// int step= 1;
+// int stepCount= 1;
+// for (int currentDimI= 0; currentDimI < this.dimAttribute.length; currentDimI++) {
+// final int currentDimLength= this.dimAttribute.intValues[currentDimI];
+// if (currentDimI == dim) {
+// final int add= step*idx;
+// for (int i= 0; i < size; i++) {
+// dataIdxs[i]+= add;
+// }
+// }
+// else {
+// if (currentDimI > 0) {
+// int temp= 0;
+// for (int i= 0; i < size; ) {
+// final int add= step*temp;
+// for (int j= 0; j < stepCount && i < size; i++,j++) {
+// dataIdxs[i]+= add;
+// }
+// temp++;
+// if (temp == currentDimLength) {
+// temp= 0;
+// }
+// }
+// }
+// stepCount *= currentDimLength;
+// }
+// step *= currentDimLength;
+// }
+// return dataIdxs;
+// }
+//
+// public void setDim(final int[] dim) {
+// checkDim(getLength(), dim);
+// this.dimAttribute= dim;
+// }
+//
+// public void setDimNames(final List<RCharacterStore> list) {
+// }
+
+// public void insert(final int dim, final int idx) {
+// ((RDataResizeExtension) this.data).insertNA(getDataInsertIdxs(dim, idx));
+// this.dimAttribute[dim]++;
+// if (this.dimnamesAttribute != null) {
+// final RVector<RCharacterStore> names= (RVector<RCharacterStore>) this.dimnamesAttribute.get(dim);
+// if (names != null) {
+// names.insert(idx);
+// }
+// }
+// }
+//
+// public void remove(final int dim, final int idx) {
+// ((RDataResizeExtension) this.data).remove(RDataUtils.getDataIdxs(this.dimAttribute, dim, idx));
+// this.dimAttribute[dim]--;
+// if (this.dimnamesAttribute != null) {
+// final RVector<RCharacterStore> names= (RVector<RCharacterStore>) this.dimnamesAttribute.get(dim);
+// if (names != null) {
+// names.remove(idx);
+// }
+// }
+// }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RObject type=RArray, class=").append(getRClassName());
+ sb.append("\n\tlength=").append(getLength());
+ sb.append("\n\tdim=");
+ this.dimAttribute.appendTo(sb);
+ sb.append("\n\tdata: ");
+ sb.append(this.data.toString());
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacter32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacter32Store.java
new file mode 100644
index 0000000..18feeab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacter32Store.java
@@ -0,0 +1,342 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RCharacter32Store extends AbstractCharacterStore
+ implements RDataResizeExtension<String>, ExternalizableRStore, Externalizable {
+
+
+ private int length;
+
+ protected String[] charValues;
+
+
+ public RCharacter32Store() {
+ this.length= 0;
+ this.charValues= EMPTY_STRING_ARRAY;
+ }
+
+ public RCharacter32Store(final int length) {
+ this.length= length;
+ this.charValues= new String[length];
+ Arrays.fill(this.charValues, "");
+ }
+
+ public RCharacter32Store(final String[] values) {
+ this.length= values.length;
+ this.charValues= values;
+ }
+
+ public RCharacter32Store(final String[] values, final int length) {
+ this.length= length;
+ this.charValues= values;
+ }
+
+
+ RCharacter32Store(final RCharacter32Store source, final boolean reuse) {
+ String[] values;
+ if (reuse) {
+ values= source.charValues;
+ }
+ else {
+ values= ensureCapacity(this.charValues, source.length);
+ System.arraycopy(source, 0, values, 0, source.length);
+ }
+ this.charValues= values;
+ this.length= source.length;
+ }
+
+
+ public RCharacter32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.charValues= new String[length];
+ io.readStringData(this.charValues, length);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeStringData(this.charValues, this.length);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ this.length= in.readInt();
+ this.charValues= new String[this.length];
+ for (int i= 0; i < this.length; i++) {
+ final int l= in.readInt();
+ if (l >= 0) {
+ final char[] c= new char[l];
+ for (int j= 0; j < l; j++) {
+ c[j]= in.readChar();
+ }
+ this.charValues[i]= new String(c);
+ }
+// else {
+// this.charValues[i]= null;
+// }
+ }
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.length);
+ for (int i= 0; i < this.length; i++) {
+ if (this.charValues[i] != null) {
+ out.writeInt(this.charValues[i].length());
+ out.writeChars(this.charValues[i]);
+ }
+ else {
+ out.writeInt(-1);
+ }
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ public final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.charValues[idx] == null);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.charValues[(int) idx] == null);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+// if (this.charValues[idx] == null) {
+// return;
+// }
+ this.charValues[idx]= null;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+// if (this.charValues[(int) idx] == null) {
+// return;
+// }
+ this.charValues[(int) idx]= null;
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.charValues[idx] == null);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.charValues[(int) idx] == null);
+ }
+
+ @Override
+ public String getChar(final int idx) {
+ return this.charValues[idx];
+ }
+
+ @Override
+ public String getChar(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.charValues[(int) idx];
+ }
+
+ @Override
+ public void setChar(final int idx, final String value) {
+// assert (value != null);
+ this.charValues[idx]= value;
+ }
+
+ @Override
+ public void setChar(final long idx, final String value) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+// assert (value != null);
+ this.charValues[(int) idx]= value;
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.charValues= prepareInsert(this.charValues, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insertChar(final int idx, final String value) {
+// assert (value != null);
+ prepareInsert(new int[] { idx });
+ this.charValues[idx]= value;
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.charValues[idx]= null;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ if (idxs.length == 0) {
+ return;
+ }
+ prepareInsert(idxs);
+ for (int i= 0; i < idxs.length; i++) {
+ this.charValues[idxs[i]]= null;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.charValues= remove(this.charValues, this.length, new int[] { idx });
+ this.length--;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.charValues= remove(this.charValues, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public String get(final int idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.charValues[idx];
+ }
+
+ @Override
+ public String get(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.charValues[(int) idx];
+ }
+
+ @Override
+ public String[] toArray() {
+ final String[] array= new String[length()];
+ System.arraycopy(this.charValues, 0, array, 0, array.length);
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final String[] chars= this.charValues;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (chars[i] == null) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int indexOfNA(int fromIdx) {
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final String[] chars= this.charValues;
+ for (int i= fromIdx; i < l; i++) {
+ if (chars[i] == null) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final String character, long fromIdx) {
+ if (character == null
+ || fromIdx >= Integer.MAX_VALUE) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final String[] chars= this.charValues;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (chars[i] != null && chars[i].equals(character)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public int indexOf(final String character, int fromIdx) {
+ if (character == null) {
+ throw new NullPointerException();
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final String[] chars= this.charValues;
+ while (fromIdx < l) {
+ if (chars[fromIdx] != null && chars[fromIdx].equals(character)) {
+ return fromIdx;
+ }
+ fromIdx++;
+ }
+ return -1;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterFix64Store.java
new file mode 100644
index 0000000..27010a9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterFix64Store.java
@@ -0,0 +1,202 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RCharacterFix64Store extends AbstractCharacterStore
+ implements ExternalizableRStore {
+
+
+ public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+
+ protected final String[][] charValues;
+
+
+ public RCharacterFix64Store(final long length) {
+ this.length= length;
+ this.charValues= new2dStringArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.charValues.length; i++) {
+ Arrays.fill(this.charValues[i], "");
+ }
+ }
+
+ public RCharacterFix64Store(final String[][] values) {
+ this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+ this.charValues= values;
+ }
+
+
+ public RCharacterFix64Store(final RJIO io, final long length) throws IOException {
+ this.length= length;
+ this.charValues= new2dStringArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.charValues.length; i++) {
+ io.readStringData(this.charValues[i], this.charValues[i].length);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ for (int i= 0; i < this.charValues.length; i++) {
+ io.writeStringData(this.charValues[i], this.charValues[i].length);
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == null);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ return (this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == null);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= null;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= null;
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == null);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ return (this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == null);
+ }
+
+ @Override
+ public String getChar(final int idx) {
+ return this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public String getChar(final long idx) {
+ return this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public void setChar(final int idx, final String value) {
+// assert (value != null);
+ this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= value;
+ }
+
+ @Override
+ public void setChar(final long idx, final String value) {
+// assert (value != null);
+ this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= value;
+ }
+
+
+ @Override
+ public String get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.charValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public String get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.charValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public String[] toArray() {
+ final int l= checkToArrayLength();
+ final String[] array= new String[l];
+ int k= 0;
+ for (int i= 0; i < this.charValues.length; i++) {
+ final String[] chars= this.charValues[i];
+ System.arraycopy(chars, 0, array, k, chars.length);
+ k+= chars.length;
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ while (i < this.charValues.length) {
+ final String[] chars= this.charValues[i];
+ while (j < chars.length) {
+ if (chars[j] == null) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final String character, long fromIdx) {
+ if (character == null) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ while (i < this.charValues.length) {
+ final String[] chars= this.charValues[i];
+ while (j < chars.length) {
+ if (chars[j] != null && chars[j].equals(character)) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ return -1;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterStructStore.java
new file mode 100644
index 0000000..2c1df04
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RCharacterStructStore.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RCharacterStructStore extends AbstractCharacterStore {
+
+
+ public RCharacterStructStore() {
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return true;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return -1;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String get(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String get(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ return (CHARACTER == other.getStoreType()
+ && other.getLength() == -1 );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexB32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexB32Store.java
new file mode 100644
index 0000000..4f4a6e4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexB32Store.java
@@ -0,0 +1,362 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RComplexStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RComplexB32Store extends AbstractComplexStore
+ implements RDataResizeExtension<RComplexStore.Complex>, ExternalizableRStore, Externalizable {
+
+
+ private int length;
+
+ protected double[] realValues;
+ protected double[] imaginaryValues;
+
+
+ public RComplexB32Store() {
+ this.length= 0;
+ this.realValues= EMPTY_DOUBLE_ARRAY;
+ this.imaginaryValues= EMPTY_DOUBLE_ARRAY;
+ }
+
+ public RComplexB32Store(final int length) {
+ this.length= length;
+ this.realValues= new double[length];
+ this.imaginaryValues= new double[length];
+ }
+
+ protected RComplexB32Store(final double[] realValues, final double[] imaginaryValues) {
+ this.length= realValues.length;
+ this.realValues= realValues;
+ this.imaginaryValues= imaginaryValues;
+ }
+
+ public RComplexB32Store(final double[] realValues, final double[] imaginaryValues, final int[] naIdxs) {
+ if (realValues.length != imaginaryValues.length) {
+ throw new IllegalArgumentException();
+ }
+ this.length= realValues.length;
+ this.realValues= realValues;
+ this.imaginaryValues= imaginaryValues;
+ if (naIdxs != null) {
+ for (int i= 0; i < naIdxs.length; i++) {
+ this.realValues[naIdxs[i]]= NA_numeric_DOUBLE;
+ this.imaginaryValues[naIdxs[i]]= NA_numeric_DOUBLE;
+ }
+ }
+ }
+
+
+ public RComplexB32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.realValues= io.readDoubleData(new double[length], length);
+ this.imaginaryValues= io.readDoubleData(new double[length], length);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeDoubleData(this.realValues, this.length);
+ io.writeDoubleData(this.imaginaryValues, this.length);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ this.length= in.readInt();
+ this.realValues= new double[this.length];
+ this.imaginaryValues= new double[this.length];
+ for (int i= 0; i < this.length; i++) {
+ this.realValues[i]= Double.longBitsToDouble(in.readLong());
+ this.imaginaryValues[i]= Double.longBitsToDouble(in.readLong());
+ }
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.length);
+ for (int i= 0; i < this.length; i++) {
+ out.writeLong(Double.doubleToRawLongBits(this.realValues[i]));
+ out.writeLong(Double.doubleToRawLongBits(this.imaginaryValues[i]));
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ protected final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ final double v= this.realValues[idx];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[(int) idx];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.realValues[idx]= NA_numeric_DOUBLE;
+ this.imaginaryValues[idx]= NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.realValues[(int) idx]= NA_numeric_DOUBLE;
+ this.imaginaryValues[(int) idx]= NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public boolean isNaN(final int idx) {
+ final double v= this.realValues[idx];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNaN(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double value= this.realValues[(int) idx];
+ return (Double.isNaN(value)
+ && (int) Double.doubleToRawLongBits(value) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (Double.isNaN(this.realValues[idx]));
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (Double.isNaN(this.realValues[(int) idx]));
+ }
+
+ @Override
+ public double getCplxRe(final int idx) {
+ return this.realValues[idx];
+ }
+
+ @Override
+ public double getCplxRe(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.realValues[(int) idx];
+ }
+
+ @Override
+ public double getCplxIm(final int idx) {
+ return this.imaginaryValues[idx];
+ }
+
+ @Override
+ public double getCplxIm(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.imaginaryValues[(int) idx];
+ }
+
+ @Override
+ public void setCplx(final int idx, final double real, final double imaginary) {
+ if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+ this.realValues[idx]= NaN_numeric_DOUBLE;
+ this.imaginaryValues[idx]= NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[idx]= real;
+ this.imaginaryValues[idx]= imaginary;
+ }
+ }
+
+ @Override
+ public void setCplx(final long idx, final double real, final double imaginary) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+ this.realValues[(int) idx]= NaN_numeric_DOUBLE;
+ this.imaginaryValues[(int) idx]= NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[(int) idx]= real;
+ this.imaginaryValues[(int) idx]= imaginary;
+ }
+ }
+
+ @Override
+ public void setNum(final int idx, final double real) {
+ if (Double.isNaN(real)) {
+ this.realValues[idx]= NaN_numeric_DOUBLE;
+ this.imaginaryValues[idx]= NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[idx]= real;
+ this.imaginaryValues[idx]= 0.0;
+ }
+ }
+
+ @Override
+ public void setNum(final long idx, final double real) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ if (Double.isNaN(real)) {
+ this.realValues[(int) idx]= NaN_numeric_DOUBLE;
+ this.imaginaryValues[(int) idx]= NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[(int) idx]= real;
+ this.imaginaryValues[(int) idx]= 0.0;
+ }
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.realValues= prepareInsert(this.realValues, this.length, idxs);
+ this.imaginaryValues= prepareInsert(this.imaginaryValues, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insertCplx(final int idx, final double realValue, final double imaginaryValue) {
+ prepareInsert(new int[] { idx });
+ if (Double.isNaN(realValue) || Double.isNaN(imaginaryValue)) {
+ this.realValues[idx]= NaN_numeric_DOUBLE;
+ this.imaginaryValues[idx]= NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[idx]= realValue;
+ this.imaginaryValues[idx]= imaginaryValue;
+ }
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.realValues[idx]= NA_numeric_DOUBLE;
+ this.imaginaryValues[idx]= NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ if (idxs.length == 0) {
+ return;
+ }
+ prepareInsert(idxs);
+ for (int idx= 0; idx < idxs.length; idx++) {
+ this.realValues[idx]= NA_numeric_DOUBLE;
+ this.imaginaryValues[idx]= NA_numeric_DOUBLE;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.realValues= remove(this.realValues, this.length, new int[] { idx });
+ this.imaginaryValues= remove(this.imaginaryValues, this.length, new int[] { idx });
+ this.length--;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.realValues= remove(this.realValues, this.length, idxs);
+ this.imaginaryValues= remove(this.imaginaryValues, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public Complex get(final int idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[idx];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ new Complex(v, this.imaginaryValues[idx]) :
+ null;
+ }
+
+ @Override
+ public Complex get(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[(int) idx];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ new Complex(v, this.imaginaryValues[(int) idx]) :
+ null;
+ }
+
+ @Override
+ public Complex[] toArray() {
+ final double[] reals= this.realValues;
+ final double[] imgs= this.imaginaryValues;
+ final Complex[] array= new Complex[length()];
+ for (int i= 0; i < array.length; i++) {
+ final double v= reals[i];
+ if (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+ array[i]= new Complex(v, imgs[i]);
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexBFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexBFix64Store.java
new file mode 100644
index 0000000..70389e6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexBFix64Store.java
@@ -0,0 +1,272 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RComplexBFix64Store extends AbstractComplexStore
+ implements ExternalizableRStore {
+
+
+ public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+
+ protected final double[][] realValues;
+ protected final double[][] imaginaryValues;
+
+
+ public RComplexBFix64Store(final long length) {
+ this.length= length;
+ this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+ this.imaginaryValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+ }
+
+ public RComplexBFix64Store(final double[][] realValues, final double[][] imaginaryValues) {
+ this.length= check2dArrayLength(realValues, SEGMENT_LENGTH);
+ if (this.length != check2dArrayLength(imaginaryValues, SEGMENT_LENGTH)) {
+ throw new IllegalArgumentException();
+ }
+ this.realValues= realValues;
+ this.imaginaryValues= imaginaryValues;
+ }
+
+
+ public RComplexBFix64Store(final RJIO io, final long length) throws IOException {
+ this.length= length;
+ this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+ this.imaginaryValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.realValues.length; i++) {
+ io.readDoubleData(this.realValues[i], this.realValues[i].length);
+ io.readDoubleData(this.imaginaryValues[i], this.imaginaryValues[i].length);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ for (int i= 0; i < this.realValues.length; i++) {
+ io.writeDoubleData(this.realValues[i], this.realValues[i].length);
+ io.writeDoubleData(this.imaginaryValues[i], this.imaginaryValues[i].length);
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NA_numeric_DOUBLE;
+ this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NA_numeric_DOUBLE;
+ this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public boolean isNaN(final int idx) {
+ final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNaN(final long idx) {
+ final double value= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (Double.isNaN(value)
+ && (int) Double.doubleToRawLongBits(value) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (Double.isNaN(
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] ));
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ return (Double.isNaN(
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] ));
+ }
+
+ @Override
+ public double getCplxRe(final int idx) {
+ return this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public double getCplxRe(final long idx) {
+ return this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public double getCplxIm(final int idx) {
+ return this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public double getCplxIm(final long idx) {
+ return this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public void setCplx(final int idx, final double real, final double imaginary) {
+ if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NaN_numeric_DOUBLE;
+ this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ real;
+ this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ imaginary;
+ }
+ }
+
+ @Override
+ public void setCplx(final long idx, final double real, final double imaginary) {
+ if (Double.isNaN(real) || Double.isNaN(imaginary)) {
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NaN_numeric_DOUBLE;
+ this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ real;
+ this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ imaginary;
+ }
+ }
+
+ @Override
+ public void setNum(final int idx, final double real) {
+ if (Double.isNaN(real)) {
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NaN_numeric_DOUBLE;
+ this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ real;
+ this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ 0.0;
+ }
+ }
+
+ @Override
+ public void setNum(final long idx, final double real) {
+ if (Double.isNaN(real)) {
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NaN_numeric_DOUBLE;
+ this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NaN_numeric_DOUBLE;
+ }
+ else {
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ real;
+ this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ 0.0;
+ }
+ }
+
+
+ @Override
+ public Complex get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ new Complex(v, this.imaginaryValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]) :
+ null;
+ }
+
+ @Override
+ public Complex get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ new Complex(v, this.imaginaryValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]) :
+ null;
+ }
+
+ @Override
+ public Complex[] toArray() {
+ final int l= checkToArrayLength();
+ final Complex[] array= new Complex[l];
+ int k= 0;
+ for (int i= 0; i < this.realValues.length; i++, k++) {
+ final double[] reals= this.realValues[i];
+ final double[] imgs= this.imaginaryValues[i];
+ for (int j= 0; j < reals.length; j++) {
+ final double v= reals[j];
+ if (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+ array[k]= new Complex(v, imgs[i]);
+ }
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexStructStore.java
new file mode 100644
index 0000000..8f2e2ca
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RComplexStructStore.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RComplexStructStore extends AbstractComplexStore {
+
+
+ public RComplexStructStore() {
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return true;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return -1;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNaN(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNaN(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Complex get(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Complex get(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Complex[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ return (COMPLEX == other.getStoreType()
+ && -1 == other.getLength() );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrame32Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrame32Impl.java
new file mode 100644
index 0000000..7a711fd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrame32Impl.java
@@ -0,0 +1,212 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RDataFrame32Impl extends RList32Impl
+ implements RDataFrame, ExternalizableRObject {
+
+
+ private RStore<?> rownamesAttribute;
+ private long rowCount;
+
+
+ public RDataFrame32Impl(final RObject[] columns, final String className1, final String[] initialNames, final String[] initialRownames) {
+ this(columns, className1, initialNames, initialRownames, true);
+ }
+
+ protected RDataFrame32Impl(final RObject[] columns, final String className1, final String[] initialNames, final String[] initialRownames, final boolean check) {
+ super(columns, className1, initialNames);
+ if (columns.length == 0) {
+ this.rowCount= 0;
+ }
+ else {
+ this.rowCount= columns[0].getLength();
+ if (check) {
+ for (int i= 0; i < columns.length; i++) {
+ if (columns[i].getRObjectType() != RObject.TYPE_VECTOR
+ || (columns[i].getLength() != this.rowCount)) {
+ throw new IllegalArgumentException("Length of column " + i + ": " + columns[i].getLength());
+ }
+ }
+ }
+ }
+ if (initialRownames != null && initialRownames.length == this.rowCount) {
+ this.rownamesAttribute= new RUniqueCharacter32Store(initialRownames);
+ if (this.rownamesAttribute.getLength() != this.rowCount) {
+ throw new IllegalArgumentException("Length of row names: " + this.rownamesAttribute.getLength());
+ }
+ }
+ }
+
+ public RDataFrame32Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+ super(io, factory, options);
+
+ this.rowCount= io.readLong();
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ this.rownamesAttribute= factory.readNames(io, this.rowCount);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ int options= 0;
+ if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.rownamesAttribute != null) {
+ options |= RObjectFactory.O_WITH_NAMES;
+ }
+ super.doWriteExternal(io, factory, options);
+ io.writeLong(this.rowCount);
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ factory.writeNames(this.rownamesAttribute, io);
+ }
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_DATAFRAME;
+ }
+
+ @Override
+ protected String getDefaultRClassName() {
+ return RObject.CLASSNAME_DATAFRAME;
+ }
+
+
+ @Override
+ public long getColumnCount() {
+ return getLength();
+ }
+
+ @Override
+ public RCharacterStore getColumnNames() {
+ return getNames();
+ }
+
+ public String getColumnName(final int idx) {
+ return getName(idx);
+ }
+
+ @Override
+ public RStore<?> getColumn(final int idx) {
+ final RObject obj= get(idx);
+ return (obj != null) ? obj.getData() : null;
+ }
+
+ @Override
+ public RStore<?> getColumn(final long idx) {
+ final RObject obj= get(idx);
+ return (obj != null) ? obj.getData() : null;
+ }
+
+ @Override
+ public RStore<?> getColumn(final String name) {
+ final RObject obj= get(name);
+ return (obj != null) ? obj.getData() : null;
+ }
+
+// public void setColumn(final int idx, final RStore<?> column) {
+// if (this.length == 0) {
+// throw new IndexOutOfBoundsException(Long.toString(idx));
+// }
+// else {
+// if (column.getLength() != this.rowCount) {
+// throw new IllegalArgumentException();
+// }
+// }
+// this.columns[idx]= new RVectorImpl(column, RDataUtils.getStoreVectorClass(column));
+// }
+
+ @Override
+ public boolean set(final int idx, final RObject component) {
+ if (component == null) {
+ throw new NullPointerException();
+ }
+ if (getLength() == 0) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ else {
+ if (component.getRObjectType() != RObject.TYPE_VECTOR) {
+ throw new IllegalArgumentException();
+ }
+ if (component.getLength() != this.rowCount) {
+ throw new IllegalArgumentException();
+ }
+ }
+ return super.set(idx, component);
+ }
+
+// public void insertColumn(final int idx, final String name, final RStore<?> column) {
+// if (column == null) {
+// throw new NullPointerException();
+// }
+// if (column.getDataType() <= 0) {
+// throw new IllegalArgumentException();
+// }
+// if (this.length == 0) {
+// this.rowCount= column.getLength();
+// }
+// else if (this.rowCount != column.getLength()) {
+// throw new IllegalArgumentException();
+// }
+// prepareInsert(idx);
+// this.columns[idx]= new RVectorImpl(column, RDataUtils.getStoreVectorClass(column));
+// this.namesAttribute.insertChar(idx, name);
+// }
+//
+
+
+ @Override
+ public long getRowCount() {
+ return this.rowCount;
+ }
+
+ @Override
+ public RStore<?> getRowNames() {
+ return this.rownamesAttribute;
+ }
+
+ public void insertRow(final int idx) {
+ final long length= getLength();
+ for (int i= 0; i < length; i++) {
+ ((RDataResizeExtension<?>) get(i)).insertNA(idx);
+ }
+ this.rowCount++;
+// if (this.rownamesAttribute != null) {
+// ((RDataResizeExtension) this.rownamesAttribute).insertAuto(idx);
+// }
+ }
+
+ public void removeRow(final int idx) {
+ final long length= getLength();
+ for (int i= 0; i < length; i++) {
+ ((RDataResizeExtension<?>) this.get(i)).remove(idx);
+ }
+ this.rowCount--;
+// if (this.rownamesAttribute != null) {
+// this.rownamesAttribute.remove(idx);
+// }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrameFix64Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrameFix64Impl.java
new file mode 100644
index 0000000..bb4d085
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataFrameFix64Impl.java
@@ -0,0 +1,149 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RDataFrameFix64Impl extends RListFix64Impl
+ implements RDataFrame, ExternalizableRObject {
+
+
+ private final RStore<?> rownamesAttribute;
+ private final long rowCount;
+
+
+ public RDataFrameFix64Impl(final RObject[][] columns, final String className1, final String[][] initialNames, final String[][] initialRownames) {
+ this(columns, className1, initialNames, initialRownames, true);
+ }
+
+ protected RDataFrameFix64Impl(final RObject[][] columns, final String className1, final String[][] initialNames, final String[][] initialRownames, final boolean check) {
+ super(columns, className1, initialNames);
+ if (columns.length == 0) {
+ this.rowCount= 0;
+ }
+ else {
+ this.rowCount= columns[0][0].getLength();
+ if (check) {
+ for (int i= 0; i < columns.length; i++) {
+ final RObject[] segment= columns[i];
+ for (int j= 0; j < segment.length; j++) {
+ if (segment[j].getRObjectType() != RObject.TYPE_VECTOR
+ || (segment[j].getLength() != this.rowCount)) {
+ throw new IllegalArgumentException("Length of column " + (i * (long) SEGMENT_LENGTH + j) + ": " + segment[j].getLength());
+ }
+ }
+ }
+ }
+ }
+ if (initialRownames != null) {
+ this.rownamesAttribute= new RCharacterFix64Store(initialRownames);
+ if (this.rownamesAttribute.getLength() != this.rowCount) {
+ throw new IllegalArgumentException("Length of row names: " + this.rownamesAttribute.getLength());
+ }
+ }
+ else {
+ this.rownamesAttribute= null;
+ }
+ }
+
+ public RDataFrameFix64Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+ super(io, factory, options);
+
+ this.rowCount= io.readLong();
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ this.rownamesAttribute= factory.readNames(io, this.rowCount);
+ }
+ else {
+ this.rownamesAttribute= null;
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ int options= 0;
+ if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.rownamesAttribute != null) {
+ options |= RObjectFactory.O_WITH_NAMES;
+ }
+ super.doWriteExternal(io, options, factory);
+ io.writeLong(this.rowCount);
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ factory.writeNames(this.rownamesAttribute, io);
+ }
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_DATAFRAME;
+ }
+
+ @Override
+ protected String getDefaultRClassName() {
+ return RObject.CLASSNAME_DATAFRAME;
+ }
+
+
+ @Override
+ public long getColumnCount() {
+ return getLength();
+ }
+
+ @Override
+ public RCharacterStore getColumnNames() {
+ return getNames();
+ }
+
+ public String getColumnName(final int idx) {
+ return getName(idx);
+ }
+
+ @Override
+ public RStore<?> getColumn(final int idx) {
+ final RObject obj= get(idx);
+ return (obj != null) ? obj.getData() : null;
+ }
+
+ @Override
+ public RStore<?> getColumn(final long idx) {
+ final RObject obj= get(idx);
+ return (obj != null) ? obj.getData() : null;
+ }
+
+ @Override
+ public RStore<?> getColumn(final String name) {
+ final RObject obj= get(name);
+ return (obj != null) ? obj.getData() : null;
+ }
+
+
+ @Override
+ public long getRowCount() {
+ return this.rowCount;
+ }
+
+ @Override
+ public RStore<?> getRowNames() {
+ return this.rownamesAttribute;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataResizeExtension.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataResizeExtension.java
new file mode 100644
index 0000000..609a1e8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RDataResizeExtension.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public interface RDataResizeExtension<P> extends RStore<P> {
+
+ void remove(int idx);
+ void remove(int[] idxs);
+ void insertNA(int idx);
+ void insertNA(int[] idxs);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/REnvironmentImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/REnvironmentImpl.java
new file mode 100644
index 0000000..79ef42a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/REnvironmentImpl.java
@@ -0,0 +1,281 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.REnvironment;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class REnvironmentImpl extends AbstractRObject
+ implements REnvironment, ExternalizableRObject {
+
+
+ private byte specialType;
+
+ private String className1;
+
+ private String environmentName;
+ private long handle;
+
+ private int length;
+ private RObject[] components;
+
+ private RCharacter32Store namesAttribute;
+
+
+ protected REnvironmentImpl(final String name, final long handle,
+ final RObject[] initialComponents, String[] initialNames, final int length,
+ final byte specialType, final String className1) {
+ this.environmentName= name;
+ this.handle= handle;
+ this.components= initialComponents;
+ this.length= length;
+ if (initialNames == null) {
+ initialNames= new String[length];
+ }
+ this.namesAttribute= new RCharacter32Store(initialNames, length);
+ this.specialType= specialType;
+ this.className1= className1;
+ }
+
+ public REnvironmentImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ //-- options
+ final int options= io.readInt();
+ //-- special attributes
+ this.specialType= (byte) ((options >>> 24) & 0xff);
+ this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+ io.readString() : RObject.CLASSNAME_ENVIRONMENT;
+ //-- data
+ this.handle= io.readLong();
+ this.environmentName= io.readString();
+ final int l= this.length= (int) io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+
+ if ((options & RObjectFactory.O_NO_CHILDREN) != 0) {
+ this.namesAttribute= null;
+ this.components= null;
+ }
+ else {
+ this.namesAttribute= new RUniqueCharacterHash32Store(io, l);
+ this.components= new RObject[l];
+ for (int i= 0; i < l; i++) {
+ this.components[i]= factory.readObject(io);
+ }
+ }
+ //-- attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ setAttributes(factory.readAttributeList(io));
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ final int l= this.length;
+ //-- options
+ int options= io.getVULongGrade(l);
+ options|= (this.specialType << 24);
+ final boolean customClass= !this.className1.equals(RObject.CLASSNAME_ENVIRONMENT);
+ if (customClass) {
+ options |= RObjectFactory.O_CLASS_NAME;
+ }
+ final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+ if (attributes != null) {
+ options |= RObjectFactory.O_WITH_ATTR;
+ }
+ if (this.components == null) {
+ options |= RObjectFactory.O_NO_CHILDREN;
+ }
+ io.writeInt(options);
+ //-- special attributes
+ if (customClass) {
+ io.writeString(this.className1);
+ }
+
+ io.writeLong(this.handle);
+ io.writeString(this.environmentName);
+ io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+
+ if (this.components != null) {
+ this.namesAttribute.writeExternal(io);
+ //-- data
+ for (int i= 0; i < l; i++) {
+ factory.writeObject(this.components[i], io);
+ }
+ }
+ //-- attributes
+ if (attributes != null) {
+ factory.writeAttributeList(attributes, io);
+ }
+ }
+
+
+ @Override
+ public final byte getRObjectType() {
+ return TYPE_ENVIRONMENT;
+ }
+
+ @Override
+ public String getRClassName() {
+ return this.className1;
+ }
+
+
+ @Override
+ public int getSpecialType() {
+ return this.specialType;
+ }
+
+ @Override
+ public String getEnvironmentName() {
+ return this.environmentName;
+ }
+
+ @Override
+ public long getHandle() {
+ return this.handle;
+ }
+
+
+ @Override
+ public long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public RCharacterStore getNames() {
+ return this.namesAttribute;
+ }
+
+ @Override
+ public String getName(final int idx) {
+ return this.namesAttribute.getChar(idx);
+ }
+
+ @Override
+ public String getName(final long idx) {
+ return this.namesAttribute.getChar(idx);
+ }
+
+ @Override
+ public RObject get(final int idx) {
+ return this.components[idx];
+ }
+
+ @Override
+ public RObject get(final long idx) {
+ if (idx < 0 || idx >= Integer.MAX_VALUE) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.components[(int) idx];
+ }
+
+ @Override
+ public RObject get(final String name) {
+ final int idx= this.namesAttribute.indexOf(name, 0);
+ if (idx >= 0) {
+ return this.components[idx];
+ }
+ return null;
+ }
+
+ public RObject[] toArray() {
+ final RObject[] array= new RObject[this.length];
+ System.arraycopy(this.components, 0, array, 0, this.length);
+ return array;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+ public boolean set(final int idx, final RObject component) {
+ this.components[idx]= component;
+ return true;
+ }
+
+ public boolean set(final String name, final RObject component) {
+ if (component == null) {
+ throw new NullPointerException();
+ }
+ final int idx= this.namesAttribute.indexOf(name, 0);
+ if (idx >= 0) {
+ this.components[idx]= component;
+ return true;
+ }
+ return false;
+ }
+
+ public void insert(final int idx, final String name, final RObject component) {
+ if (component == null) {
+ throw new NullPointerException();
+ }
+ final int[] idxs= new int[] { idx };
+ this.components= prepareInsert(this.components, this.length, idxs);
+ this.length++;
+ if (name == null) {
+ this.namesAttribute.insertNA(idxs);
+ }
+ else {
+ this.namesAttribute.insertChar(idx, name);
+ }
+ }
+
+ public void add(final String name, final RObject component) {
+ insert(this.length, name, component);
+ }
+
+ public void remove(final int idx) {
+ final int[] idxs= new int[] { idx };
+ this.components= remove(this.components, this.length, idxs);
+ this.length--;
+ this.namesAttribute.remove(idxs);
+ }
+
+
+ public boolean containsName(final String name) {
+ return (this.namesAttribute.indexOf(name) >= 0);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RObject type=REnvironment, class=").append(getRClassName());
+ sb.append("\n\tlength=").append(this.length);
+ if (this.components != null) {
+ sb.append("\n\tdata: ");
+ for (int i= 0; i < this.length; i++) {
+ sb.append("\n$").append(this.namesAttribute.getChar(i)).append("\n");
+ sb.append(this.components[i]);
+ }
+ }
+ else {
+ sb.append("\n<NODATA/>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactor32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactor32Store.java
new file mode 100644
index 0000000..b0ebb08
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactor32Store.java
@@ -0,0 +1,421 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RFactor32Store extends AbstractFactorStore
+ implements RDataResizeExtension<Integer>, ExternalizableRStore, Externalizable {
+
+
+ private int length;
+
+ protected int[] codes;
+
+ protected RCharacter32Store codeLabels;
+
+
+ public RFactor32Store(final int length, final boolean isOrdered, final String[] levelLabels) {
+ if (levelLabels == null) {
+ throw new NullPointerException();
+ }
+ this.length= length;
+ this.isOrdered= isOrdered;
+ this.codes= new int[length];
+ Arrays.fill(this.codes, NA_integer_INT);
+ this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+ }
+
+ public RFactor32Store(final int[] codes, final boolean isOrdered, final String[] levelLabels) {
+ if (codes == null || levelLabels == null) {
+ throw new NullPointerException();
+ }
+ this.length= codes.length;
+ this.isOrdered= isOrdered;
+ this.codes= codes;
+ this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+ }
+
+
+ public RFactor32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.isOrdered= io.readBoolean();
+ this.codes= io.readIntData(new int[length], length);
+ this.codeLabels= readLabels(io, io.readInt());
+ }
+ protected RCharacter32Store readLabels(final RJIO io, final int l) throws IOException {
+ return new RUniqueCharacter32Store(io, l);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeBoolean(this.isOrdered);
+ io.writeIntData(this.codes, this.length);
+ io.writeInt(this.codeLabels.length());
+ this.codeLabels.writeExternal(io);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ this.isOrdered= in.readBoolean();
+ this.length= in.readInt();
+ this.codes= new int[this.length];
+ for (int i= 0; i < this.length; i++) {
+ this.codes[i]= in.readInt();
+ }
+ this.codeLabels= new RUniqueCharacter32Store();
+ this.codeLabels.readExternal(in);
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeBoolean(this.isOrdered);
+ out.writeInt(this.length);
+ for (int i= 0; i < this.length; i++) {
+ out.writeInt(this.codes[i]);
+ }
+ this.codeLabels.writeExternal(out);
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ protected final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.codes[idx] <= 0);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.codes[(int) idx] <= 0);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.codes[idx]= NA_integer_INT;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.codes[(int) idx]= NA_integer_INT;
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.codes[idx] <= 0);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.codes[(int) idx] <= 0);
+ }
+
+ @Override
+ public int getInt(final int idx) {
+ return this.codes[idx];
+ }
+
+ @Override
+ public int getInt(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.codes[(int) idx];
+ }
+
+ @Override
+ public void setInt(final int idx, final int code) {
+ if (code <= 0 || code > this.codeLabels.length()) {
+ throw new IllegalArgumentException();
+ }
+ this.codes[idx]= code;
+ }
+
+ @Override
+ public void setInt(final long idx, final int code) {
+ if (code <= 0 || code > this.codeLabels.length()) {
+ throw new IllegalArgumentException();
+ }
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.codes[(int) idx]= code;
+ }
+
+ @Override
+ public String getChar(final int idx) {
+ final int code= this.codes[idx];
+ return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+ }
+
+ @Override
+ public String getChar(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int code= this.codes[(int) idx];
+ return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+ }
+
+ @Override
+ public void setChar(final int idx, final String data) {
+ final int code= this.codeLabels.indexOf(data, 0) + 1;
+ if (code <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.codes[idx]= code;
+ }
+
+ @Override
+ public void setChar(final long idx, final String data) {
+ final int code= this.codeLabels.indexOf(data, 0) + 1;
+ if (code <= 0) {
+ throw new IllegalArgumentException();
+ }
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.codes[(int) idx]= code;
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.codes= prepareInsert(this.codes, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insertChar(final int idx, final String data) {
+ final int code= this.codeLabels.indexOf(data, 0) + 1;
+ if (code <= 0) {
+ throw new IllegalArgumentException();
+ }
+ prepareInsert(new int[] { idx });
+ this.codes[idx]= code;
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.codes[idx]= NA_integer_INT;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ prepareInsert(idxs);
+ for (int idx= 0; idx < idxs.length; idx++) {
+ this.codes[idx]= NA_integer_INT;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.codes= remove(this.codes, this.length, new int[] { idx });
+ this.length--;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.codes= remove(this.codes, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public RCharacterStore getLevels() {
+ return this.codeLabels;
+ }
+
+ @Override
+ public int getLevelCount() {
+ return this.codeLabels.length();
+ }
+
+ public void addLevel(final String label) {
+ insertLevel(this.codes.length, label);
+ }
+
+ public void insertLevel(final int position, final String label) {
+ this.codeLabels.insertChar(position, label);
+ if (position < this.codeLabels.getLength()-1) {
+ final int length= length();
+ for (int i= 0; i < length; i++) {
+ if (this.codes[i] >= position) {
+ this.codes[i]++;
+ }
+ }
+ }
+ }
+
+ public void renameLevel(final String oldLabel, final String newLabel) {
+ final int code= this.codeLabels.indexOf(oldLabel, 0) + 1;
+ if (code <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.codeLabels.setChar(code - 1, newLabel);
+ }
+
+ public void removeLevel(final String label) {
+ final int code= this.codeLabels.indexOf(label, 0) + 1;
+ if (code <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.codeLabels.remove(code - 1);
+ final int length= length();
+ for (int i= 0; i < length; i++) {
+ if (this.codes[i] == code) {
+ this.codes[i]= NA_integer_INT;
+ }
+ else if (this.codes[i] > code) {
+ this.codes[i]--;
+ }
+ }
+ }
+
+ @Override
+ public RCharacterStore toCharacterData() {
+ final String[] data= new String[length()];
+ final int[] ints= this.codes;
+ for (int i= 0; i < data.length; i++) {
+ final int code= ints[i];
+ if (code > 0) {
+ data[i]= this.codeLabels.getChar(this.codes[i] - 1);
+ }
+ }
+ return new RCharacter32Store(data);
+ }
+
+
+ @Override
+ public Integer get(final int idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int code= this.codes[idx];
+ return (code > 0) ?
+ Integer.valueOf(code) :
+ null;
+ }
+
+ @Override
+ public Integer get(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int code= this.codes[(int) idx];
+ return (code > 0) ?
+ Integer.valueOf(code) :
+ null;
+ }
+
+ @Override
+ public Integer[] toArray() {
+ final Integer[] array= new Integer[length()];
+ final int[] ints= this.codes;
+ for (int i= 0; i < array.length; i++) {
+ final int code= ints[i];
+ if (code > 0) {
+ array[i]= Integer.valueOf(code);
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final int[] ints= this.codes;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (ints[i] == NA_integer_INT) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final int code, long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE
+ || code <= 0 || code > this.codeLabels.length()) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final int[] ints= this.codes;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (ints[i] == code) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ final int code= ((character != null) ?
+ this.codeLabels.indexOf(character, 0) :
+ this.codeLabels.indexOfNA(0) ) + 1;
+ return indexOf(code, fromIdx);
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorFix64Store.java
new file mode 100644
index 0000000..74302a6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorFix64Store.java
@@ -0,0 +1,303 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RFactorFix64Store extends AbstractFactorStore
+ implements ExternalizableRStore {
+
+
+ public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+
+ protected final int[][] codes;
+
+ protected final RCharacter32Store codeLabels;
+
+
+ public RFactorFix64Store(final long length, final boolean isOrdered, final String[] levelLabels) {
+ this.length= length;
+ this.isOrdered= isOrdered;
+ this.codes= new2dIntArray(length, SEGMENT_LENGTH);
+ Arrays.fill(this.codes, NA_integer_INT);
+ this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+ }
+
+ public RFactorFix64Store(final int[][] codes, final boolean isOrdered, final String[] levelLabels) {
+ this.length= check2dArrayLength(codes, SEGMENT_LENGTH);
+ this.isOrdered= isOrdered;
+ this.codes= codes;
+ this.codeLabels= new RUniqueCharacter32Store(levelLabels);
+ }
+
+
+ public RFactorFix64Store(final RJIO io, final long length) throws IOException {
+ this.length= length;
+ this.isOrdered= io.readBoolean();
+ this.codes= new2dIntArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.codes.length; i++) {
+ io.readIntData(this.codes[i], this.codes[i].length);
+ }
+ this.codeLabels= readLabels(io, io.readInt());
+ }
+ protected RCharacter32Store readLabels(final RJIO io, final int l) throws IOException {
+ return new RUniqueCharacter32Store(io, l);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeBoolean(this.isOrdered);
+ for (int i= 0; i < this.codes.length; i++) {
+ io.writeIntData(this.codes[i], this.codes[i].length);
+ }
+ io.writeInt(this.codeLabels.length());
+ this.codeLabels.writeExternal(io);
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] <= 0);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ return (this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] <= 0);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NA_integer_INT;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NA_integer_INT;
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] <= 0);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ return (this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] <= 0);
+ }
+
+ @Override
+ public int getInt(final int idx) {
+ return this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public int getInt(final long idx) {
+ return this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public void setInt(final int idx, final int code) {
+ if (code <= 0 || code > this.codeLabels.length()) {
+ throw new IllegalArgumentException();
+ }
+ this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= code;
+ }
+
+ @Override
+ public void setInt(final long idx, final int code) {
+ if (code <= 0 || code > this.codeLabels.length()) {
+ throw new IllegalArgumentException();
+ }
+ this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= code;
+ }
+
+ @Override
+ public String getChar(final int idx) {
+ final int code= this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+ }
+
+ @Override
+ public String getChar(final long idx) {
+ final int code= this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (code > 0) ? this.codeLabels.getChar(code - 1): null;
+ }
+
+ @Override
+ public void setChar(final int idx, final String data) {
+ final int code= this.codeLabels.indexOf(data, 0) + 1;
+ if (code <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]= code;
+ }
+
+ @Override
+ public void setChar(final long idx, final String data) {
+ final int code= this.codeLabels.indexOf(data, 0) + 1;
+ if (code <= 0) {
+ throw new IllegalArgumentException();
+ }
+ this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]= code;
+ }
+
+
+ @Override
+ public RCharacterStore getLevels() {
+ return this.codeLabels;
+ }
+
+ @Override
+ public int getLevelCount() {
+ return this.codeLabels.length();
+ }
+
+ @Override
+ public RCharacterStore toCharacterData() {
+ final String[][] data= new2dStringArray(this.length, SEGMENT_LENGTH);
+ for (int i= 0; i < data.length; i++) {
+ final String[] chars= data[i];
+ final int[] ints= this.codes[i];
+ for (int j= 0; j < ints.length; j++) {
+ final int code= ints[j];
+ if (code > 0) {
+ chars[j]= this.codeLabels.getChar(code - 1);
+ }
+ }
+ }
+ return new RCharacterFix64Store(data);
+ }
+
+
+ @Override
+ public Integer get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int code= this.codes[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (code > 0) ?
+ Integer.valueOf(code) :
+ null;
+ }
+
+ @Override
+ public Integer get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int code= this.codes[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (code > 0) ?
+ Integer.valueOf(code) :
+ null;
+ }
+
+ @Override
+ public Integer[] toArray() {
+ final int l= checkToArrayLength();
+ final Integer[] array= new Integer[l];
+ int k= 0;
+ for (int i= 0; i < this.codes.length; i++, k++) {
+ final int[] ints= this.codes[i];
+ for (int j= 0; j < ints.length; j++) {
+ final int code= ints[j];
+ if (code > 0) {
+ array[k]= Integer.valueOf(code);
+ }
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ while (i < this.codes.length) {
+ final int[] ints= this.codes[i];
+ while (j < ints.length) {
+ if (ints[i] == NA_integer_INT) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final int code, long fromIdx) {
+ if (code <= 0 || code > this.codeLabels.length()) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ while (i < this.codes.length) {
+ final int[] ints= this.codes[i];
+ while (j < ints.length) {
+ if (ints[i] == code) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ final int code= ((character != null) ?
+ this.codeLabels.indexOf(character, 0) :
+ this.codeLabels.indexOfNA(0) ) + 1;
+ return indexOf(code, fromIdx);
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorStructStore.java
new file mode 100644
index 0000000..43e79ee
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFactorStructStore.java
@@ -0,0 +1,146 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RFactorStore;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RFactorStructStore extends AbstractFactorStore {
+
+
+ public static RFactorStructStore addLevels(final RFactorStore store, final RCharacterStore levels) {
+ final long levelCount= levels.getLength();
+ if (levelCount > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException("levelCount > 2^31-1");
+ }
+ return new RFactorStructStore(store.isOrdered(), (int) levels.getLength()) {
+ @Override
+ public RCharacterStore getLevels() {
+ return levels;
+ }
+ };
+ }
+
+
+ private final int levelCount;
+
+
+ public RFactorStructStore(final boolean isOrdered, final int levelCount) {
+ this.isOrdered= isOrdered;
+ this.levelCount= levelCount;
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return true;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return -1;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final int getLevelCount() {
+ return this.levelCount;
+ }
+
+ @Override
+ public RCharacterStore getLevels() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void insertLevel(final int position, final String label) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeLevel(final String label) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void renameLevel(final String oldLabel, final String newLabel) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RCharacterStore toCharacterData() {
+ return new RCharacterStructStore();
+ }
+
+ @Override
+ public Integer get(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Integer get(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final Integer[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ return (FACTOR == other.getStoreType()
+ && this.isOrdered == ((RFactorStore) other).isOrdered()
+ && this.levelCount == ((RFactorStore) other).getLevelCount()
+ && -1 == other.getLength() );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFunctionImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFunctionImpl.java
new file mode 100644
index 0000000..c06e140
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RFunctionImpl.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RFunction;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RFunctionImpl extends AbstractRObject
+ implements RFunction, ExternalizableRObject {
+
+
+ private String headerSource;
+ private String bodySource;
+
+
+ public RFunctionImpl(final String header) {
+ this.headerSource= header;
+ }
+
+ public RFunctionImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ /*final int options =*/ io.readInt();
+ this.headerSource= io.readString();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ io.writeInt(/*options*/ 0);
+ io.writeString(this.headerSource);
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_FUNCTION;
+ }
+
+ @Override
+ public String getRClassName() {
+ return "function";
+ }
+
+
+ @Override
+ public long getLength() {
+ return 0;
+ }
+
+ @Override
+ public String getHeaderSource() {
+ return this.headerSource;
+ }
+
+ @Override
+ public String getBodySource() {
+ return this.bodySource;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RInteger32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RInteger32Store.java
new file mode 100644
index 0000000..054bb79
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RInteger32Store.java
@@ -0,0 +1,306 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RInteger32Store extends AbstractIntegerStore
+ implements RDataResizeExtension<Integer>, ExternalizableRStore, Externalizable {
+
+
+ private int length;
+
+ protected int[] intValues;
+
+
+ public RInteger32Store() {
+ this.length= 0;
+ this.intValues= EMPTY_INT_ARRAY;
+ }
+
+ public RInteger32Store(final int length) {
+ this.intValues= new int[length];
+ this.length= length;
+ }
+
+ public RInteger32Store(final int[] values) {
+ this.length= values.length;
+ this.intValues= values;
+ }
+
+ public RInteger32Store(final int[] values, final int length) {
+ this.length= length;
+ this.intValues= values;
+ }
+
+ public RInteger32Store(final int[] values, final int[] naIdxs) {
+ this.length= values.length;
+ this.intValues= values;
+ if (naIdxs != null) {
+ for (int i= 0; i < naIdxs.length; i++) {
+ this.intValues[naIdxs[i]]= NA_integer_INT;
+ }
+ }
+ }
+
+
+ public RInteger32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.intValues= io.readIntData(new int[length], length);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeIntData(this.intValues, this.length);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ this.length= in.readInt();
+ this.intValues= new int[this.length];
+ for (int i= 0; i < this.length; i++) {
+ this.intValues[i]= in.readInt();
+ }
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.length);
+ for (int i= 0; i < this.length; i++) {
+ out.writeInt(this.intValues[i]);
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ protected final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.intValues[idx] == NA_integer_INT);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.intValues[(int) idx] == NA_integer_INT);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.intValues[idx]= NA_integer_INT;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.intValues[(int) idx]= NA_integer_INT;
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.intValues[idx] == NA_integer_INT);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.intValues[(int) idx] == NA_integer_INT);
+ }
+
+ @Override
+ public int getInt(final int idx) {
+ return this.intValues[idx];
+ }
+
+ @Override
+ public int getInt(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.intValues[(int) idx];
+ }
+
+ @Override
+ public void setInt(final int idx, final int value) {
+// assert (value != NA_integer_INT);
+ this.intValues[idx]= value;
+ }
+
+ @Override
+ public void setInt(final long idx, final int value) {
+// assert (value != NA_integer_INT);
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.intValues[(int) idx]= value;
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.intValues= prepareInsert(this.intValues, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insertInt(final int idx, final int value) {
+// assert (value != NA_integer_INT);
+ prepareInsert(new int[] { idx });
+ this.intValues[idx]= value;
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.intValues[idx]= NA_integer_INT;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ if (idxs.length == 0) {
+ return;
+ }
+ prepareInsert(idxs);
+ for (int idx= 0; idx < idxs.length; idx++) {
+ this.intValues[idxs[idx]+idx]= NA_integer_INT;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.intValues= remove(this.intValues, this.length, new int[] { idx });
+ this.length --;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.intValues= remove(this.intValues, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public Integer get(final int idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int v= this.intValues[idx];
+ return (v != NA_integer_INT) ?
+ Integer.valueOf(v) : null;
+ }
+
+ @Override
+ public Integer get(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int v= this.intValues[(int) idx];
+ return (v != NA_integer_INT) ?
+ Integer.valueOf(v) : null;
+ }
+
+ @Override
+ public Integer[] toArray() {
+ final Integer[] array= new Integer[length()];
+ final int[] ints= this.intValues;
+ for (int i= 0; i < array.length; i++) {
+ final int v= ints[i];
+ if (v != NA_integer_INT) {
+ array[i]= Integer.valueOf(v);
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public final long indexOfNA(long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final int[] ints= this.intValues;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (ints[i] == NA_integer_INT) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public final long indexOf(final int integer, long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE
+ || integer == NA_integer_INT ) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final int[] ints= this.intValues;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (ints[i] == integer) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ public void appendTo(final StringBuilder sb) {
+ sb.append('[');
+ final int l= length();
+ if (l > 0) {
+ final int[] ints= this.intValues;
+ for (int i= 0; i < l; i++) {
+ sb.append(ints[i]);
+ sb.append(", ");
+ }
+ sb.delete(sb.length()-2, sb.length());
+ }
+ sb.append(']');
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerFix64Store.java
new file mode 100644
index 0000000..9339939
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerFix64Store.java
@@ -0,0 +1,212 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RIntegerFix64Store extends AbstractIntegerStore
+ implements ExternalizableRStore {
+
+
+ public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+
+ protected final int[][] intValues;
+
+
+ public RIntegerFix64Store(final long length) {
+ this.length= length;
+ this.intValues= new2dIntArray(length, SEGMENT_LENGTH);
+ }
+
+ public RIntegerFix64Store(final int[][] values) {
+ this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+ this.intValues= values;
+ }
+
+
+ public RIntegerFix64Store(final RJIO io, final long length) throws IOException {
+ this.length= length;
+ this.intValues= new2dIntArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.intValues.length; i++) {
+ io.readIntData(this.intValues[i], this.intValues[i].length);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ for (int i= 0; i < this.intValues.length; i++) {
+ io.writeIntData(this.intValues[i], this.intValues[i].length);
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_integer_INT);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ return (this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_integer_INT);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NA_integer_INT;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NA_integer_INT;
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_integer_INT);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ return (this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_integer_INT);
+ }
+
+ @Override
+ public int getInt(final int idx) {
+ return this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public int getInt(final long idx) {
+ return this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public void setInt(final int idx, final int value) {
+// assert (value != NA_integer_INT);
+ this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ value;
+ }
+
+ @Override
+ public void setInt(final long idx, final int value) {
+// assert (value != NA_integer_INT);
+ this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ value;
+ }
+
+
+ @Override
+ public Integer get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int v= this.intValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (v != NA_integer_INT) ?
+ Integer.valueOf(v) :
+ null;
+ }
+
+ @Override
+ public Integer get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final int v= this.intValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (v != NA_integer_INT) ?
+ Integer.valueOf(v) :
+ null;
+ }
+
+ @Override
+ public Integer[] toArray() {
+ final int l= checkToArrayLength();
+ final Integer[] array= new Integer[l];
+ int k= 0;
+ for (int i= 0; i < this.intValues.length; i++, k++) {
+ final int[] ints= this.intValues[i];
+ for (int j= 0; j < ints.length; j++) {
+ final int v= ints[j];
+ if (v != NA_integer_INT) {
+ array[k]= Integer.valueOf(v);
+ }
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ while (i < this.intValues.length) {
+ final int[] ints= this.intValues[i];
+ while (j < ints.length) {
+ if (ints[i] == NA_integer_INT) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ return -1;
+ }
+
+ @Override
+ public final long indexOf(final int integer, long fromIdx) {
+ if (integer == NA_integer_INT ) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ while (i < this.intValues.length) {
+ final int[] ints= this.intValues[i];
+ while (j < ints.length) {
+ if (ints[i] == integer) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ return -1;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerStructStore.java
new file mode 100644
index 0000000..8fad89c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RIntegerStructStore.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RIntegerStructStore extends AbstractIntegerStore {
+
+
+ public RIntegerStructStore() {
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return true;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return -1;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Integer get(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Integer get(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final Integer[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ return (INTEGER == other.getStoreType()
+ && -1 == other.getLength() );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLanguageImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLanguageImpl.java
new file mode 100644
index 0000000..041887c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLanguageImpl.java
@@ -0,0 +1,146 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RLanguageImpl extends AbstractRObject
+ implements RLanguage, ExternalizableRObject {
+
+
+ public static final String getBaseClassname(final byte type) {
+ switch (type) {
+ case NAME:
+ return CLASSNAME_NAME;
+ case CALL:
+ return CLASSNAME_CALL;
+ default:
+ return CLASSNAME_EXPRESSION;
+ }
+ }
+
+
+ private byte type;
+
+ private String className1;
+
+ private String source;
+
+
+ public RLanguageImpl(final byte type, final String source, final String className1) {
+ this.type= type;
+ this.className1= (className1 != null) ? className1 : getBaseClassname(type);
+ this.source= source;
+ }
+
+ public RLanguageImpl(final byte type, final String className1) {
+ this.type= type;
+ this.className1= (className1 != null) ? className1 : getBaseClassname(type);
+ }
+
+ public RLanguageImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ //-- options
+ final int options= io.readInt();
+ //-- special attributes
+ this.type= io.readByte();
+ this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+ io.readString() :
+ getBaseClassname(this.type);
+ //-- data
+ if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0) {
+ this.source= io.readString();
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ int options= 0;
+ if (!this.className1.equals(getBaseClassname(this.type))) {
+ options |= RObjectFactory.O_CLASS_NAME;
+ }
+ io.writeInt(options);
+ io.writeByte(this.type);
+ //-- special attributes
+ if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+ io.writeString(this.className1);
+ }
+ //-- data
+ if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0) {
+ io.writeString(this.source);
+ }
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_LANGUAGE;
+ }
+
+ @Override
+ public byte getLanguageType() {
+ return this.type;
+ }
+
+ @Override
+ public String getRClassName() {
+ return this.className1;
+ }
+
+
+ @Override
+ public long getLength() {
+ return 0;
+ }
+
+ @Override
+ public String getSource() {
+ return this.source;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RObject type=RLanguage, class=").append(getRClassName());
+ if (this.source != null) {
+ sb.append("\n\tsource: ");
+ final int idx= this.source.indexOf('\n');
+ if (idx >= 0) {
+ sb.append(this.source.substring(0, idx));
+ sb.append(" ...");
+ }
+ else {
+ sb.append(this.source);
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RList32Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RList32Impl.java
new file mode 100644
index 0000000..8acb469
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RList32Impl.java
@@ -0,0 +1,285 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RList32Impl extends AbstractRObject
+ implements RList, ExternalizableRObject {
+
+
+ private int length;
+ private RObject[] components; // null of RObject.F_NOCHILDREN
+
+ private String className1;
+ private RCharacter32Store namesAttribute;
+
+
+ public RList32Impl(final RObject[] initialComponents, final String[] initialNames) {
+ this(initialComponents, RObject.CLASSNAME_LIST, initialNames, initialComponents.length);
+ }
+
+ public RList32Impl(final RObject[] initialComponents, final String className1, final String[] initialNames) {
+ this(initialComponents, className1, initialNames, initialComponents.length);
+ }
+
+ public RList32Impl(final RObject[] initialComponents, final String className1, String[] initialNames, final int length) {
+ this.length= length;
+ this.components= initialComponents;
+ this.className1= className1;
+ if (initialNames == null && initialComponents != null) {
+ initialNames= new String[length];
+ }
+ this.namesAttribute= (initialNames != null) ? createNamesStore(initialNames) : null;
+ }
+
+ protected RCharacter32Store createNamesStore(final String[] names) {
+ return new RCharacter32Store(names, this.length);
+ }
+
+ public RList32Impl(final RObject[] initialComponents, final RCharacter32Store initialNames) {
+ this.components= initialComponents;
+ this.length= this.components.length;
+ this.namesAttribute= initialNames;
+ }
+
+ public RList32Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+ //-- special attributes
+ this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+ io.readString() : ((getRObjectType() == RObject.TYPE_DATAFRAME) ?
+ RObject.CLASSNAME_DATAFRAME : RObject.CLASSNAME_LIST);
+ final int l= this.length= checkShortLength(
+ io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK)) );
+
+ if ((options & RObjectFactory.O_NO_CHILDREN) != 0) {
+ this.namesAttribute= null;
+ this.components= null;
+ }
+ else {
+ this.namesAttribute= (RCharacter32Store) factory.readNames(io, l);
+ //-- data
+ this.components= new RObject[l];
+ for (int i= 0; i < l; i++) {
+ this.components[i]= factory.readObject(io);
+ }
+ }
+ //-- attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ setAttributes(factory.readAttributeList(io));
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ doWriteExternal(io, factory, 0);
+ }
+ protected final void doWriteExternal(final RJIO io, final RObjectFactory factory, int options) throws IOException {
+ final int l= this.length;
+ //-- options
+ options |= io.getVULongGrade(l);
+ if (!this.className1.equals(getDefaultRClassName())) {
+ options |= RObjectFactory.O_CLASS_NAME;
+ }
+ final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+ if (attributes != null) {
+ options |= RObjectFactory.O_WITH_ATTR;
+ }
+ if (this.components == null) {
+ options |= RObjectFactory.O_NO_CHILDREN;
+ }
+ io.writeInt(options);
+ //-- special attributes
+ if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+ io.writeString(this.className1);
+ }
+ io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+
+ if ((options & RObjectFactory.O_NO_CHILDREN) == 0) {
+ factory.writeNames(this.namesAttribute, io);
+ //-- data
+ for (int i= 0; i < l; i++) {
+ factory.writeObject(this.components[i], io);
+ }
+ }
+ //-- attributes
+ if (attributes != null) {
+ factory.writeAttributeList(attributes, io);
+ }
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_LIST;
+ }
+
+ protected String getDefaultRClassName() {
+ return RObject.CLASSNAME_LIST;
+ }
+
+ @Override
+ public final String getRClassName() {
+ return this.className1;
+ }
+
+
+ protected int length() {
+ return this.length;
+ }
+
+ @Override
+ public long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public final RCharacterStore getNames() {
+ return this.namesAttribute;
+ }
+
+ @Override
+ public final String getName(final int idx) {
+ if (this.namesAttribute != null) {
+ return this.namesAttribute.getChar(idx);
+ }
+ return null;
+ }
+
+ @Override
+ public final String getName(final long idx) {
+ if (this.namesAttribute != null) {
+ return this.namesAttribute.getChar(idx);
+ }
+ return null;
+ }
+
+ @Override
+ public final RObject get(final int idx) {
+ return this.components[idx];
+ }
+
+ @Override
+ public final RObject get(final long idx) {
+ if (idx < 0 || idx >= Integer.MAX_VALUE) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.components[(int) idx];
+ }
+
+ @Override
+ public final RObject get(final String name) {
+ if (this.namesAttribute != null) {
+ final int idx= this.namesAttribute.indexOf(name, 0);
+ if (idx >= 0) {
+ return this.components[idx];
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public final RStore<?> getData() {
+ return null;
+ }
+
+
+ public boolean set(final int idx, final RObject component) {
+ this.components[idx]= component;
+ return true;
+ }
+
+// public boolean set(final long idx, final RObject component) {
+// if (idx < 0 || idx >= Integer.MAX_VALUE) {
+// throw new IndexOutOfBoundsException(Long.toString(idx));
+// }
+// this.components[(int) idx]= component;
+// return true;
+// }
+
+ public final boolean set(final String name, final RObject component) {
+ if (component == null) {
+ throw new NullPointerException();
+ }
+ final int idx= this.namesAttribute.indexOf(name, 0);
+ if (idx >= 0) {
+ set(idx, component);
+ return true;
+ }
+ return false;
+ }
+
+ public void insert(final int idx, final String name, final RObject component) {
+ if (component == null) {
+ throw new NullPointerException();
+ }
+ final int[] idxs= new int[] { idx };
+ this.components= prepareInsert(this.components, this.length, idxs);
+ this.length++;
+ if (name == null) {
+ this.namesAttribute.insertNA(idxs);
+ }
+ else {
+ this.namesAttribute.insertChar(idx, name);
+ }
+ }
+
+ public void add(final String name, final RObject component) {
+ insert(this.length, name, component);
+ }
+
+ public void remove(final int idx) {
+ final int[] idxs= new int[] { idx };
+ this.components= remove(this.components, this.length, idxs);
+ this.length--;
+ this.namesAttribute.remove(idxs);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RObject type=RList, class=").append(getRClassName());
+ sb.append("\n\tlength=").append(this.length);
+ if (this.components != null) {
+ sb.append("\n\tdata: ");
+ for (int i= 0; i < this.length; i++) {
+ if (i > 100) {
+ sb.append("\n... ");
+ break;
+ }
+ if (this.namesAttribute == null || this.namesAttribute.isNA(i)) {
+ sb.append("\n[[").append((i + 1)).append("]]\n");
+ }
+ else {
+ sb.append("\n$").append(this.namesAttribute.getChar(i)).append("\n");
+ }
+ sb.append(this.components[i]);
+ }
+ }
+ else {
+ sb.append("\n<NODATA/>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RListFix64Impl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RListFix64Impl.java
new file mode 100644
index 0000000..cd0affc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RListFix64Impl.java
@@ -0,0 +1,239 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RListFix64Impl extends AbstractRObject
+ implements RList, ExternalizableRObject {
+
+
+ public static final int SEGMENT_LENGTH= AbstractRStore.DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+ private final RObject[][] components; // null of RObject.F_NOCHILDREN
+
+ private final String className1;
+ private final RCharacterStore namesAttribute;
+
+
+ public RListFix64Impl(final RObject[][] initialComponents, final String[][] initialNames) {
+ this(initialComponents, RObject.CLASSNAME_LIST, initialNames);
+ }
+
+ public RListFix64Impl(final RObject[][] initialComponents, final String className1, final String[][] initialNames) {
+ this.length= check2dArrayLength(initialComponents, SEGMENT_LENGTH);
+ this.components= initialComponents;
+ this.className1= className1;
+ if (initialNames != null) {
+ this.namesAttribute= new RCharacterFix64Store(initialNames);
+ if (this.namesAttribute.getLength() != this.length) {
+ throw new IllegalArgumentException("Different length of components and names.");
+ }
+ }
+ else {
+ this.namesAttribute= null;
+ }
+ }
+
+ public RListFix64Impl(final RObject[][] initialComponents, final RCharacter32Store initialNames) {
+ this.components= initialComponents;
+ this.length= this.components.length;
+ this.className1= RObject.CLASSNAME_LIST;
+ this.namesAttribute= initialNames;
+ }
+
+ public RListFix64Impl(final long length, final String className1) {
+ this.length= length;
+ this.className1= className1;
+ this.components= null;
+ this.namesAttribute= null;
+ }
+
+ public RListFix64Impl(final RJIO io, final RObjectFactory factory, final int options) throws IOException {
+ //-- special attributes
+ this.className1= ((options & RObjectFactory.O_CLASS_NAME) != 0) ?
+ io.readString() : ((getRObjectType() == RObject.TYPE_DATAFRAME) ?
+ RObject.CLASSNAME_DATAFRAME : RObject.CLASSNAME_LIST);
+ final long l= this.length= io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+
+ if ((options & RObjectFactory.O_NO_CHILDREN) != 0) {
+ this.namesAttribute= null;
+ this.components= null;
+ }
+ else {
+ this.namesAttribute= (RCharacterStore) factory.readNames(io, l);
+ //-- data
+ this.components= new2dRObjectArray(options, SEGMENT_LENGTH);
+ for (int i= 0; i < this.components.length; i++) {
+ final RObject[] segment= this.components[i];
+ for (int j= 0; j < segment.length; j++) {
+ segment[j]= factory.readObject(io);
+ }
+ }
+ }
+ //-- attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ setAttributes(factory.readAttributeList(io));
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ doWriteExternal(io, 0, factory);
+ }
+ protected final void doWriteExternal(final RJIO io, int options, final RObjectFactory factory) throws IOException {
+ final long l= this.length;
+ //-- options
+ options |= io.getVULongGrade(l);
+ if (!this.className1.equals(getDefaultRClassName())) {
+ options |= RObjectFactory.O_CLASS_NAME;
+ }
+ final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+ if (attributes != null) {
+ options |= RObjectFactory.O_WITH_ATTR;
+ }
+ if (this.components == null) {
+ options |= RObjectFactory.O_NO_CHILDREN;
+ }
+ io.writeInt(options);
+ //-- special attributes
+ if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+ io.writeString(this.className1);
+ }
+ io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+
+ if ((options & RObjectFactory.O_NO_CHILDREN) == 0) {
+ factory.writeNames(this.namesAttribute, io);
+ //-- data
+ for (int i= 0; i < this.components.length; i++) {
+ final RObject[] segment= this.components[i];
+ for (int j= 0; j < segment.length; j++) {
+ factory.writeObject(segment[j], io);
+ }
+ }
+ }
+ //-- attributes
+ if (attributes != null) {
+ factory.writeAttributeList(attributes, io);
+ }
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_LIST;
+ }
+
+ protected String getDefaultRClassName() {
+ return RObject.CLASSNAME_LIST;
+ }
+
+ @Override
+ public final String getRClassName() {
+ return this.className1;
+ }
+
+
+ @Override
+ public long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public final RCharacterStore getNames() {
+ return this.namesAttribute;
+ }
+
+ @Override
+ public final String getName(final int idx) {
+ if (this.namesAttribute != null) {
+ return this.namesAttribute.getChar(idx);
+ }
+ return null;
+ }
+
+ @Override
+ public final String getName(final long idx) {
+ if (this.namesAttribute != null) {
+ return this.namesAttribute.getChar(idx);
+ }
+ return null;
+ }
+
+ @Override
+ public final RObject get(final int idx) {
+ return this.components[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public final RObject get(final long idx) {
+ return this.components[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public final RObject get(final String name) {
+ if (this.namesAttribute != null) {
+ final long idx= this.namesAttribute.indexOf(name);
+ if (idx >= 0) {
+ return get(idx);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public final RStore<?> getData() {
+ return null;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RObject type=RList, class=").append(getRClassName());
+ sb.append("\n\tlength=").append(this.length);
+ if (this.components != null) {
+ sb.append("\n\tdata: ");
+ for (int i= 0; i < this.length; i++) {
+ if (i > 100) {
+ sb.append("\n... ");
+ break;
+ }
+ if (this.namesAttribute == null || this.namesAttribute.isNA(i)) {
+ sb.append("\n[[").append((i + 1)).append("]]\n");
+ }
+ else {
+ sb.append("\n$").append(this.namesAttribute.getChar(i)).append("\n");
+ }
+ sb.append(this.components[i]);
+ }
+ }
+ else {
+ sb.append("\n<NODATA/>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByte32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByte32Store.java
new file mode 100644
index 0000000..e3b0182
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByte32Store.java
@@ -0,0 +1,340 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Based on byte array.
+ *
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RLogicalByte32Store extends AbstractLogicalStore
+ implements RDataResizeExtension<Boolean>, ExternalizableRStore, Externalizable {
+
+
+ public static final byte TRUE= TRUE_BYTE;
+ public static final byte FALSE= FALSE_BYTE;
+
+
+ private int length;
+
+ private byte[] boolValues;
+
+
+ public RLogicalByte32Store() {
+ this.length= 0;
+ this.boolValues= EMPTY_BYTE_ARRAY;
+ }
+
+ public RLogicalByte32Store(final int length) {
+ this.length= length;
+ this.boolValues= new byte[length];
+ }
+
+ public RLogicalByte32Store(final boolean[] values) {
+ this.length= values.length;
+ this.boolValues= new byte[values.length];
+ for (int i= values.length-1; i >= 0; i--) {
+ this.boolValues[i]= (values[i]) ? TRUE_BYTE : FALSE_BYTE;
+ }
+ }
+
+ public RLogicalByte32Store(final boolean[] values, final int[] naIdxs) {
+ this.length= values.length;
+ this.boolValues= new byte[values.length];
+ for (int i= values.length-1; i >= 0; i--) {
+ this.boolValues[i]= (values[i]) ? TRUE_BYTE : FALSE_BYTE;
+ }
+ if (naIdxs != null) {
+ for (int i= 0; i < naIdxs.length; i++) {
+ this.boolValues[naIdxs[i]]= NA_logical_BYTE;
+ }
+ }
+ }
+
+ public RLogicalByte32Store(final byte[] values) {
+ this.length= values.length;
+ this.boolValues= values;
+ }
+
+ public RLogicalByte32Store(final byte[] values, final byte trueCode, final byte naCode) {
+ this.length= values.length;
+ if (trueCode != TRUE_BYTE || naCode != NA_logical_BYTE) {
+ for (int i= values.length-1; i >= 0; i--) {
+ final int value= values[i];
+ if (value == trueCode) {
+ values[i]= TRUE_BYTE;
+ }
+ else if (value == naCode) {
+ values[i]= NA_logical_BYTE;
+ }
+ else {
+ values[i]= FALSE_BYTE;
+ }
+ }
+ }
+ this.boolValues= values;
+ }
+
+
+ public RLogicalByte32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.boolValues= io.readByteData(new byte[length], length);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeByteData(this.boolValues, this.length);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ this.length= in.readInt();
+ this.boolValues= new byte[this.length];
+ in.readFully(this.boolValues, 0, this.length);
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.length);
+ out.write(this.boolValues, 0, this.length);
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ protected final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.boolValues[idx] == NA_logical_BYTE);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[(int) idx] == NA_logical_BYTE);
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.boolValues[idx] == NA_logical_BYTE);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[(int) idx] == NA_logical_BYTE);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.boolValues[idx]= NA_logical_BYTE;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.boolValues[(int) idx]= NA_logical_BYTE;
+ }
+
+ @Override
+ public boolean getLogi(final int idx) {
+ return (this.boolValues[idx] == TRUE_BYTE);
+ }
+
+ @Override
+ public boolean getLogi(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[(int) idx] == TRUE_BYTE);
+ }
+
+ @Override
+ public void setLogi(final int idx, final boolean value) {
+ this.boolValues[idx]= (value) ? TRUE_BYTE : FALSE_BYTE;
+ }
+
+ @Override
+ public void setLogi(final long idx, final boolean value) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.boolValues[(int) idx]= (value) ? TRUE_BYTE : FALSE_BYTE;
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.boolValues= prepareInsert(this.boolValues, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insertLogi(final int idx, final boolean value) {
+ prepareInsert(new int[] { idx });
+ this.boolValues[idx]= value ? TRUE_BYTE : FALSE_BYTE;
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.boolValues[idx]= NA_logical_BYTE;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ if (idxs.length == 0) {
+ return;
+ }
+ prepareInsert(idxs);
+ for (int idx= 0; idx < idxs.length; idx++) {
+ this.boolValues[idxs[idx]+idx]= NA_logical_BYTE;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.boolValues= remove(this.boolValues, this.length, new int[] { idx });
+ this.length--;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.boolValues= remove(this.boolValues, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public Boolean get(final int idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ switch(this.boolValues[idx]) {
+ case TRUE_BYTE:
+ return Boolean.TRUE;
+ case FALSE_BYTE:
+ return Boolean.FALSE;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public Boolean get(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ switch(this.boolValues[(int) idx]) {
+ case TRUE_BYTE:
+ return Boolean.TRUE;
+ case FALSE_BYTE:
+ return Boolean.FALSE;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public Boolean[] toArray() {
+ final Boolean[] array= new Boolean[length()];
+ final byte[] bools= this.boolValues;
+ for (int i= 0; i < array.length; i++) {
+ switch(bools[i]) {
+ case TRUE_BYTE:
+ array[i]= Boolean.TRUE;
+ continue;
+ case FALSE_BYTE:
+ array[i]= Boolean.FALSE;
+ continue;
+ default:
+ continue;
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final long l= getLength();
+ final byte[] bools= this.boolValues;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (bools[i] == NA_logical_BYTE) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final int integer, long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE
+ || integer == NA_integer_INT ) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final byte[] bools= this.boolValues;
+ if (integer != 0) {
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (bools[i] == TRUE_BYTE) {
+ return i;
+ }
+ }
+ }
+ else {
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (bools[i] == FALSE_BYTE) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByteFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByteFix64Store.java
new file mode 100644
index 0000000..5be518d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalByteFix64Store.java
@@ -0,0 +1,247 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Based on byte array.
+ *
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RLogicalByteFix64Store extends AbstractLogicalStore
+ implements ExternalizableRStore {
+
+
+ public static final byte TRUE= TRUE_BYTE;
+ public static final byte FALSE= FALSE_BYTE;
+
+ public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+
+ private final byte[][] boolValues;
+
+
+ public RLogicalByteFix64Store(final long length) {
+ this.length= length;
+ this.boolValues= new2dByteArray(length, SEGMENT_LENGTH);
+ }
+
+ public RLogicalByteFix64Store(final byte[][] values) {
+ this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+ this.boolValues= values;
+ }
+
+
+ public RLogicalByteFix64Store(final RJIO io, final long length) throws IOException {
+ this.length= length;
+ this.boolValues= new2dByteArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.boolValues.length; i++) {
+ io.readByteData(this.boolValues[i], this.boolValues[i].length);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ for (int i= 0; i < this.boolValues.length; i++) {
+ io.writeByteData(this.boolValues[i], this.boolValues[i].length);
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_logical_BYTE);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ return (this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_logical_BYTE);
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == NA_logical_BYTE);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ return (this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == NA_logical_BYTE);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NA_logical_BYTE;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NA_logical_BYTE;
+ }
+
+ @Override
+ public boolean getLogi(final int idx) {
+ return (this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] == TRUE_BYTE);
+ }
+
+ @Override
+ public boolean getLogi(final long idx) {
+ return (this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] == TRUE_BYTE);
+ }
+
+ @Override
+ public void setLogi(final int idx, final boolean value) {
+ this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ (value) ? TRUE_BYTE : FALSE_BYTE;
+ }
+
+ @Override
+ public void setLogi(final long idx, final boolean value) {
+ this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ (value) ? TRUE_BYTE : FALSE_BYTE;
+ }
+
+
+ @Override
+ public Boolean get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ switch(this.boolValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]) {
+ case TRUE_BYTE:
+ return Boolean.TRUE;
+ case FALSE_BYTE:
+ return Boolean.FALSE;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public Boolean get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ switch(this.boolValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]) {
+ case TRUE_BYTE:
+ return Boolean.TRUE;
+ case FALSE_BYTE:
+ return Boolean.FALSE;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public Boolean[] toArray() {
+ final int l= checkToArrayLength();
+ final Boolean[] array= new Boolean[l];
+ int k= 0;
+ for (int i= 0; i < this.boolValues.length; i++, k++) {
+ final byte[] bools= this.boolValues[i];
+ for (int j= 0; j < bools.length; j++) {
+ switch(bools[j]) {
+ case TRUE_BYTE:
+ array[k]= Boolean.TRUE;
+ continue;
+ case FALSE_BYTE:
+ array[k]= Boolean.FALSE;
+ continue;
+ default:
+ continue;
+ }
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ { while (i < this.boolValues.length) {
+ final byte[] bools= this.boolValues[i];
+ while (j < bools.length) {
+ if (bools[i] == NA_logical_BYTE) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final int integer, long fromIdx) {
+ if (integer == NA_integer_INT ) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ if (integer != 0) {
+ while (i < this.boolValues.length) {
+ final byte[] bools= this.boolValues[i];
+ while (j < bools.length) {
+ if (bools[i] == TRUE_BYTE) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ }
+ else {
+ while (i < this.boolValues.length) {
+ final byte[] bools= this.boolValues[i];
+ while (j < bools.length) {
+ if (bools[i] == FALSE_BYTE) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalInt32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalInt32Store.java
new file mode 100644
index 0000000..ae5faab
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalInt32Store.java
@@ -0,0 +1,300 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Based on int array.
+ *
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RLogicalInt32Store extends AbstractLogicalStore
+ implements RDataResizeExtension<Boolean>, ExternalizableRStore {
+
+
+ private int length;
+
+ protected int[] boolValues;
+
+
+ public RLogicalInt32Store() {
+ this.boolValues= EMPTY_INT_ARRAY;
+ this.length= 0;
+ }
+
+ public RLogicalInt32Store(final boolean[] values, final int[] naIdxs) {
+ this.boolValues= new int[values.length];
+ for (int i= values.length-1; i >= 0; i--) {
+ this.boolValues[i]= values[i] ? TRUE_INT : FALSE_INT;
+ }
+ this.length= this.boolValues.length;
+ if (naIdxs != null) {
+ for (int i= 0; i < naIdxs.length; i++) {
+ this.boolValues[naIdxs[i]]= NA_logical_INT;
+ }
+ }
+ }
+
+ /**
+ * Create new logical data based on the given Java int array
+ * encoded as follows:
+ * <code>FALSE</code>= 0
+ * <code>NA</code>= 2
+ * <code>TRUE</code>= anything else (default value 1)
+ *
+ * @param values encoded value array, used directly (not copied)
+ */
+ public RLogicalInt32Store(final int[] values) {
+ this.length= values.length;
+ this.boolValues= values;
+ }
+
+ public RLogicalInt32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.boolValues= new int[length];
+ for (int i= 0; i < this.length; i++) {
+ final byte b= io.readByte();
+ if (b == TRUE_BYTE) {
+ this.boolValues[i]= TRUE_INT;
+ }
+ else if (b == NA_logical_BYTE) {
+ this.boolValues[i]= NA_integer_INT;
+ }
+ else {
+ this.boolValues[i]= FALSE_INT;
+ }
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ for (int i= 0; i < this.length; i++) {
+ switch (this.boolValues[i]) {
+ case FALSE_INT:
+ io.writeByte(FALSE_BYTE);
+ continue;
+ case NA_logical_INT:
+ io.writeByte(NA_logical_BYTE);
+ continue;
+ default:
+ io.writeByte(TRUE_BYTE);
+ continue;
+ }
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ protected final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ return (this.boolValues[idx] == NA_logical_INT);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[(int) idx] == NA_logical_INT);
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (this.boolValues[idx] == NA_logical_INT);
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[(int) idx] == NA_logical_INT);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.boolValues[idx]= NA_logical_INT;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.boolValues[(int) idx]= NA_logical_INT;
+ }
+
+ @Override
+ public boolean getLogi(final int idx) {
+ return (this.boolValues[idx] != FALSE_INT);
+ }
+
+ @Override
+ public boolean getLogi(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[(int) idx] != FALSE_INT);
+ }
+
+ @Override
+ public void setLogi(final int idx, final boolean value) {
+ this.boolValues[idx]= value ? TRUE_INT : FALSE_INT;
+ }
+
+ @Override
+ public void setLogi(final long idx, final boolean value) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.boolValues[(int) idx]= value ? TRUE_INT : FALSE_INT;
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.boolValues= prepareInsert(this.boolValues, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insertLogi(final int idx, final boolean value) {
+ prepareInsert(new int[] { idx });
+ this.boolValues[idx]= value ? TRUE_INT : FALSE_INT;
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.boolValues[idx]= NA_logical_INT;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ if (idxs.length == 0) {
+ return;
+ }
+ prepareInsert(idxs);
+ for (int idx= 0; idx < idxs.length; idx++) {
+ this.boolValues[idxs[idx]+idx]= NA_logical_INT;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.boolValues= remove(this.boolValues, this.length, new int[] { idx });
+ this.length--;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.boolValues= remove(this.boolValues, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public Boolean get(final int idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[idx] != NA_logical_INT) ?
+ ((this.boolValues[idx] == TRUE_INT) ? Boolean.TRUE : Boolean.FALSE) : null;
+ }
+
+ @Override
+ public Boolean get(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (this.boolValues[(int) idx] != NA_logical_INT) ?
+ ((this.boolValues[(int) idx] == TRUE_INT) ? Boolean.TRUE : Boolean.FALSE) : null;
+ }
+
+ @Override
+ public Boolean[] toArray() {
+ final Boolean[] array= new Boolean[length()];
+ for (int i= 0; i < array.length; i++) {
+ if (this.boolValues[i] != NA_logical_INT) {
+ array[i]= (this.boolValues[i] == TRUE_INT) ? Boolean.TRUE : Boolean.FALSE;
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOfNA(long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final long l= getLength();
+ final int[] ints= this.boolValues;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (ints[i] == NA_integer_INT) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public long indexOf(final int integer, long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE
+ || integer == NA_integer_INT ) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final int l= length();
+ final int[] ints= this.boolValues;
+ if (integer != 0) {
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (ints[i] == TRUE_INT) {
+ return i;
+ }
+ }
+ }
+ else {
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (ints[i] == FALSE_INT) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalStructStore.java
new file mode 100644
index 0000000..00adf52
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RLogicalStructStore.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RLogicalStructStore extends AbstractLogicalStore {
+
+
+ public RLogicalStructStore() {
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return true;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return -1;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Boolean get(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Boolean get(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final Boolean[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ return (LOGICAL == other.getStoreType()
+ && -1 == other.getLength() );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RMissingImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RMissingImpl.java
new file mode 100644
index 0000000..10b13ac
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RMissingImpl.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * Default implementation of an R object of type {@link RObject#TYPE_MISSING MISSING}.
+ *
+ * @since de.walware.rj.data 0.5
+ */
+public class RMissingImpl implements RObject {
+
+
+ public static final RMissingImpl INSTANCE= new RMissingImpl();
+
+
+ public RMissingImpl() {
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_MISSING;
+ }
+
+ @Override
+ public String getRClassName() {
+ return "<missing>";
+ }
+
+ /**
+ * Returns the length of the object. The length of {@link RObject#TYPE_MISSING MISSING}
+ * is always zero.
+ *
+ * @return the length
+ */
+ @Override
+ public long getLength() {
+ return 0;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+ @Override
+ public RList getAttributes() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 68462137;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (this == obj || (
+ (obj instanceof RObject) && ((RObject) obj).getRObjectType() == RObject.TYPE_MISSING) );
+ }
+
+ @Override
+ public String toString() {
+ return "RObject type=RMissingImpl";
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNullImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNullImpl.java
new file mode 100644
index 0000000..00b311e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNullImpl.java
@@ -0,0 +1,79 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RNullImpl implements RObject {
+
+
+ public static final RNullImpl INSTANCE= new RNullImpl();
+
+
+ public RNullImpl() {
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_NULL;
+ }
+
+ @Override
+ public String getRClassName() {
+ return CLASSNAME_NULL;
+ }
+
+ /**
+ * Returns the length of the object. The length of {@link RObject#TYPE_NULL NULL}
+ * is always zero.
+ *
+ * @return the length
+ */
+ @Override
+ public long getLength() {
+ return 0;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+ @Override
+ public RList getAttributes() {
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ return 15677;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (this == obj || (
+ (obj instanceof RObject) && ((RObject) obj).getRObjectType() == RObject.TYPE_NULL) );
+ }
+
+ @Override
+ public String toString() {
+ return "RObject type=RNullImpl";
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericB32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericB32Store.java
new file mode 100644
index 0000000..a3d7488
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericB32Store.java
@@ -0,0 +1,270 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RNumericB32Store extends AbstractNumericStore
+ implements RDataResizeExtension<Double>, ExternalizableRStore, Externalizable {
+
+
+ private int length;
+
+ protected double[] realValues;
+
+
+ public RNumericB32Store() {
+ this.length= 0;
+ this.realValues= EMPTY_DOUBLE_ARRAY;
+ }
+
+ public RNumericB32Store(final int length) {
+ this.length= length;
+ this.realValues= new double[length];
+ }
+
+ public RNumericB32Store(final double[] values) {
+ this.length= values.length;
+ this.realValues= values;
+ }
+
+ public RNumericB32Store(final double[] values, final int[] naIdxs) {
+ this.length= values.length;
+ this.realValues= values;
+ if (naIdxs != null) {
+ for (int i= 0; i < naIdxs.length; i++) {
+ this.realValues[naIdxs[i]]= NA_numeric_DOUBLE;
+ }
+ }
+ }
+
+
+ public RNumericB32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.realValues= io.readDoubleData(new double[length], length);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeDoubleData(this.realValues, this.length);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ this.length= in.readInt();
+ this.realValues= new double[this.length];
+ for (int i= 0; i < this.length; i++) {
+ this.realValues[i]= Double.longBitsToDouble(in.readLong());
+ }
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.length);
+ for (int i= 0; i < this.length; i++) {
+ out.writeLong(Double.doubleToRawLongBits(this.realValues[i]));
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ protected final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ final double v= this.realValues[idx];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[(int) idx];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.realValues[idx]= NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.realValues[(int) idx]= NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public boolean isNaN(final int idx) {
+ final double v= this.realValues[idx];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNaN(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[(int) idx];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (Double.isNaN(this.realValues[idx]));
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return (Double.isNaN(this.realValues[(int) idx]));
+ }
+
+ @Override
+ public double getNum(final int idx) {
+ return this.realValues[idx];
+ }
+
+ @Override
+ public double getNum(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.realValues[(int) idx];
+ }
+
+ @Override
+ public void setNum(final int idx, final double value) {
+ this.realValues[idx]= (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+ }
+
+ @Override
+ public void setNum(final long idx, final double value) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.realValues[(int) idx]= (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.realValues= prepareInsert(this.realValues, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insertNum(final int idx, final double value) {
+ prepareInsert(new int[] { idx });
+ this.realValues[idx]= (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.realValues[idx]= NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ if (idxs.length == 0) {
+ return;
+ }
+ prepareInsert(idxs);
+ for (int idx= 0; idx < idxs.length; idx++) {
+ this.realValues[idx]= NA_numeric_DOUBLE;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.realValues= remove(this.realValues, this.length, new int[] { idx });
+ this.length--;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.realValues= remove(this.realValues, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public Double get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[idx];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ Double.valueOf(v) : null;
+ }
+
+ @Override
+ public Double get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[(int) idx];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ Double.valueOf(v) : null;
+ }
+
+
+ @Override
+ public Double[] toArray() {
+ final Double[] array= new Double[length()];
+ final double[] reals= this.realValues;
+ for (int i= 0; i < array.length; i++) {
+ final double v= reals[i];
+ if (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+ array[i]= Double.valueOf(v);
+ }
+ }
+ return array;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericBFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericBFix64Store.java
new file mode 100644
index 0000000..4fc2759
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericBFix64Store.java
@@ -0,0 +1,190 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RNumericBFix64Store extends AbstractNumericStore
+ implements ExternalizableRStore {
+
+
+ public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+
+ protected final double[][] realValues;
+
+
+ public RNumericBFix64Store(final long length) {
+ this.length= length;
+ this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+ }
+
+ public RNumericBFix64Store(final double[][] values) {
+ this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+ this.realValues= values;
+ }
+
+
+ public RNumericBFix64Store(final RJIO io, final long length) throws IOException {
+ this.length= length;
+ this.realValues= new2dDoubleArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.realValues.length; i++) {
+ io.readDoubleData(this.realValues[i], this.realValues[i].length);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ for (int i= 0; i < this.realValues.length; i++) {
+ io.writeDoubleData(this.realValues[i], this.realValues[i].length);
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) == NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ NA_numeric_DOUBLE;
+ }
+
+ @Override
+ public boolean isNaN(final int idx) {
+ final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isNaN(final long idx) {
+ final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (Double.isNaN(v)
+ && (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH);
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ return (Double.isNaN(
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] ));
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ return (Double.isNaN(
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] ));
+ }
+
+ @Override
+ public double getNum(final int idx) {
+ return this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public double getNum(final long idx) {
+ return this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public void setNum(final int idx, final double value) {
+ this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+ }
+
+ @Override
+ public void setNum(final long idx, final double value) {
+ this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ (Double.isNaN(value)) ? NaN_numeric_DOUBLE : value;
+ }
+
+
+ @Override
+ public Double get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ Double.valueOf(v) :
+ null;
+ }
+
+ @Override
+ public Double get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ final double v= this.realValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ return (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) ?
+ Double.valueOf(v) :
+ null;
+ }
+
+
+ @Override
+ public Double[] toArray() {
+ final int l= checkToArrayLength();
+ final Double[] array= new Double[l];
+ int k= 0;
+ for (int i= 0; i < this.realValues.length; i++, k++) {
+ final double[] reals= this.realValues[i];
+ for (int j= 0; j < reals.length; j++) {
+ final double v= reals[j];
+ if (!Double.isNaN(v)
+ || (int) Double.doubleToRawLongBits(v) != NA_numeric_INT_MATCH) {
+ array[k]= Double.valueOf(v);
+ }
+ }
+ }
+ return array;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericStructStore.java
new file mode 100644
index 0000000..f0d005e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RNumericStructStore.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RNumericStructStore extends AbstractNumericStore {
+
+
+ public RNumericStructStore() {
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return true;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return -1;
+ }
+
+ @Override
+ public boolean isNA(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNA(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNaN(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isNaN(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMissing(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Double get(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Double get(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final Double[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ return (NUMERIC == other.getStoreType()
+ && -1 == other.getLength() );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RObjectStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RObjectStore.java
new file mode 100644
index 0000000..a8d2f27
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RObjectStore.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RObject;
+
+
+public abstract class RObjectStore {
+
+
+ public abstract RObject get(long idx);
+
+ public abstract void set(long idx, RObject item);
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ROtherImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ROtherImpl.java
new file mode 100644
index 0000000..719fd8b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/ROtherImpl.java
@@ -0,0 +1,97 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class ROtherImpl extends AbstractRObject
+ implements ExternalizableRObject {
+
+
+ private String className1;
+
+
+ public ROtherImpl(final String className1) {
+ if (className1 == null) {
+ throw new NullPointerException();
+ }
+ this.className1= className1;
+ }
+
+ public ROtherImpl(final String className1, final RList attributes) {
+ if (className1 == null) {
+ throw new NullPointerException();
+ }
+ this.className1= className1;
+ setAttributes(attributes);
+ }
+
+ public ROtherImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ //-- options
+ final int options= io.readInt();
+ //-- special attributes
+ this.className1= io.readString();
+ //-- attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ setAttributes(factory.readAttributeList(io));
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+ //-- options
+ final int options= (attributes != null) ? RObjectFactory.O_WITH_ATTR : 0;
+ io.writeInt(options);
+ //-- special attributes
+ io.writeString(this.className1);
+ //-- attributes
+ if (attributes != null) {
+ factory.writeAttributeList(attributes, io);
+ }
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_OTHER;
+ }
+
+ @Override
+ public String getRClassName() {
+ return this.className1;
+ }
+
+ @Override
+ public long getLength() {
+ return 0;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RPromiseImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RPromiseImpl.java
new file mode 100644
index 0000000..bbf6043
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RPromiseImpl.java
@@ -0,0 +1,62 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * Default implementation of an R object of type {@link RObject#TYPE_PROMISE PROMISE}.
+ *
+ * @since de.walware.rj.data 0.6
+ */
+public class RPromiseImpl implements RObject {
+
+
+ public static final RPromiseImpl INSTANCE= new RPromiseImpl();
+
+
+ public RPromiseImpl() {
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_PROMISE;
+ }
+
+ @Override
+ public String getRClassName() {
+ return "<promise>";
+ }
+
+ @Override
+ public long getLength() {
+ return 0;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+ @Override
+ public RList getAttributes() {
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRaw32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRaw32Store.java
new file mode 100644
index 0000000..59d87d0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRaw32Store.java
@@ -0,0 +1,213 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * This implementation is limited to length of 2<sup>31</sup>-1.
+ */
+public class RRaw32Store extends AbstractRawStore
+ implements RDataResizeExtension<Byte>, ExternalizableRStore, Externalizable {
+
+
+ private int length;
+
+ protected byte[] byteValues;
+
+
+ public RRaw32Store() {
+ this.byteValues= EMPTY_BYTE_ARRAY;
+ this.length= 0;
+ }
+
+ public RRaw32Store(final int length) {
+ this.byteValues= new byte[length];
+ this.length= length;
+ }
+
+ public RRaw32Store(final byte[] values) {
+ this.byteValues= values;
+ this.length= this.byteValues.length;
+ }
+
+
+ public RRaw32Store(final RJIO io, final int length) throws IOException {
+ this.length= length;
+ this.byteValues= io.readByteData(new byte[length], length);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeByteData(this.byteValues, this.length);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ this.length= in.readInt();
+ this.byteValues= new byte[this.length];
+ in.readFully(this.byteValues, 0, this.length);
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.length);
+ out.write(this.byteValues, 0, this.length);
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ protected final int length() {
+ return this.length;
+ }
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public byte getRaw(final int idx) {
+ return this.byteValues[idx];
+ }
+
+ @Override
+ public byte getRaw(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.byteValues[(int) idx];
+ }
+
+ @Override
+ public void setRaw(final int idx, final byte value) {
+ this.byteValues[idx]= value;
+ }
+
+ @Override
+ public void setRaw(final long idx, final byte value) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ this.byteValues[(int) idx]= value;
+ }
+
+
+ private void prepareInsert(final int[] idxs) {
+ this.byteValues= prepareInsert(this.byteValues, this.length, idxs);
+ this.length+= idxs.length;
+ }
+
+ public void insert(final int idx, final byte value) {
+ prepareInsert(new int[] { idx });
+ this.byteValues[idx]= value;
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ prepareInsert(new int[] { idx });
+ this.byteValues[idx]= NA_byte_BYTE;
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ if (idxs.length == 0) {
+ return;
+ }
+ prepareInsert(idxs);
+ for (int idx= 0; idx < idxs.length; idx++) {
+ this.byteValues[idx]= NA_byte_BYTE;
+ }
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.byteValues= remove(this.byteValues, this.length, new int[] { idx });
+ this.length--;
+ }
+
+ @Override
+ public void remove(final int[] idxs) {
+ this.byteValues= remove(this.byteValues, this.length, idxs);
+ this.length-= idxs.length;
+ }
+
+
+ @Override
+ public Byte get(final int idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return Byte.valueOf(this.byteValues[idx]);
+ }
+
+ @Override
+ public Byte get(final long idx) {
+ if (idx < 0 || idx >= length()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return Byte.valueOf(this.byteValues[(int) idx]);
+ }
+
+ @Override
+ public Byte[] toArray() {
+ final Byte[] array= new Byte[length()];
+ final byte[] raws= this.byteValues;
+ for (int i= 0; i < array.length; i++) {
+ array[i]= Byte.valueOf(raws[i]);
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOf(final int integer, long fromIdx) {
+ if (fromIdx >= Integer.MAX_VALUE
+ || (integer & 0xffffff00) != 0 ) {
+ return -1;
+ }
+ if (fromIdx < 0) {
+ fromIdx= 0;
+ }
+ final byte raw= (byte) (integer & 0xff);
+ final int l= length();
+ final byte[] raws= this.byteValues;
+ for (int i= (int) fromIdx; i < l; i++) {
+ if (raws[i] == raw) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawFix64Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawFix64Store.java
new file mode 100644
index 0000000..ae29f32
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawFix64Store.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RRawFix64Store extends AbstractRawStore
+ implements ExternalizableRStore {
+
+
+ public static final int SEGMENT_LENGTH= DEFAULT_LONG_DATA_SEGMENT_LENGTH;
+
+
+ private final long length;
+
+ protected final byte[][] byteValues;
+
+
+ public RRawFix64Store(final long length) {
+ this.length= length;
+ this.byteValues= new2dByteArray(length, SEGMENT_LENGTH);
+ }
+
+ public RRawFix64Store(final byte[][] values) {
+ this.length= check2dArrayLength(values, SEGMENT_LENGTH);
+ this.byteValues= values;
+ }
+
+
+ public RRawFix64Store(final RJIO io, final long length) throws IOException {
+ this.length= length;
+ this.byteValues= new2dByteArray(length, SEGMENT_LENGTH);
+ for (int i= 0; i < this.byteValues.length; i++) {
+ io.readByteData(this.byteValues[i], this.byteValues[i].length);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ for (int i= 0; i < this.byteValues.length; i++) {
+ io.writeByteData(this.byteValues[i], this.byteValues[i].length);
+ }
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return false;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public byte getRaw(final int idx) {
+ return this.byteValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH];
+ }
+
+ @Override
+ public byte getRaw(final long idx) {
+ return this.byteValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)];
+ }
+
+ @Override
+ public void setRaw(final int idx, final byte value) {
+ this.byteValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH] =
+ value;
+ }
+
+ @Override
+ public void setRaw(final long idx, final byte value) {
+ this.byteValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)] =
+ value;
+ }
+
+
+ @Override
+ public Byte get(final int idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return Byte.valueOf(this.byteValues[idx / SEGMENT_LENGTH][idx % SEGMENT_LENGTH]);
+ }
+
+ @Override
+ public Byte get(final long idx) {
+ if (idx < 0 || idx >= this.length) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return Byte.valueOf(this.byteValues[(int) (idx / SEGMENT_LENGTH)][(int) (idx % SEGMENT_LENGTH)]);
+ }
+
+ @Override
+ public Byte[] toArray() {
+ final int l= checkToArrayLength();
+ final Byte[] array= new Byte[l];
+ int k= 0;
+ for (int i= 0; i < this.byteValues.length; i++, k++) {
+ final byte[] raws= this.byteValues[i];
+ for (int j= 0; j < raws.length; j++) {
+ array[k]= Byte.valueOf(raws[j]);
+ }
+ }
+ return array;
+ }
+
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ if ((integer & 0xffffff00) != 0) {
+ return -1;
+ }
+ final byte raw= (byte) (integer & 0xff);
+ int i= (int) (fromIdx / SEGMENT_LENGTH);
+ int j= (int) (fromIdx % SEGMENT_LENGTH);
+ while (i < this.byteValues.length) {
+ final byte[] raws= this.byteValues[i];
+ while (j < raws.length) {
+ if (raws[i] == raw) {
+ return (i * (long) SEGMENT_LENGTH) + j;
+ }
+ }
+ i++;
+ j= 0;
+ }
+ return -1;
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawStructStore.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawStructStore.java
new file mode 100644
index 0000000..1f62049
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RRawStructStore.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RRawStructStore extends AbstractRawStore {
+
+
+ public RRawStructStore() {
+ }
+
+
+ @Override
+ protected final boolean isStructOnly() {
+ return true;
+ }
+
+
+ @Override
+ public final long getLength() {
+ return -1;
+ }
+
+ @Override
+ public Byte get(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Byte get(final long idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final Byte[] toArray() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long indexOfNA(final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final int integer, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long indexOf(final String character, final long fromIdx) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean allEqual(final RStore<?> other) {
+ return (RAW == other.getStoreType()
+ && -1 == other.getLength() );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RReferenceImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RReferenceImpl.java
new file mode 100644
index 0000000..b38f85d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RReferenceImpl.java
@@ -0,0 +1,121 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RReferenceImpl implements RReference, ExternalizableRObject {
+
+
+ private long handle;
+ private byte type;
+ private String baseClassName;
+
+
+ public RReferenceImpl(final long handler, final byte type, final String baseClass) {
+ this.handle= handler;
+ this.type= type;
+ this.baseClassName= baseClass;
+ }
+
+ public RReferenceImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ this.handle= io.readLong();
+ this.type= io.readByte();
+ this.baseClassName= io.readString();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ io.writeLong(this.handle);
+ io.writeByte(this.type);
+ io.writeString(this.baseClassName);
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_REFERENCE;
+ }
+
+ @Override
+ public byte getReferencedRObjectType() {
+ return this.type;
+ }
+
+ @Override
+ public String getRClassName() {
+ return this.baseClassName;
+ }
+
+ @Override
+ public long getLength() {
+ return 0;
+ }
+
+ @Override
+ public long getHandle() {
+ return this.handle;
+ }
+
+ @Override
+ public RObject getResolvedRObject() {
+ return null;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return null;
+ }
+
+ @Override
+ public RList getAttributes() {
+ return null;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return (int) this.handle;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (this == obj
+ || (obj instanceof RReference
+ && this.handle == ((RReference) obj).getHandle() ));
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RObjectReference type= ").append(RDataUtils.getObjectTypeName(this.type));
+ sb.append(", class= ").append(getRClassName());
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RS4ObjectImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RS4ObjectImpl.java
new file mode 100644
index 0000000..3ebdb4d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RS4ObjectImpl.java
@@ -0,0 +1,194 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RS4Object;
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RS4ObjectImpl extends AbstractRObject
+ implements RS4Object, ExternalizableRObject {
+
+
+ private String className;
+
+ private int dataSlotIdx;
+ private RCharacter32Store slotNames;
+ private RObject[] slotValues;
+
+
+ public RS4ObjectImpl(final String className, final String[] slotNames, final RObject[] slotValues) {
+ if (className == null || slotNames == null || slotValues == null) {
+ throw new NullPointerException();
+ }
+ this.className= className;
+ this.slotNames= new RCharacter32Store(slotNames);
+
+ this.dataSlotIdx= this.slotNames.indexOf(".Data", 0);
+ this.slotValues= slotValues;
+ }
+
+ public RS4ObjectImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ //-- options
+ final int options= io.readInt();
+ //-- special attributes
+ this.className= io.readString();
+ //-- data
+ final int l= (int) io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+
+ this.dataSlotIdx= io.readInt();
+ this.slotNames= new RCharacter32Store(io, l);
+ this.slotValues= new RObject[l];
+ for (int i= 0; i < l; i++) {
+ this.slotValues[i]= factory.readObject(io);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ final int l= this.slotValues.length;
+ //-- options
+ final int options= io.getVULongGrade(l);
+ io.writeInt(options);
+ //-- special attributes
+ io.writeString(this.className);
+ //-- data
+ io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), l);
+
+ io.writeInt(this.dataSlotIdx);
+ this.slotNames.writeExternal(io);
+ for (int i= 0; i < l; i++) {
+ factory.writeObject(this.slotValues[i], io);
+ }
+ }
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_S4OBJECT;
+ }
+
+ @Override
+ public String getRClassName() {
+ return this.className;
+ }
+
+
+ @Override
+ public long getLength() {
+ return this.slotValues.length;
+ }
+
+ @Override
+ public boolean hasDataSlot() {
+ return (this.dataSlotIdx >= 0);
+ }
+
+ @Override
+ public RObject getDataSlot() {
+ return (this.dataSlotIdx >= 0) ? this.slotValues[this.dataSlotIdx] : null;
+ }
+
+ public byte getDataType() {
+ return (this.dataSlotIdx >= 0 && this.slotValues[this.dataSlotIdx] != null) ?
+ this.slotValues[this.dataSlotIdx].getData().getStoreType() : 0;
+ }
+
+ @Override
+ public RStore<?> getData() {
+ return (this.dataSlotIdx >= 0 && this.slotValues[this.dataSlotIdx] != null) ?
+ this.slotValues[this.dataSlotIdx].getData() : null;
+ }
+
+ @Override
+ public RCharacterStore getNames() {
+ return this.slotNames;
+ }
+
+ @Override
+ public String getName(final int idx) {
+ return this.slotNames.getChar(idx);
+ }
+
+ @Override
+ public String getName(final long idx) {
+ return this.slotNames.getChar(idx);
+ }
+
+ @Override
+ public RObject get(final int idx) {
+ return this.slotValues[idx];
+ }
+
+ @Override
+ public RObject get(final long idx) {
+ if (idx < 0 || idx >= Integer.MAX_VALUE) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ return this.slotValues[(int) idx];
+ }
+
+ @Override
+ public RObject get(final String name) {
+ final int idx= this.slotNames.indexOf(name, 0);
+ if (idx >= 0) {
+ return this.slotValues[idx];
+ }
+ throw new IllegalArgumentException();
+ }
+
+
+ public void insert(final int idx, final String name, final RObject component) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void add(final String name, final RObject component) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void remove(final int idx) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean set(final int idx, final RObject value) {
+ this.slotValues[idx]= value;
+ return true;
+ }
+
+ public boolean set(final String name, final RObject component) {
+ if (this.dataSlotIdx >= 0 && name.equals(".Data")) {
+ this.slotValues[this.dataSlotIdx]= component;
+ return true;
+ }
+ else {
+ final int i= this.slotNames.indexOf(name, 0);
+ if (i >= 0) {
+ this.slotValues[i]= component;
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacter32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacter32Store.java
new file mode 100644
index 0000000..176d50d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacter32Store.java
@@ -0,0 +1,102 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RUniqueCharacter32Store extends RCharacter32Store {
+
+
+ public RUniqueCharacter32Store() {
+ super();
+ }
+
+ public RUniqueCharacter32Store(final String[] initialValues) {
+ super(initialValues, initialValues.length);
+ }
+
+ RUniqueCharacter32Store(final RCharacter32Store source, final boolean reuse) {
+ super(source, reuse);
+ }
+
+ public RUniqueCharacter32Store(final RJIO io, final int length) throws IOException {
+ super(io, length);
+ }
+
+
+ @Override
+ public void setChar(final int idx, final String value) {
+ if (indexOf(value) >= 0) {
+ if (indexOf(value) == idx) {
+ return;
+ }
+ throw new IllegalArgumentException();
+ }
+ super.setChar(idx, value);
+ }
+
+ @Override
+ public void setChar(final long idx, final String value) {
+ if (idx < 0 || idx >= getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ setChar((int) idx, value);
+ }
+
+ @Override
+ public void insertChar(final int idx, final String value) {
+ if (indexOf(value) >= 0) {
+ throw new IllegalArgumentException();
+ }
+ super.insertChar(idx, value);
+ }
+
+ @Override
+ public void setNA(final int idx) {
+ }
+
+ @Override
+ public void setNA(final long idx) {
+ }
+
+ @Override
+ public void insertNA(final int idx) {
+ }
+
+ @Override
+ public void insertNA(final int[] idxs) {
+ }
+
+ protected void insertAuto(final int idx) {
+ insertChar(idx, createAuto(idx));
+ }
+
+ protected String createAuto(final int idx) {
+ final String nr= Integer.toString(idx+1);
+ if (indexOf(nr) < 0) {
+ return nr;
+ }
+ for (int i= 1; ; i++) {
+ final String sub= nr+'.'+Integer.toString(i);
+ if (indexOf(sub) < 0) {
+ return sub;
+ }
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacterHash32Store.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacterHash32Store.java
new file mode 100644
index 0000000..66c7707
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RUniqueCharacterHash32Store.java
@@ -0,0 +1,97 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class RUniqueCharacterHash32Store extends RUniqueCharacter32Store {
+
+
+ private final HashMap<String, Integer> map;
+
+
+ public RUniqueCharacterHash32Store(final String names[]) {
+ super(names);
+ this.map= new HashMap<>();
+ initMap();
+ }
+
+ RUniqueCharacterHash32Store(final RCharacter32Store source, final boolean reuse) {
+ super(source, reuse);
+ this.map= new HashMap<>();
+ initMap();
+ }
+
+ public RUniqueCharacterHash32Store(final RJIO io, final int length) throws IOException {
+ super(io, length);
+ this.map= new HashMap<>();
+ initMap();
+ }
+
+
+ protected void initMap() {
+ final int length= (int) getLength();
+ for (int idx= 0; idx < length; idx++) {
+ if (this.charValues[idx] != null) {
+ this.map.put(this.charValues[idx], idx);
+ }
+ }
+ }
+
+
+ @Override
+ public void setChar(final int idx, final String value) {
+ final String previous= getChar(idx);
+ super.setChar(idx, value);
+ this.map.remove(previous);
+ this.map.put(value, idx);
+ }
+
+ @Override
+ public void setChar(final long idx, final String value) {
+ if (idx < 0 || idx >= getLength()) {
+ throw new IndexOutOfBoundsException(Long.toString(idx));
+ }
+ setChar((int) idx, value);
+ }
+
+ @Override
+ public void insertChar(final int idx, final String name) {
+ super.insertChar(idx, name);
+ this.map.put(name, idx);
+ }
+
+ @Override
+ public void remove(final int idx) {
+ this.map.remove(getChar(idx));
+ super.remove(idx);
+ }
+
+
+ @Override
+ public boolean contains(final String value) {
+ return (value != null && this.map.containsKey(value));
+ }
+
+ @Override
+ public long indexOf(final String name, final long fromIdx) {
+ return this.map.get(name);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RVectorImpl.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RVectorImpl.java
new file mode 100644
index 0000000..03cf1de
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/RVectorImpl.java
@@ -0,0 +1,188 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.RStore;
+import org.eclipse.statet.rj.data.RVector;
+
+
+public class RVectorImpl<TData extends RStore<?>> extends AbstractRObject
+ implements RVector<TData>, ExternalizableRObject {
+
+
+ private TData data;
+ private long length;
+
+ private String className1;
+ private RStore<?> namesAttribute;
+
+
+ public RVectorImpl(final TData data, final String className1) {
+ this(data, data.getLength(), className1, null);
+ }
+
+ public RVectorImpl(final TData data) {
+ this(data, data.getLength(), data.getBaseVectorRClassName(), null);
+ }
+
+ public RVectorImpl(final TData data, final String className1, final String[] initialNames) {
+ this(data, data.getLength(), className1, initialNames);
+ }
+
+ public RVectorImpl(final TData data, final long length, final String className1, final String[] initialNames) {
+ if (data == null || className1 == null) {
+ throw new NullPointerException();
+ }
+ if ((initialNames != null && initialNames.length != length)
+ || (data.getLength() >= 0 && data.getLength() != length) ) {
+ throw new IllegalArgumentException();
+ }
+ this.data= data;
+ this.length= length;
+ this.className1= className1;
+ if (initialNames != null) {
+ this.namesAttribute= new RCharacter32Store(initialNames);
+ }
+ }
+
+ public RVectorImpl(final TData data, final String className1, final RStore<?> initialNames) {
+ if (data == null || className1 == null) {
+ throw new NullPointerException();
+ }
+ if ((initialNames != null && initialNames.getLength() != data.getLength())) {
+ throw new IllegalArgumentException();
+ }
+ this.data= data;
+ this.length= data.getLength();
+ this.className1= className1;
+ this.namesAttribute= initialNames;
+ }
+
+ public RVectorImpl(final RJIO io, final RObjectFactory factory) throws IOException {
+ readExternal(io, factory);
+ }
+
+ public void readExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ //-- options
+ final int options= io.readInt();
+ //-- special attributes
+ if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+ this.className1= io.readString();
+ }
+ this.length= io.readVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK));
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ this.namesAttribute= factory.readNames(io, this.length);
+ }
+ //-- data
+ this.data= (TData) factory.readStore(io, this.length);
+ if ((options & RObjectFactory.O_CLASS_NAME) == 0) {
+ this.className1= this.data.getBaseVectorRClassName();
+ }
+ // attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ setAttributes(factory.readAttributeList(io));
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io, final RObjectFactory factory) throws IOException {
+ //-- options
+ int options= io.getVULongGrade(this.length);
+ if (!this.className1.equals(this.data.getBaseVectorRClassName())) {
+ options |= RObjectFactory.O_CLASS_NAME;
+ }
+ if ((io.flags & RObjectFactory.F_ONLY_STRUCT) == 0 && this.namesAttribute != null) {
+ options |= RObjectFactory.O_WITH_NAMES;
+ }
+ final RList attributes= ((io.flags & RObjectFactory.F_WITH_ATTR) != 0) ? getAttributes() : null;
+ if (attributes != null) {
+ options |= RObjectFactory.O_WITH_ATTR;
+ }
+ io.writeInt(options);
+ //-- special attributes
+ if ((options & RObjectFactory.O_CLASS_NAME) != 0) {
+ io.writeString(this.className1);
+ }
+ io.writeVULong((byte) (options & RObjectFactory.O_LENGTHGRADE_MASK), this.length);
+ if ((options & RObjectFactory.O_WITH_NAMES) != 0) {
+ factory.writeNames(this.namesAttribute, io);
+ }
+ //-- data
+ factory.writeStore(this.data, io);
+ // attributes
+ if ((options & RObjectFactory.O_WITH_ATTR) != 0) {
+ factory.writeAttributeList(attributes, io);
+ }
+ }
+
+
+ @Override
+ public byte getRObjectType() {
+ return TYPE_VECTOR;
+ }
+
+ @Override
+ public String getRClassName() {
+ return this.className1;
+ }
+
+ @Override
+ public long getLength() {
+ return this.length;
+ }
+
+ @Override
+ public RStore<?> getNames() {
+ return this.namesAttribute;
+ }
+
+
+ @Override
+ public TData getData() {
+ return this.data;
+ }
+
+
+ public void setData(final TData data) {
+ this.data= data;
+ }
+
+ public void insert(final int idx) {
+ ((RDataResizeExtension<?>) this.data).insertNA(idx);
+ this.length++;
+ }
+
+ public void remove(final int idx) {
+ ((RDataResizeExtension<?>) this.data).remove(idx);
+ this.length--;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RObject type=RVector, class=").append(getRClassName());
+ sb.append("\n\tlength=").append(getLength());
+ sb.append("\n\tdata: ");
+ sb.append(this.data.toString());
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/SimpleRList.java b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/SimpleRList.java
new file mode 100644
index 0000000..88f4ff1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.data/src/org/eclipse/statet/rj/data/impl/SimpleRList.java
@@ -0,0 +1,57 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.data.impl;
+
+import org.eclipse.statet.rj.data.RCharacterStore;
+
+
+public class SimpleRList<T> {
+
+
+ private final RCharacter32Store names;
+ private final T[] values;
+
+
+ public SimpleRList(final T[] values, final RCharacter32Store names) {
+ this.names= names;
+ this.values= values;
+ }
+
+
+ public int getLength() {
+ return this.names.length();
+ }
+
+ public RCharacterStore getNames() {
+ return this.names;
+ }
+
+ public String getName(final int idx) {
+ return this.names.get(idx);
+ }
+
+ public T get(final int idx) {
+ return this.values[idx];
+ }
+
+ public T get(final String name) {
+ final int idx= this.names.indexOf(name, 0);
+ if (idx >= 0) {
+ return this.values[idx];
+ }
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.classpath b/core/org.eclipse.statet.rj.server.remotetools/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.gitignore b/core/org.eclipse.statet.rj.server.remotetools/.gitignore
new file mode 100644
index 0000000..ef319c8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.gitignore
@@ -0,0 +1,3 @@
+/bin
+/binShaj
+/target
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.project b/core/org.eclipse.statet.rj.server.remotetools/.project
new file mode 100644
index 0000000..988eb46
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.server.remotetools</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.server.remotetools/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.server.remotetools/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..fc1cbdc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.server.remotetools
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Server - Remote Tools
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)"
diff --git a/core/org.eclipse.statet.rj.server.remotetools/about.html b/core/org.eclipse.statet.rj.server.remotetools/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.server.remotetools/about_files/LICENSE.txt b/core/org.eclipse.statet.rj.server.remotetools/about_files/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/about_files/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/core/org.eclipse.statet.rj.server.remotetools/build.properties b/core/org.eclipse.statet.rj.server.remotetools/build.properties
new file mode 100644
index 0000000..3fac0f6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/build.properties
@@ -0,0 +1,12 @@
+source..= srcShaj/
+output..= binShaj/
+javacDefaultEncoding..= UTF-8
+
+bin.includes = META-INF/,\
+ about.html,\
+ about_files/,\
+ startup.sh,\
+ startup.cmd,\
+ startup.ps1,\
+ security.policy
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.server.remotetools/security.policy b/core/org.eclipse.statet.rj.server.remotetools/security.policy
new file mode 100644
index 0000000..6e902c1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/security.policy
@@ -0,0 +1,7 @@
+grant codeBase "file:${{java.ext.dirs}}/*" {
+ permission java.security.AllPermission;
+};
+
+grant {
+ permission java.security.AllPermission;
+};
diff --git a/core/org.eclipse.statet.rj.server.remotetools/startup.cmd b/core/org.eclipse.statet.rj.server.remotetools/startup.cmd
new file mode 100644
index 0000000..f76decb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/startup.cmd
@@ -0,0 +1,411 @@
+echo off
+
+rem #=============================================================================#
+rem # Copyright (c) 2009, 2017 Stephan Wahlbrink and others.
+rem #
+rem # This program and the accompanying materials are made available under the
+rem # terms of the Eclipse Public License 2.0 which is available at
+rem # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+rem # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+rem #
+rem # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+rem #
+rem # Contributors:
+rem # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+rem #=============================================================================#
+
+
+rem ##
+rem # Windows batch script to start R server (for StatET)
+rem ##
+rem # Usually you have to change only the CONFIG sections. You should set at least:
+rem # R_HOME
+rem # JAVA_HOME
+rem # Depending on the system configuration, it can be required to set:
+rem # S_HOSTADDRESS
+rem #
+rem # The authentication is set to 'fx' (method using SSH) by default.
+rem ##
+rem # Usage of this script:
+rem # startup.cmd <address> [options]
+rem # startup.cmd <name> [options]
+rem # It starts the R server asynchronously in background by default.
+rem # <address> the complete RMI-address
+rem # <name> the session name only (the hostname
+rem # should be set in this file)
+rem # Options:
+rem # -wd=<working directory> initial R working directory
+rem # -debug enables debug output and
+rem # runs R in foreground
+rem #
+rem # Note: This script does not start an RMI registry! You have to launch it
+rem # as system daemon or manually (see Java documentation), e.g. by:
+rem # $JAVA_HOME/bin/rmiregistry.exe
+rem ##
+rem # Author: Stephan Wahlbrink <sw@wahlbrink.eu>
+rem ###############################################################################
+
+rem ###############################################################################
+rem # SCRIPT - INIT / READING PARAMETERS ##########################################
+rem ###############################################################################
+if [ -z "$1" ]
+then
+ echo Missing address or name for R server
+ exit -1
+fi
+set ADDRESS=$1
+set S_NAME=`basename $ADDRESS`
+set S_HOSTADDRESS=
+set S_REGISTRYPORT=
+if [ "$ADDRESS" != "$S_NAME" ]
+then
+ set S_HOSTADDRESS=`expr "$ADDRESS" : "[^/]*\/\/\([^:/]*\).*"`
+ set S_REGISTRYPORT=`expr "$ADDRESS" : "[^/]*\/\/[^:/]*:\([0-9]\+\)\/.*"`
+fi
+shift
+set WD=~
+set SCRIPT=`readlink -f "$0"`
+
+until [ -z "$1" ] # Until all parameters used up
+do
+ case "$1" in
+ -wd=*)
+ WD=${1##-wd=}
+ ;;
+# -host=*)
+# S_HOSTADDRESS=${1##-host=}
+# ;;
+ -debug*)
+ DEBUG=1
+ echo Debug mode enabled
+ ;;
+ -dev*)
+ DEV=1
+ echo Development mode enabled
+ ;;
+ *)
+ echo Unknown parameter: $1
+ ;;
+ esac
+ shift
+done
+rem ###############################################################################
+
+rem ###############################################################################
+rem # CONFIG - SYSTEM SETTINGS ####################################################
+rem ###############################################################################
+rem # Configure the startup in the following sections
+
+rem ###############################################################################
+rem # Required system specific settings
+rem #
+rem # Set the path to home of R and Java.
+rem # If parts of the R installation (e.g. the documentation) are located in not
+rem # sub-directories of R home, it is often required to set additional variables
+rem # specifying the several installation locations (see example).
+rem #
+rem # Example:
+rem # R_HOME=/usr/lib/R
+rem # R_DOC_DIR=/usr/share/doc/R
+rem # R_SHARE_DIR=/usr/share/R
+rem # R_INCLUDE_DIR=/usr/include/R
+rem # R_LIBS_SITE=/usr/local/lib/R/site-library
+rem # JAVA_HOME=/usr/lib/jvm/java-6-sun
+
+set R_HOME=
+set JAVA_HOME=
+
+rem #rem ##############################################################################
+rem # Set the home and work directory of this R server.
+rem # The home must contain the jar files of this server, if this file is in this
+rem # directory, you don't have to change the value.
+rem # The working directory is for files like log files
+rem ##
+rem # Example:
+rem # RJS_HOME=`dirname "$SCRIPT"`
+rem # RJS_WORK=~/.RJServer
+
+set RJS_HOME=`dirname "$SCRIPT"`
+set RJS_WORK=~/.RJServer
+
+rem ###############################################################################
+rem # Set explicitly the hostname and port you want to use to access the RMI
+rem # registry/R server.
+rem # It is recommended to use the IP address instead of a name.
+rem # By default, the hostname is extracted form the specified RMI address
+rem # (script parameter). Nevertheless there are some reasons to set it explicitly
+rem # here, e.g.:
+rem # - For SSH tunnel connections '127.0.0.1' (localhost) is sufficient;
+rem # recommend, if no other network connections are used; and required if the
+rem # public IP address is blocked by the firewall.
+rem # - To make sure that the correct IP address is set even the hostname is
+rem # used in the RMI address.
+rem ##
+rem # Usage:
+rem # S_HOSTADDRESS=<ip or hostname>
+rem # S_REGISTRYPORT=<port of rmi-registry>
+rem # Example:
+rem # S_HOSTADDRESS=192.168.1.80
+
+rem set S_HOSTADDRESS=
+
+
+rem #rem ##############################################################################
+# Add additional java options here
+rem ##
+rem # Example:
+rem # JAVA_OPTS="-server -Dorg.eclipse.statet.rj.rmi.disableSocketFactory=true"
+
+set JAVA_OPTS="-server"
+set JAVA_OPTS_LIB=
+
+
+rem ###############################################################################
+rem # CONFIG - AUTHENTICATION METHODS #############################################
+rem ###############################################################################
+rem # You must specify the method (exactly one) to use for authentication when
+rem # clients wants to connect to the R.
+rem # There are several methods available. The methods provided by default
+rem # are described in the following subsections. To change the method uncomment
+rem # the lines of method you want to use and comment the previous AUTH definition.
+rem ##
+rem # General usage:
+rem # RJ parm: -auth=<method-id>[:<config>]
+rem # -auth=<classname>[:<config>]
+rem #
+rem # <config> option depends on the selected method
+
+rem ###############################################################################
+rem # Authentication method: disabled / 'none'
+rem #
+rem # Disables authentication. Anybody can connect to R. Use it only if you are in
+rem # a secure environment! All users can connect to R get full user rights!
+rem ##
+rem # General usage:
+rem # RJ param: -auth=none
+rem #
+rem # Script Usage:
+rem # AUTH=none
+
+rem set AUTH=none
+
+rem ###############################################################################
+rem # Authentication method: password file / 'name-pass'
+rem #
+rem # Authentication using loginname-password combination.
+rem ##
+rem # General usage:
+rem # RJ Param: -auth=name-pass:file=<passwordfile>
+rem #
+rem # Script usage:
+rem # AUTH=name-pass:file
+rem # AUTH_PW_FILE=~/.RJServer/logins
+rem #
+rem # <passwordfile> is the path to a property file with
+rem # pairs of loginname and password, for example:
+rem # myname=mypassword
+rem # Make sure that only authorized users can read this file!
+
+rem set AUTH=name-pass:file
+rem set AUTH_PW_FILE=~/.RJServer/logins
+
+rem ###############################################################################
+rem # Authentication method: local user account / 'local-shaj'
+rem #
+rem # Authentication using your local loginname-password combination (PAM).
+rem # The 'Shaj' library is required for this method. It is provided in sources and
+rem # binary form for several platforms. If no binary match your environment, you
+rem # have to build it for your system. You find the files inside the folder
+rem # shaj
+rem # of this remotetools package.
+rem ##
+rem # General Usage:
+rem # RJ Param: -auth=local-shaj
+rem # Java Prop: java.library.path=<folder of library>
+rem #
+rem # Script Usage:
+rem # AUTH=local-shaj
+rem # AUTH_SHAJ_LD_DIR=<folder of library>
+rem # Example:
+rem # AUTH=local-shaj
+rem # AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/linux-x64"
+
+rem set AUTH=local-shaj
+rem set AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/<platform>"
+
+rem ###############################################################################
+rem # Authentication method: ssh / 'fx' (exchange over file)
+rem #
+rem # Authentication for automatic startup (via ssh by StatET).
+rem ##
+rem # General Usage:
+rem # RJ Param: -auth=fx:file=<keyfile>
+rem #
+rem # Script Usage:
+rem # AUTH=fx:file
+rem # AUTH_FX_FILE=<keyfile>
+rem # AUTH_FX_USER=$USER
+rem # AUTH_FX_MASK=600
+rem #
+rem # <keyfile> a (empty). The fs permission to edit the files represents the
+rem # right to login into R, so:
+rem # The file must be writable for authorized user only!
+rem # If the script setup is used, the files is created automatically and
+rem # the permission is set according to AUTH_FX_USER and AUTH_FX_MASK
+
+set AUTH=fx:file
+set AUTH_FX_FILE="$RJS_WORK/session-$S_NAME.lock"
+set AUTH_FX_USER=$USER
+set AUTH_FX_MASK=600
+
+
+rem ###############################################################################
+rem # SCRIPT - STARTUP SERVER #####################################################
+rem ###############################################################################
+rem # Usually you don't have to edit the lines below
+
+rem set $JAVA_HOME/bin/rmiregistry &
+
+mkdir -p "$RJS_WORK"
+
+rem ## Final RMI address
+if [ -n "$S_HOSTADDRESS" ]
+then
+ set S_ADDRESS="//$S_HOSTADDRESS"
+ if [ -n "$S_REGISTRYPORT" ]
+ then
+ set S_ADDRESS="$S_ADDRESS:$S_REGISTRYPORT"
+ fi
+ set S_ADDRESS="$S_ADDRESS/$S_NAME"
+else
+ set S_ADDRESS="//$S_NAME"
+fi
+
+rem ## Finish auth configuration
+if [ "$FORCE_AUTH" ]
+then
+ set AUTH="$FORCE_AUTH"
+fi
+
+if [ "$AUTH" = "name-pass:file" ]
+then
+ set AUTH="name-pass:file=$AUTH_PW_FILE"
+fi
+
+if [ "$AUTH" = "local-shaj" ]
+then
+ set AUTH=local-shaj
+ set JAVA_OPTS_LIB="$JAVA_OPTS_LIB:$AUTH_SHAJ_LD_DIR"
+ set JAVA_CP="$JAVA_CP:$RJS_HOME/shaj/auth.jar"
+fi
+
+if [ "$AUTH" = "fx:file" ]
+then
+ set AUTH="fx:file=$AUTH_FX_FILE"
+ set AUTH_FX_FOLDER=`dirname "$AUTH_FX_FILE"`
+ mkdir -p "$AUTH_FX_FOLDER"
+ echo "00000000" > "$AUTH_FX_FILE"
+ if [ $AUTH_FX_USER ]
+ then
+ chown $AUTH_FX_USER "$AUTH_FX_FILE"
+ fi
+ if [ $AUTH_FX_MASK ]
+ then
+ chmod $AUTH_FX_MASK "$AUTH_FX_FILE"
+ fi
+fi
+
+OPTS="-auth=$AUTH"
+if [ $DEBUG ]
+then
+ OPTS="$OPTS -verbose"
+fi
+
+rem ## Java config
+if [ $DEV ]
+then
+ set JAVA_CP="$RJS_HOME/../org.eclipse.statet.rj.server/bin:$RJS_HOME/../org.eclipse.statet.rj.data/bin:$RJS_HOME/bin:$RJS_HOME/binShaj"
+ set RMI_BASE="file://$RJS_HOME/../org.eclipse.statet.rj.server/bin"
+ set RJAVA_CP=
+else
+ set JAVA_CP="$RJS_HOME/org.eclipse.statet.rj.server.jar:$RJS_HOME/org.eclipse.statet.rj.data.jar:$JAVA_CP"
+ set RMI_BASE="file://$RJS_HOME/org.eclipse.statet.rj.server.jar"
+ set RJAVA_CP=
+fi
+
+set JAVA_OPTS="$JAVA_OPTS -Djava.security.policy=$RJS_HOME/security.policy -Djava.rmi.server.codebase=$RMI_BASE"
+if [ -n "$S_HOSTADDRESS" ]
+then
+ set JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=$S_HOSTADDRESS"
+fi
+if [ -n "$JAVA_OPTS_LIB" ]
+then
+ set JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$JAVA_OPTS_LIB"
+fi
+if [ -n "$RJAVA_CP" ]
+then
+ set JAVA_OPTS="$JAVA_OPTS -Drjava.class.path=$RJAVA_CP"
+fi
+
+rem ## Other environment
+set PATH=$R_HOME/bin:$PATH
+set LD_LIBRARY_PATH=$R_HOME/lib
+
+export PATH
+export LD_LIBRARY_PATH
+export JAVA_HOME
+export R_HOME
+export R_LIBS
+export R_LIBS_USER
+export R_LIBS_SITE
+export R_DOC_DIR
+export R_SHARE_DIR
+export R_INCLUDE_DIR
+export LC_ALL
+
+cd "$WD"
+
+set START_EXEC="$JAVA_HOME/bin/java -cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl start $S_ADDRESS $OPTS"
+rem echo $START_EXEC
+
+if [ $DEBUG ]
+then
+ echo S_HOSTADDRESS = $S_HOSTADDRESS
+ echo S_REGISTRYPORT = $S_REGISTRYPORT
+ echo PATH = $PATH
+ echo LD_LIBRARY_PATH = $LD_LIBRARY_PATH
+ echo R_HOME = $R_HOME
+ echo JAVA_HOME = $JAVA_HOME
+ echo CLASSPATH = $JAVA_CP
+ echo JAVA_OPTIONS = $JAVA_OPTS
+ echo AUTH = $AUTH
+
+ rem # Start server directly
+ $START_EXEC
+ START_EXIT=$?
+ START_PID=$!
+ exit $START_EXIT
+else
+ rem # First check if running or dead server is already bound
+ CLEAN_EXEC="$JAVA_HOME/bin/java -cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl clean $S_ADDRESS"
+ $CLEAN_EXEC
+ CLEAN_EXIT=$?
+ if [ $CLEAN_EXIT -ne 0 ]
+ then
+ echo "Check and cleanup of old server failed (CODE=$CLEAN_EXIT), cancelling startup."
+ exit $CLEAN_EXIT
+ fi
+
+ rem # Start server detached
+ nohup $START_EXEC > "$RJS_WORK/session-$S_NAME.out" 2>&1 < /dev/null &
+ START_EXIT=$?
+ START_PID=$!
+ if [ $START_EXIT -eq 0 ]
+ then
+ echo "Started server in background (PID=$START_PID)."
+ exit 0
+ else
+ echo "Startup failed"
+ exit $START_EXIT
+ fi
+fi
diff --git a/core/org.eclipse.statet.rj.server.remotetools/startup.ps1 b/core/org.eclipse.statet.rj.server.remotetools/startup.ps1
new file mode 100644
index 0000000..93c4757
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/startup.ps1
@@ -0,0 +1,420 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+##
+# Shell (PowerShell) script to start R server (for StatET)
+##
+# Usually you have to change only the CONFIG sections. You should set at least:
+# R_HOME
+# JAVA_HOME
+# Depending on the system configuration, it can be required to set:
+# S_HOSTADDRESS
+#
+# The authentication is set to 'none' by default.
+##
+# Usage of this script:
+# startup.sh <address> [options]
+# startup.sh <name> [options]
+# It starts the R server asynchronously in background by default.
+# <address> the complete RMI-address
+# <name> the session name only (the hostname
+# should be set in this file)
+# Options:
+# -wd=<working directory> initial R working directory
+# -debug enables debug output and
+# runs R in foreground
+#
+# Note: This script does not start an RMI registry! You have to launch it
+# as system daemon or manually (see Java documentation), e.g. by:
+# %JAVA_HOME%/bin/rmiregistry.exe -J-Djava.rmi.server.codebase=file:///<path to file org.eclipse.statet.rj.server.jar>
+# or in a detached process (not official):
+# %JAVA_HOME%/bin/javaw.exe -Djava.rmi.server.codebase=file:///<path to file org.eclipse.statet.rj.server.jar> sun.rmi.registry.RegistryImpl
+##
+# Author: Stephan Wahlbrink <sw@wahlbrink.eu>
+###############################################################################
+
+###############################################################################
+# SCRIPT - INIT / READING PARAMETERS ##########################################
+###############################################################################
+param([String] $ADDRESS)
+
+if ([String]::IsNullOrEmpty("$ADDRESS"))
+{
+ echo "Missing address or name for R server"
+ exit -1
+}
+
+$S_NAME=$ADDRESS -replace '.*\/([^/]+)$', '$1'
+$S_HOSTADDRESS=""
+$S_REGISTRYPORT=""
+if ( $ADDRESS -ne $S_NAME )
+{
+ $S_HOSTADDRESS=$ADDRESS -replace '[^/]*\/\/([^:/]*).*', '$1'
+ $S_REGISTRYPORT=$ADDRESS -replace '[^/]*\/\/[^:/]*:?([0-9]*)\/.*', '$1'
+}
+
+$WD=$HOME
+$SCRIPT=$MyInvocation.MyCommand.Path
+
+foreach ($1 in $Args) {
+ switch -wildcard ("$1") {
+ "-wd=*" {
+ $WD=$1.Substring(4)
+ }
+# "-host=*" {
+# $S_HOSTADDRESS=$1.Substring(6)
+# }
+ "-debug*" {
+ $DEBUG=1
+ echo "Debug mode enabled"
+ }
+ "-dev*" {
+ $DEV=1
+ echo "Development mode enabled"
+ }
+ default {
+ echo "Unknown parameter: $1"
+ }
+ }
+}
+###############################################################################
+
+###############################################################################
+# CONFIG - SYSTEM SETTINGS ####################################################
+###############################################################################
+# Configure the startup in the following sections
+
+###############################################################################
+# Required system specific settings
+#
+# Set the path to home of R and Java.
+# If parts of the R installation (e.g. the documentation) are located in not
+# sub-directories of R home, it is often required to set additional variables
+# specifying the several installation locations (see example).
+#
+# Example:
+# R_HOME="/usr/lib/R"
+# R_ARCH="/x64"
+# R_DOC_DIR="/usr/share/doc/R"
+# R_SHARE_DIR="/usr/share/R"
+# R_INCLUDE_DIR="/usr/include/R"
+# R_LIBS_SITE="/usr/local/lib/R/site-library"
+# JAVA_HOME="/usr/lib/jvm/java-6-sun"
+
+$R_HOME=""
+$R_ARCH="/x64"
+$JAVA_HOME=""
+
+###############################################################################
+# Set the home and work directory of this R server.
+# The home must contain the jar files of this server, if this file is in this
+# directory, you don't have to change the value.
+# The working directory is for files like log files
+##
+# Example:
+# RJS_HOME=`dirname "$SCRIPT"`
+# RJS_WORK="~/.RJServer"
+
+$RJS_HOME=Split-Path -Path $SCRIPT -Parent
+$RJS_WORK="$HOME/.RJServer"
+
+###############################################################################
+# Set explicitly the hostname and port you want to use to access the RMI
+# registry/R server.
+# It is recommended to use the IP address instead of a name.
+# By default, the hostname is extracted form the specified RMI address
+# (script parameter). Nevertheless there are some reasons to set it explicitly
+# here, e.g.:
+# - For SSH tunnel connections '127.0.0.1' (localhost) is sufficient;
+# recommend, if no other network connections are used; and required if the
+# public IP address is blocked by the firewall.
+# - To make sure that the correct IP address is set even the hostname is
+# used in the RMI address.
+##
+# Usage:
+# S_HOSTADDRESS=<ip or hostname>
+# S_REGISTRYPORT=<port of rmi-registry>
+# Example:
+# S_HOSTADDRESS=192.168.1.80
+
+#$S_HOSTADDRESS=""
+
+
+###############################################################################
+# Add additional java options here
+##
+# Example:
+# JAVA_OPTS="-server -Dorg.eclipse.statet.rj.rmi.disableSocketFactory=true"
+
+$JAVA_OPTS=@("-server")
+$JAVA_OPTS_LIB=@()
+
+
+###############################################################################
+# CONFIG - AUTHENTICATION METHODS #############################################
+###############################################################################
+# You must specify the method (exactly one) to use for authentication when
+# clients wants to connect to the R.
+# There are several methods available. The methods provided by default
+# are described in the following subsections. To change the method uncomment
+# the lines of method you want to use and comment the previous AUTH definition.
+##
+# General usage:
+# RJ parm: -auth=<method-id>[:<config>]
+# -auth=<classname>[:<config>]
+#
+# <config> option depends on the selected method
+
+###############################################################################
+# Authentication method: disabled / 'none'
+#
+# Disables authentication. Anybody can connect to R. Use it only if you are in
+# a secure environment! All users can connect to R get full user rights!
+##
+# General usage:
+# RJ param: -auth=none
+#
+# Script Usage:
+# AUTH=none
+
+$AUTH="none"
+
+###############################################################################
+# Authentication method: password file / 'name-pass'
+#
+# Authentication using loginname-password combination.
+##
+# General usage:
+# RJ Param: -auth=name-pass:file=<passwordfile>
+#
+# Script usage:
+# AUTH="name-pass:file"
+# AUTH_PW_FILE="~/.RJServer/logins"
+#
+# <passwordfile> is the path to a property file with
+# pairs of loginname and password, for example:
+# myname=mypassword
+# Make sure that only authorized users can read this file!
+
+#$AUTH="name-pass:file"
+#$AUTH_PW_FILE="$HOME/.RJServer/logins"
+
+###############################################################################
+# Authentication method: local user account / 'local-shaj'
+#
+# Authentication using your local loginname-password combination (PAM).
+# The 'Shaj' library is required for this method. It is provided in sources and
+# binary form for several platforms. If no binary match your environment, you
+# have to build it for your system. You find the files inside the folder
+# shaj
+# of this remotetools package.
+##
+# General Usage:
+# RJ Param: -auth=local-shaj
+# Java Prop: java.library.path=<folder of library>
+#
+# Script Usage:
+# AUTH="local-shaj"
+# AUTH_SHAJ_LD_DIR="<folder of library>"
+# Example:
+# AUTH=local-shaj
+# AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/linux-x64"
+
+#$AUTH="local-shaj"
+#$AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/<platform>"
+
+###############################################################################
+# Authentication method: ssh / 'fx' (exchange over file)
+#
+# Authentication for automatic startup (via ssh by StatET).
+##
+# General Usage:
+# RJ Param: -auth=fx:file=<keyfile>
+#
+# Script Usage:
+# AUTH="fx:file"
+# AUTH_FX_FILE="<keyfile>"
+# AUTH_FX_USER=$USER
+# AUTH_FX_MASK="600"
+#
+# <keyfile> a (empty). The fs permission to edit the files represents the
+# right to login into R, so:
+# The file must be writable for authorized user only!
+# If the script setup is used, the files is created automatically and
+# the permission is set according to AUTH_FX_USER and AUTH_FX_MASK
+
+#$AUTH="fx:file"
+$AUTH_FX_FILE="$RJS_WORK/session-$S_NAME.lock"
+$AUTH_FX_USER=[System.Security.Principal.WindowsIdentity]::GetCurrent().Name
+$AUTH_FX_MASK=new-object System.Security.AccessControl.FileSystemAccessRule $AUTH_FX_USER, 'FullControl', 'Allow'
+
+
+###############################################################################
+# SCRIPT - STARTUP SERVER #####################################################
+###############################################################################
+# Usually you don't have to edit the lines below
+$PATH_SEP=";"
+
+#$JAVA_HOME/bin/rmiregistry &
+
+if ( !( Test-Path "$RJS_WORK" ) ) {
+ mkdir -p "$RJS_WORK"
+}
+
+## Final RMI address
+if ( $S_HOSTADDRESS )
+{
+ $S_ADDRESS="//$S_HOSTADDRESS"
+ if ( $S_REGISTRYPORT ) {
+ $S_ADDRESS="$S_ADDRESS:$S_REGISTRYPORT"
+ }
+ $S_ADDRESS="$S_ADDRESS/$S_NAME"
+} else {
+ $S_ADDRESS="///$S_NAME"
+}
+
+## Finish auth configuration
+if ( $FORCE_AUTH )
+{
+ $AUTH="$FORCE_AUTH"
+}
+
+if ( $AUTH -eq "name-pass:file" )
+{
+ $AUTH="name-pass:file=$AUTH_PW_FILE"
+}
+
+if ( $AUTH -eq "local-shaj" )
+{
+ $AUTH="local-shaj"
+ $JAVA_OPTS_LIB="$JAVA_OPTS_LIB$PATH_SEP$AUTH_SHAJ_LD_DIR"
+ $JAVA_CP="$JAVA_CP$PATH_SEP$RJS_HOME/shaj/auth.jar"
+}
+
+if ( "$AUTH" -eq "fx:file" )
+{
+ $AUTH="fx:file=$AUTH_FX_FILE"
+ $AUTH_FX_FOLDER=Split-Path -Path $AUTH_FX_FILE -Parent
+ mkdir -p "$AUTH_FX_FOLDER"
+ echo "00000000" > "$AUTH_FX_FILE"
+
+ $ACL=Get-Acl "$AUTH_FX_FILE"
+ $ACL.SetAccessRule($AUTH_FX_MASK)
+ #$SystemAccessRule = new-object System.Security.AccessControl.FileSystemAccessRule 'SYSTEM', 'FullControl', 'Allow'
+ #$ACL.SetAccessRule($SystemAccessRule)
+ $ACL.SetAccessRuleProtection($True, $False)
+ Set-Acl "$AUTH_FX_FILE" $ACL
+}
+
+$OPTS=@("-auth=$AUTH")
+if ( $DEBUG )
+{
+ $OPTS+="-verbose"
+}
+
+## Java config
+$JAVA_EXE="$JAVA_HOME/bin/java.exe"
+if ( $DEV )
+{
+ $JAVA_CP="$RJS_HOME/../org.eclipse.statet.rj.server/bin$PATH_SEP$RJS_HOME/../org.eclipse.statet.rj.data/bin$PATH_SEP$RJS_HOME/bin$PATH_SEP$RJS_HOME/binShaj"
+ $RMI_BASE="file://$RJS_HOME/../org.eclipse.statet.rj.server/bin"
+ $RJAVA_CP=""
+} else {
+ $JAVA_CP="$RJS_HOME/org.eclipse.statet.rj.server.jar$PATH_SEP$RJS_HOME/org.eclipse.statet.rj.data.jar$PATH_SEP$JAVA_CP"
+ $RMI_BASE="file://$RJS_HOME/org.eclipse.statet.rj.server.jar"
+ $RJAVA_CP=""
+}
+
+$JAVA_OPTS+="-Djava.security.policy=$RJS_HOME/security.policy"
+$JAVA_OPTS+="-Djava.rmi.server.codebase=$RMI_BASE"
+if ( $S_HOSTADDRESS )
+{
+ $JAVA_OPTS+="-Djava.rmi.server.hostname=$S_HOSTADDRESS"
+}
+if ( $JAVA_OPTS_LIB )
+{
+ $JAVA_OPTS+="-Djava.library.path=$JAVA_OPTS_LIB"
+}
+if ( $RJAVA_CP )
+{
+ $JAVA_OPTS+="-Drjava.class.path=$RJAVA_CP"
+}
+
+## Other environment
+$PATH="$R_HOME/bin$R_ARCH$PATH_SEP$Env:PATH"
+$LD_LIBRARY_PATH="$R_HOME/lib"
+
+$env:PATH = $PATH
+$env:JAVA_HOME = $JAVA_HOME
+$env:R_HOME = $R_HOME
+$env:R_ARCH = $R_ARCH
+$env:R_LIBS = $R_LIBS
+$env:R_LIBS_USER = $R_LIBS_USER
+$env:R_LIBS_SITE = $R_LIBS_SITE
+$env:R_DOC_DIR = $R_DOC_DIR
+$env:R_SHARE_DIR = $R_SHARE_DIR
+$env:R_INCLUDE_DIR = $R_INCLUDE_DIR
+$env:LC_ALL = $LC_ALL
+
+cd $WD
+
+$START_ARGS=@('-cp',$JAVA_CP)+$JAVA_OPTS+@('org.eclipse.statet.rj.server.RMIServerControl','start',$S_ADDRESS)+$OPTS
+#echo "$JAVA_EXE $START_ARGS"
+
+if ( $DEBUG )
+{
+ echo "S_HOSTADDRESS = $S_HOSTADDRESS"
+ echo "S_REGISTRYPORT = $S_REGISTRY_PORT"
+ echo "PATH = $PATH"
+ echo "LD_LIBRARY_PATH = $LD_LIBRARY_PATH"
+ echo "R_HOME = $R_HOME"
+ echo "R_ARCH = $R_ARCH"
+ echo "JAVA_HOME = $JAVA_HOME"
+ echo "JAVA_EXE = $JAVA_EXE"
+ echo "CLASSPATH = $JAVA_CP"
+ echo "JAVA_OPTIONS = $JAVA_OPTS"
+ echo "AUTH = $AUTH"
+
+ # Start server directly
+ & $JAVA_EXE $START_ARGS
+ $START_EXIT=$LastExitCode
+ exit $START_EXIT
+} else {
+ # First check if running or dead server is already bound
+ $CLEAN_ARGS=@('-cp',$JAVA_CP)+$JAVA_OPTS+@('org.eclipse.statet.rj.server.RMIServerControl','clean',$S_ADDRESS)
+ & $JAVA_EXE $CLEAN_ARGS
+ $CLEAN_EXIT=$LastExitcode
+ if ( $CLEAN_EXIT -ne 0 )
+ {
+ echo "Check and cleanup of old server failed (CODE=$CLEAN_EXIT), cancelling startup."
+ exit $CLEAN_EXIT
+ }
+
+ # Start server detached
+ $JAVA_EXE="$JAVA_HOME/bin/javaw.exe"
+ $START_PROCESS=Start-Process $JAVA_EXE -NoNewWindow -PassThru`
+ -RedirectStandardOutput "$RJS_WORK/session-$S_NAME.out" `
+ -RedirectStandardError "$RJS_WORK/session-$S_NAME.err" `
+ $START_ARGS
+ #$START_EXIT=
+ $START_PID=$START_PROCESS.Id
+ if ( ! $START_PROCESS.HasExited )
+ {
+ echo "Started server in background (PID=$START_PID)."
+ exit 0
+ } else {
+ echo "Startup failed"
+ exit -1
+ }
+}
diff --git a/core/org.eclipse.statet.rj.server.remotetools/startup.sh b/core/org.eclipse.statet.rj.server.remotetools/startup.sh
new file mode 100644
index 0000000..04273e4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.remotetools/startup.sh
@@ -0,0 +1,464 @@
+#!/bin/sh
+
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+##
+# Shell script to start R server (for StatET)
+##
+# Usually you have to change only the CONFIG sections. You should set at least:
+# R_HOME
+# JAVA_HOME
+# Depending on the system configuration, it can be required to set:
+# S_HOSTADDRESS
+#
+# The authentication is set to 'fx' (method using SSH) by default.
+##
+# Usage of this script:
+# startup.sh <address> [options]
+# startup.sh <name> [options]
+# It starts the R server asynchronously in background by default.
+# <address> the complete RMI-address
+# <name> the session name only (the hostname
+# should be set in this file)
+# Options:
+# -wd=<working directory> initial R working directory
+# -debug enables debug output and
+# runs R in foreground
+#
+# Note: This script does not start an RMI registry! You have to launch it
+# as system daemon or manually (see Java documentation), e.g. by:
+# $JAVA_HOME/bin/rmiregistry -J-Djava.rmi.server.codebase=file:///<path to file org.eclipse.statet.rj.server.jar> &
+# or if appropriate by uncommenting the section "Start registry" in this script.
+##
+# Author: Stephan Wahlbrink <sw@wahlbrink.eu>
+###############################################################################
+
+###############################################################################
+# SCRIPT - INIT / READING PARAMETERS ##########################################
+###############################################################################
+OS=`uname | tr '[:upper:]' '[:lower:]'`
+case "$OS" in
+darwin)
+ C_READLINK=greadlink
+ LD_LIB_VAR="DYLD_LIBRARY_PATH"
+ LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
+ ;;
+*)
+ C_READLINK=readlink
+ LD_LIB_VAR="LD_LIBRARY_PATH"
+ LD_PRELOAD_VAR="LD_PRELOAD"
+ ;;
+esac
+
+if [ -z "$1" ]
+then
+ echo "Missing address or name for R server"
+ exit -1
+fi
+ADDRESS=$1
+S_NAME=`basename $ADDRESS`
+S_HOSTADDRESS=""
+S_REGISTRYPORT=""
+if [ "$ADDRESS" != "$S_NAME" ]
+then
+ S_HOSTADDRESS=`expr "$ADDRESS" : "[^/]*\/\/\([^:/]*\).*"`
+ S_REGISTRYPORT=`expr "$ADDRESS" : "[^/]*\/\/[^:/]*:\([0-9]\+\)\/.*"`
+fi
+shift
+WD=~
+SCRIPT=`$C_READLINK -f "$0"`
+
+until [ -z "$1" ]
+do
+ case "$1" in
+ -wd=*)
+ WD=${1##-wd=}
+ ;;
+# -host=*)
+# S_HOSTADDRESS=${1##-host=}
+# ;;
+ -debug*)
+ DEBUG=1
+ echo Debug mode enabled
+ ;;
+ -dev*)
+ DEV=1
+ echo Development mode enabled
+ ;;
+ *)
+ echo Unknown parameter: $1
+ ;;
+ esac
+ shift
+done
+###############################################################################
+
+###############################################################################
+# CONFIG - SYSTEM SETTINGS ####################################################
+###############################################################################
+# Configure the startup in the following sections
+
+###############################################################################
+# Required system specific settings
+#
+# Set the path to home of R and Java.
+# If parts of the R installation (e.g. the documentation) are located in not
+# sub-directories of R home, it is often required to set additional variables
+# specifying the several installation locations (see example).
+#
+# Example:
+# R_HOME="/usr/lib/R"
+# R_ARCH="/x64"
+# R_DOC_DIR="/usr/share/doc/R"
+# R_SHARE_DIR="/usr/share/R"
+# R_INCLUDE_DIR="/usr/include/R"
+# R_LIBS_SITE="/usr/local/lib/R/site-library"
+# JAVA_HOME="/usr/lib/jvm/java-6-sun"
+
+R_HOME=
+JAVA_HOME=
+
+###############################################################################
+# Set the home and work directory of this R server.
+# The home must contain the jar files of this server, if this file is in this
+# directory, you don't have to change the value.
+# The working directory is for files like log files
+##
+# Example:
+# RJS_HOME=`dirname "$SCRIPT"`
+# RJS_WORK="~/R/rj-consoleserver/work"
+
+RJS_HOME=`dirname "$SCRIPT"`
+RJS_WORK=~/.RJServer
+
+###############################################################################
+# Set explicitly the hostname and port you want to use to access the RMI
+# registry/R server.
+# It is recommended to use the IP address instead of a name.
+# By default, the hostname is extracted form the specified RMI address
+# (script parameter). Nevertheless there are some reasons to set it explicitly
+# here, e.g.:
+# - For SSH tunnel connections '127.0.0.1' (localhost) is sufficient;
+# recommend, if no other network connections are used; and required if the
+# public IP address is blocked by the firewall.
+# - To make sure that the correct IP address is set even the hostname is
+# used in the RMI address.
+##
+# Usage:
+# S_HOSTADDRESS=<ip or hostname>
+# S_REGISTRYPORT=<port of rmi-registry>
+# Example:
+# S_HOSTADDRESS=192.168.1.80
+
+#S_HOSTADDRESS=""
+
+
+###############################################################################
+# Add additional java options here
+##
+# Example:
+# JAVA_OPTS="-server -Djava.net.preferIPv4Stack=true"
+# JAVA_OPTS="-server -Dorg.eclipse.statet.rj.rmi.disableSocketFactory=true"
+
+JAVA_OPTS="-server"
+JAVA_OPTS_LIB=
+
+
+###############################################################################
+# CONFIG - AUTHENTICATION METHODS #############################################
+###############################################################################
+# You must specify the method (exactly one) to use for authentication when
+# clients wants to connect to the R.
+# There are several methods available. The methods provided by default
+# are described in the following subsections. To change the method uncomment
+# the lines of method you want to use and comment the previous AUTH definition.
+##
+# General usage:
+# RJ parm: -auth=<method-id>[:<config>]
+# -auth=<classname>[:<config>]
+#
+# <config> option depends on the selected method
+
+###############################################################################
+# Authentication method: disabled / 'none'
+#
+# Disables authentication. Anybody can connect to R. Use it only if you are in
+# a secure environment! All users can connect to R get full user rights!
+##
+# General usage:
+# RJ param: -auth=none
+#
+# Script Usage:
+# AUTH="none"
+
+#AUTH="none"
+
+###############################################################################
+# Authentication method: password file / 'name-pass'
+#
+# Authentication using loginname-password combination.
+##
+# General usage:
+# RJ Param: -auth=name-pass:file=<passwordfile>
+#
+# Script usage:
+# AUTH="name-pass:file"
+# AUTH_PW_FILE="~/.RJServer/logins"
+#
+# <passwordfile> is the path to a property file with
+# pairs of loginname and password, for example:
+# myname=mypassword
+# Make sure that only authorized users can read this file!
+
+#AUTH="name-pass:file"
+#AUTH_PW_FILE="~/.RJServer/logins"
+
+###############################################################################
+# Authentication method: local user account / 'local-shaj'
+#
+# Authentication using your local loginname-password combination (PAM).
+# The 'Shaj' library is required for this method. It is provided in sources and
+# binary form for several platforms. If no binary match your environment, you
+# have to build it for your system. You find the files inside the folder
+# shaj
+# of this remotetools package.
+##
+# General Usage:
+# RJ Param: -auth=local-shaj
+# Java Prop: java.library.path=<folder of library>
+#
+# Script Usage:
+# AUTH="local-shaj"
+# AUTH_SHAJ_LD_DIR="<folder of library>"
+# Example:
+# AUTH=local-shaj
+# AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/linux-x64"
+
+#AUTH="local-shaj"
+#AUTH_SHAJ_LD_DIR="$RJS_HOME/shaj/<platform>"
+
+###############################################################################
+# Authentication method: ssh / 'fx' (exchange over file)
+#
+# Authentication for automatic startup (via ssh by StatET).
+##
+# General Usage:
+# RJ Param: -auth=fx:file=<keyfile>
+#
+# Script Usage:
+# AUTH="fx:file"
+# AUTH_FX_FILE="<keyfile>"
+# AUTH_FX_USER=$USER
+# AUTH_FX_MASK="600"
+#
+# <keyfile> a (empty). The fs permission to edit the files represents the
+# right to login into R, so:
+# The file must be writable for authorized user only!
+# If the script setup is used, the files is created automatically and
+# the permission is set according to AUTH_FX_USER and AUTH_FX_MASK
+
+AUTH="fx:file"
+AUTH_FX_FILE="$RJS_WORK/session-$S_NAME.lock"
+AUTH_FX_USER=$USER
+AUTH_FX_MASK=600
+
+
+###############################################################################
+# SCRIPT - STARTUP SERVER #####################################################
+###############################################################################
+# Usually you don't have to edit the lines below
+PATH_SEP=":"
+
+mkdir -p "$RJS_WORK"
+
+## Final RMI address
+if [ -n "$S_HOSTADDRESS" ]
+then
+ S_ADDRESS="//$S_HOSTADDRESS"
+ if [ -n "$S_REGISTRYPORT" ]
+ then
+ S_ADDRESS="$S_ADDRESS:$S_REGISTRYPORT"
+ fi
+ S_ADDRESS="$S_ADDRESS/$S_NAME"
+else
+ S_ADDRESS="///$S_NAME"
+fi
+
+S_FINAL_REGISTRYPORT="$S_REGISTRYPORT"
+if [ -z "$S_FINAL_REGISTRYPORT" ]
+then
+ S_FINAL_REGISTRYPORT=1099
+fi
+
+## Finish auth configuration
+if [ "$FORCE_AUTH" ]
+then
+ AUTH="$FORCE_AUTH"
+fi
+
+if [ "$AUTH" = "name-pass:file" ]
+then
+ AUTH="name-pass:file=$AUTH_PW_FILE"
+fi
+
+if [ "$AUTH" = "local-shaj" ]
+then
+ AUTH="local-shaj"
+ JAVA_OPTS_LIB="$JAVA_OPTS_LIB$PATH_SEP$AUTH_SHAJ_LD_DIR"
+ JAVA_CP="$JAVA_CP$PATH_SEP$RJS_HOME/shaj/auth.jar"
+fi
+
+if [ "$AUTH" = "fx:file" ]
+then
+ AUTH="fx:file=$AUTH_FX_FILE"
+ AUTH_FX_FOLDER=`dirname "$AUTH_FX_FILE"`
+ mkdir -p "$AUTH_FX_FOLDER"
+ echo "00000000" > "$AUTH_FX_FILE"
+ if [ $AUTH_FX_USER ]
+ then
+ chown $AUTH_FX_USER "$AUTH_FX_FILE"
+ fi
+ if [ $AUTH_FX_MASK ]
+ then
+ chmod $AUTH_FX_MASK "$AUTH_FX_FILE"
+ fi
+fi
+
+OPTS="-auth=$AUTH"
+if [ $DEBUG ]
+then
+ OPTS="$OPTS -verbose"
+fi
+
+## Java config
+JAVA_EXE="$JAVA_HOME/bin/java"
+if [ $DEV ]
+then
+ JAVA_CP="$RJS_HOME/../org.eclipse.statet.rj.server/bin$PATH_SEP$RJS_HOME/../org.eclipse.statet.rj.data/bin$PATH_SEP$RJS_HOME/bin$PATH_SEP$RJS_HOME/binShaj"
+ RMI_BASE="file://$RJS_HOME/../org.eclipse.statet.rj.server/bin"
+ RJAVA_CP=
+else
+ JAVA_CP="$RJS_HOME/org.eclipse.statet.rj.server.jar$PATH_SEP$RJS_HOME/org.eclipse.statet.rj.data.jar$PATH_SEP$JAVA_CP"
+ RMI_BASE="file://$RJS_HOME/org.eclipse.statet.rj.server.jar"
+ RJAVA_CP=
+fi
+
+JAVA_OPTS="$JAVA_OPTS -Djava.security.policy=$RJS_HOME/security.policy"
+JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.codebase=$RMI_BASE"
+if [ -n "$S_HOSTADDRESS" ]
+then
+ JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=$S_HOSTADDRESS"
+fi
+if [ -n "$JAVA_OPTS_LIB" ]
+then
+ JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$JAVA_OPTS_LIB"
+fi
+if [ -n "$RJAVA_CP" ]
+then
+ JAVA_OPTS="$JAVA_OPTS -Drjava.class.path=$RJAVA_CP"
+fi
+
+## Other environment
+PATH=$R_HOME/bin$PATH_SEP$PATH
+LD_LIB_PATH=$R_HOME/lib
+#LD_PRELOAD_VALUE=$JAVA_HOME/jre/lib/amd64/server/libjsig.so
+
+
+## Start registry
+# For codebase see also:
+# http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/enhancements-7.html
+
+# Netcat (nc) is used to test if the registry port is in use
+#nc -z $S_HOSTADDRESS $S_FINAL_REGISTRYPORT
+#if [ $? -ne 0 ]
+#then
+# echo "No registry found at port $S_FINAL_REGISTRYPORT, starting registry..."
+# nohup $JAVA_HOME/bin/rmiregistry $S_REGISTRYPORT "-J-Djava.rmi.server.codebase=$RMI_BASE" >> "$RJS_WORK/registry-$S_FINAL_REGISTRYPORT.out" 2>&1 < /dev/null &
+# sleep 1
+#fi
+
+
+## Prepare start
+
+export PATH
+export $LD_LIB_VAR=$LD_LIB_PATH
+export $LD_PRELOAD_VAR=$LD_PRELOAD_VALUE
+export JAVA_HOME
+export R_HOME
+#export R_ARCH
+export R_LIBS
+export R_LIBS_USER
+export R_LIBS_SITE
+export R_DOC_DIR
+export R_SHARE_DIR
+export R_INCLUDE_DIR
+export LC_ALL
+
+cd "$WD"
+
+START_ARGS="-cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl start $S_ADDRESS $OPTS"
+#echo $JAVA_EXE $START_ARGS
+
+if [ $DEBUG ]
+then
+ echo "S_HOSTADDRESS = $S_HOSTADDRESS"
+ echo "S_REGISTRYPORT = $S_REGISTRYPORT"
+ echo "S_FINAL_REGISTRYPORT = $S_FINAL_REGISTRYPORT"
+ echo "PATH = $PATH"
+ # ${!LD_LIB_VAR} does not work e.g. in dash
+ echo "$LD_LIB_VAR = $LD_LIB_PATH"
+ echo "$LD_PRELOAD_VAR = $LD_PRELOAD_VALUE"
+ echo "R_HOME = $R_HOME"
+ echo "R_ARCH = $R_ARCH"
+ echo "JAVA_HOME = $JAVA_HOME"
+ echo "JAVA_EXE = $JAVA_EXE"
+ echo "CLASSPATH = $JAVA_CP"
+ echo "JAVA_OPTIONS = $JAVA_OPTS"
+ echo "AUTH = $AUTH"
+
+ # Start server directly
+ echo "Starting server ..."
+ $JAVA_EXE $START_ARGS
+ START_EXIT=$?
+ START_PID=$!
+ exit $START_EXIT
+else
+ # First check if running or dead server is already bound
+ CLEAN_ARGS="-cp $JAVA_CP $JAVA_OPTS org.eclipse.statet.rj.server.RMIServerControl clean $S_ADDRESS"
+ $JAVA_EXE $CLEAN_ARGS
+ CLEAN_EXIT=$?
+ if [ $CLEAN_EXIT -ne 0 ]
+ then
+ echo "Check and cleanup of old server failed (CODE=$CLEAN_EXIT), cancelling startup."
+ exit $CLEAN_EXIT
+ fi
+
+ # Start server detached
+ echo "Starting server ..."
+ echo "`date --rfc-3339=seconds` RJServer Startup Script" > "$RJS_WORK/session-$S_NAME.out"
+ echo "INFO: [Startup:$S_NAME] Cmd: $JAVA_EXE $START_ARGS" >> "$RJS_WORK/session-$S_NAME.out"
+ nohup $JAVA_EXE $START_ARGS >> "$RJS_WORK/session-$S_NAME.out" 2>&1 < /dev/null &
+ START_EXIT=$?
+ START_PID=$!
+ if [ $START_EXIT -eq 0 ]
+ then
+ echo "Started server in background (PID=$START_PID)."
+ exit 0
+ else
+ echo "Startup failed"
+ exit $START_EXIT
+ fi
+fi
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.classpath b/core/org.eclipse.statet.rj.server.rpkg/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.gitignore b/core/org.eclipse.statet.rj.server.rpkg/.gitignore
new file mode 100644
index 0000000..934e0e0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.gitignore
@@ -0,0 +1,2 @@
+/bin
+/target
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.project b/core/org.eclipse.statet.rj.server.rpkg/.project
new file mode 100644
index 0000000..2e87065
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.project
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.server.rpkg</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.server.rpkg/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.server.rpkg/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..aab93da
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/META-INF/MANIFEST.MF
@@ -0,0 +1,9 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.server.rpkg
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Server - R Package
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)"
diff --git a/core/org.eclipse.statet.rj.server.rpkg/about.html b/core/org.eclipse.statet.rj.server.rpkg/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.server.rpkg/build.properties b/core/org.eclipse.statet.rj.server.rpkg/build.properties
new file mode 100644
index 0000000..93163f1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/build.properties
@@ -0,0 +1,4 @@
+bin.includes = META-INF/,\
+ pkg/,\
+ about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/DESCRIPTION b/core/org.eclipse.statet.rj.server.rpkg/pkg/DESCRIPTION
new file mode 100644
index 0000000..588539a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/DESCRIPTION
@@ -0,0 +1,13 @@
+Encoding: UTF-8
+Package: rj
+Version: 2.1.0-11
+Title: RJ - R Package for high-level Java-R library RJ
+Author: Stephan Wahlbrink and others
+Maintainer: Eclipse StatET Project <statet-dev@eclipse.org>
+Depends: R (>= 2.11.0)
+Suggests: rj.gd
+SystemRequirements: java
+Description: R interface for the high-level Java-R library RJ. The
+ package also includes callback functions for StatET.
+License: Eclipse Public License 2.0 | Apache License 2.0
+URL: https://www.eclipse.org/statet
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/NAMESPACE b/core/org.eclipse.statet.rj.server.rpkg/pkg/NAMESPACE
new file mode 100644
index 0000000..6d74100
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/NAMESPACE
@@ -0,0 +1,6 @@
+export(.rj.originals, .rj.tmp)
+export(.console.loadHistory, .console.saveHistory, .console.addtoHistory)
+export(statet.help, statet.help.start, .statet.initDebug, .statet.initHelp)
+S3method(print, "help_files_with_topic")
+export(print.help_files_with_topic)
+export(openInEditor, openPackageManager, statet.chooseFile, statet.showHistory)
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/console.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/console.R
new file mode 100644
index 0000000..2b2f948
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/console.R
@@ -0,0 +1,40 @@
+ #=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+.console.loadHistory <- function(filename = ".Rhistory") {
+ if (!is.character(filename) || length(filename) != 1) {
+ stop("Illegal argument: filename")
+ }
+ .rj_ui.execCommand("console/loadHistory", list(
+ filename = filename ), TRUE)
+ return (invisible())
+}
+.console.saveHistory <- function(filename = ".Rhistory") {
+ if (!is.character(filename) || length(filename) != 1) {
+ stop("Illegal argument: filename")
+ }
+ .rj_ui.execCommand("console/saveHistory", list(
+ filename = filename ), TRUE)
+ return (invisible())
+}
+.console.addtoHistory <- function(line) {
+ if (missing(line) || !is.character(line) || length(line) != 1) {
+ stop("Illegal argument: line")
+ }
+ .rj_ui.execCommand("console/addtoHistory", list(
+ line = line ), FALSE)
+ return (invisible())
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dataaccess.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dataaccess.R
new file mode 100644
index 0000000..0870db1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dataaccess.R
@@ -0,0 +1,193 @@
+ #=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## data access (org.eclipse.statet.rj.services.utils.dataaccess) / data editor
+
+sda002.checkDataStruct <- function(x.env, x.expr, xClass1, xDim) {
+ x <- eval(expr= x.expr)
+ if (class(x)[1] != xClass1) {
+ return (FALSE)
+ }
+ d <- dim(x)
+ if (length(d) < 2L) {
+ return (length(x) == xDim[1L])
+ }
+ else if (length(d) == 2) {
+ return (d[1L] == xDim[1L] && d[2L] == xDim[2L])
+ }
+ else {
+ return (FALSE)
+ }
+}
+
+sda002.getDataVectorValues <- function(x.env, x.expr, idxs, rowMapping) {
+ rowIdxs <- if (missing(rowMapping))
+ idxs[1L]:idxs[2L]
+ else
+ get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+ x <- eval(expr= x.expr) [rowIdxs, drop= FALSE]
+ names(x) <- NULL
+ x
+}
+
+sda002.setDataVectorValues <- function(x.env, x.expr, idxs, values) {
+ expr <- quote(x[idxs[1L]:idxs[2L]] <- values)
+ expr[[2]][[2]] <- x.expr[[1]]
+ eval(expr= as.expression(expr))
+ TRUE
+}
+
+sda002.getDataVectorRowNames <- function(x.env, x.expr, idxs, rowMapping) {
+ x.names <- names(
+ eval(expr= x.expr) )
+ if (is.null(x.names) && missing(rowMapping)) {
+ return (NULL)
+ }
+ rowIdxs <- if (missing(rowMapping))
+ idxs[1L]:idxs[2L]
+ else
+ get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+ if (!is.null(x.names))
+ names(rowIdxs) <- x.names[rowIdxs]
+ rowIdxs
+}
+
+sda002.getDataMatrixValues <- function(x.env, x.expr, idxs, rowMapping) {
+ rowIdxs <- if (missing(rowMapping))
+ idxs[1L]:idxs[2L]
+ else
+ get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+ x <- eval(expr= x.expr) [rowIdxs, idxs[3L]:idxs[4L], drop= FALSE]
+ rownames(x) <- NULL
+ x
+}
+
+sda002.getDataMatrixRowNames <- function(x.env, x.expr, idxs, rowMapping) {
+ x.names <- rownames(
+ eval(expr= x.expr) )
+ if (is.null(x.names) && missing(rowMapping)) {
+ return (NULL)
+ }
+ rowIdxs <- if (missing(rowMapping))
+ idxs[1L]:idxs[2L]
+ else
+ get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+ if (!is.null(x.names))
+ names(rowIdxs) <- x.names[rowIdxs]
+ rowIdxs
+}
+
+sda002.getDataArrayDimNames <- function(x.env, x.expr, idxs) {
+ x.dimnames <- dimnames(
+ eval(expr= x.expr) )
+ if (is.null(x.dimnames)) {
+ return (NULL)
+ }
+ names(x.dimnames)[idxs[1L]:idxs[2L]]
+}
+
+sda002.getDataArrayDimItemNames <- function(x.env, x.expr, dimIdx, idxs) {
+ x.dimnames <- dimnames(
+ eval(expr= x.expr) )
+ if (is.null(x.dimnames)) {
+ return (NULL)
+ }
+ x.dimnames[[dimIdx]][idxs[1L]:idxs[2L]]
+}
+
+sda002.getDataFrameValues <- function(x.env, x.expr, idxs, rowMapping) {
+ rowIdxs <- if (missing(rowMapping))
+ idxs[1L]:idxs[2L]
+ else
+ get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+ x <- eval(expr= x.expr) [rowIdxs, idxs[3L]:idxs[4L], drop= FALSE]
+ attr(x, 'row.names') <- NULL
+ x
+}
+
+sda002.getDataFrameRowNames <- function(x.env, x.expr, idxs, rowMapping) {
+ x.names <- attr(
+ eval(expr= x.expr),
+ 'row.names', exact= TRUE )
+ if (is.null(x.names) && missing(rowMapping)) {
+ return (NULL)
+ }
+ rowIdxs <- if (missing(rowMapping))
+ idxs[1L]:idxs[2L]
+ else
+ get(rowMapping, envir= .rj.tmp)[idxs[1L]:idxs[2L]]
+ if (!is.null(x.names))
+ names(rowIdxs) <- x.names[rowIdxs]
+ rowIdxs
+}
+
+
+.getDataLevelValues <- function(x, max = 1000) {
+ if (is.factor(x)) {
+ values <- levels(x)
+ if (any(is.na(x))) {
+ values <- c(values, NA)
+ }
+ }
+ else {
+ values <- sort(unique(x), na.last= TRUE)
+ }
+ if (length(values) > max) {
+ return (NULL)
+ }
+ return (values)
+}
+
+.getDataIntervalValues <- function(x) {
+ values <- c(min(x, na.rm= TRUE), max(x, na.rm= TRUE), if (any(is.na(x))) 1L else 0L)
+ return (values)
+}
+
+.searchDataTextValues <- function(x, type, pattern, max = 1000) {
+ if (type == 0L) { # Eclipse
+ values <- grep(pattern, x, ignore.case= TRUE, value= TRUE)
+ }
+ else if (type == 1L) {
+ values <- grep(pattern, x, ignore.case= FALSE, value= TRUE)
+ }
+ else if (type == 2L) {
+ values <- match(pattern, x)
+ if (!is.na(values)) {
+ values <- pattern
+ }
+ else {
+ values <- character(0)
+ }
+ }
+ else {
+ stop("Illegal argument: type")
+ }
+ if (length(values) > max) {
+ return (NULL)
+ }
+ return (values)
+}
+
+
+.formatInfo.maxLength <- 2L^20L
+.formatInfo.sampleLength <- 2L^19L
+
+.getFormatInfo <- function(x) {
+ if (length(x) > .formatInfo.maxLength) {
+ x <- sample(x, .formatInfo.sampleLength)
+ }
+ return (format.info(x))
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dbg.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dbg.R
new file mode 100644
index 0000000..62214d2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/dbg.R
@@ -0,0 +1,59 @@
+ #=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## RJ dbg
+
+
+#' Initializes the debug tools
+dbg.init <- function(..) {
+ error("Operation not supported")
+}
+
+
+dbg.checkBreakpoint <- function() {
+ if (tracingState(FALSE)) {
+ on.exit(tracingState(TRUE))
+ }
+
+ answer <- .Call("Re_ExecJCommand", "dbg:checkBreakpoint", sys.call(), 0L,
+ PACKAGE= "(embedding)" )
+
+ if (!is.null(answer)) {
+ envir <- sys.frame(-1)
+ eval(expr= answer, envir= envir)
+ }
+}
+
+dbg.checkEB <- function() {
+ if (tracingState(FALSE)) {
+ on.exit(tracingState(TRUE))
+ }
+
+ if ("rj" %in% loadedNamespaces()) {
+ answer <- .Call("Re_ExecJCommand", "dbg:checkEB", NULL, 0L,
+ PACKAGE= "(embedding)" )
+
+ if (!is.null(answer)) {
+ envir <- sys.frame(-1)
+ eval(expr= answer, envir= envir)
+ }
+ }
+}
+
+dbg.checkTB <- function(expr, env) {
+ answer <- .Call("Re_ExecJCommand", "dbg:checkTB", list(expr, env), 0L,
+ PACKAGE= "(embedding)" )
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/init.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/init.R
new file mode 100644
index 0000000..fc9add9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/init.R
@@ -0,0 +1,166 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## RJ init
+
+.rj.config <- new.env()
+.rj.config$isDebug <- FALSE
+
+#' Initializes the package
+.onLoad <- function(libname, pkgname) {
+ utilsEnv <- getNamespace("utils")
+ assign("help", envir = .rj.originals, value = get("help", envir = utilsEnv))
+ assign("help.start", envir = .rj.originals, value = get("help.start", envir = utilsEnv))
+
+ return (invisible(TRUE))
+}
+
+.rj.originals <- new.env()
+
+
+## Tmp
+
+#' Environment for temporary R objects
+.rj.tmp <- new.env()
+
+#' Returns the next available id (a element name with the specified prefix)
+#'
+#' @param prefix prefix of the element name, usually a key for a element type
+#' @param envir optional environment, default is \code{.rj.tmp}
+#' @return the id
+#' @returnType char
+tmp.createId <- function(prefix, envir = .rj.tmp) {
+ i <- 1L;
+ repeat {
+ name <- paste(prefix, i, sep= "")
+ if (!exists(name, envir = envir, inherits = FALSE)) {
+ assign(name, NULL, envir= envir)
+ return(name);
+ }
+ i <- i + 1L;
+ }
+}
+
+tmp.set <- function(name, value, envir = .rj.tmp) {
+ assign(name, value, envir= envir)
+ return (invisible())
+}
+
+tmp.remove <- function(name, envir = .rj.tmp) {
+ if (exists(name, envir= envir, inherits= FALSE)) {
+ rm(list= name, envir= envir, inherits= FALSE)
+ }
+ return (invisible())
+}
+
+tmp.removeAll <- function(id, envir = .rj.tmp) {
+ names <- ls(envir= envir, pattern= paste0("^\\Q", id, "\\E"))
+ if (length(names)) {
+ rm(list= names, envir= envir, inherits= FALSE)
+ }
+ return (invisible())
+}
+
+tmp.setReverseIndex <- function(name, index, len = NA, envir = .rj.tmp) {
+ index = get(index, envir= envir, inherits= FALSE)
+ if (is.na(len)) {
+ len <- length(index)
+ }
+ index.r <- rep.int(NA_integer_, len)
+ index.r[index] <- 1L:length(index)
+ assign(name, index.r, envir= envir)
+ return (invisible())
+}
+
+tmp.setWhichIndex <- function(name, filter, envir = .rj.tmp) {
+ filter <- get(filter, envir= envir, inherits= FALSE)
+ filter <- which(filter)
+ assign(name, filter, envir= envir)
+ return (invisible())
+}
+
+tmp.setFilteredIndex <- function(name, filter, index, envir = .rj.tmp) {
+ filter <- get(filter, envir= envir, inherits= FALSE)
+ index <- get(index, envir= envir, inherits= FALSE)
+ if (length(dim(index)) > 1L) {
+ idx <- index[,1L]
+ index <- index[filter[idx],]
+ }
+ else {
+ index <- index[filter[index]]
+ }
+ assign(name, index, envir= envir)
+ return (invisible())
+}
+
+tmp.getFilteredCount <- function(index, filter, envir = .rj.tmp) {
+ filter <- get(filter, envir= envir, inherits= FALSE)
+ if (missing(index)) {
+ return (sum(filter))
+ }
+ index <- get(index, envir= envir, inherits= FALSE)
+ if (length(dim(index)) > 1L) {
+ index <- index[,1L]
+ }
+ return (sum(filter[index]))
+}
+
+tmp.clear <- function(envir = .rj.tmp) {
+ toRemove <- ls(envir= envir)
+ toRemove <- toRemove[toRemove != "help"] # TODO Remove in RJ-1.2
+ rm(list= toRemove, envir= envir)
+}
+
+
+## Internal utils
+
+.rj.errorHandler <- function(e) {
+ if (.rj.config$isDebug) {
+ print(e)
+ }
+}
+
+patchPackage <- function(name, value, envir, ns = TRUE) {
+ if (exists(name, envir)) {
+ unlockBinding(name, envir)
+ on.exit(lockBinding(name, envir), add= TRUE)
+ assign(name, value, envir)
+ }
+ if (ns && getRversion() < "2.15.0") {
+ envName <- environmentName(envir)
+ if (envName == "base") {
+ ns <- "base"
+ }
+ else if (!is.null(envName) && substring(envName, 1L, 8L) == "package:") {
+ ns <- asNamespace(substring(envName, 9L))
+ }
+ else {
+ ns <- NULL
+ }
+ if (!is.null(ns)) {
+ assignInNamespace(name, value, ns= ns)
+ }
+ }
+ return (invisible(TRUE))
+}
+
+resolveVisible <- function(result) {
+ if (result$visible) {
+ return (result$value)
+ }
+ else {
+ return (invisible(result$value))
+ }
+}
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_help.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_help.R
new file mode 100644
index 0000000..f24d000
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_help.R
@@ -0,0 +1,233 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## StatET help
+
+.getHelpFile <- function(file) {
+ path <- dirname(file)
+ dirpath <- dirname(path)
+ if(!file.exists(dirpath))
+ stop(gettextf("invalid '%s' argument", "file"), domain= NA)
+ pkgname <- basename(dirpath)
+ RdDB <- file.path(path, pkgname)
+ if(!file.exists(paste(RdDB, "rdx", sep= ".")))
+ stop(gettextf("package %s exists but was not installed under R >= 2.10.0 so help cannot be accessed", sQuote(pkgname)), domain= NA)
+ tools:::fetchRdDB(RdDB, basename(file))
+}
+
+#' Creates rhelp url, mostly compatible to \code{help}
+#'
+#' @param topic
+#' @param package
+#' @param ... for compatibility
+#' @returnType character
+#' @return URL in rhelp schema
+.getRHelpUrl <- function(helpObj) {
+ if (inherits(helpObj, "packageInfo")) {
+ return (paste("rhelp:///page", helpObj$name, "", sep= "/"))
+ }
+ if (inherits(helpObj, "help_files_with_topic")) {
+ topic <- attr(helpObj, "topic", exact= TRUE)
+ if (is.null(topic)) {
+ topic <- "help"
+ package <- "utils"
+ }
+ else {
+ package <- attr(helpObj, "call", exact= TRUE)[["package"]]
+ }
+ if (is.name(y <- substitute(package))) {
+ package <- as.character(y)
+ }
+ if (is.character(package)
+ && length(package) == 1 && !is.na(package)) {
+ return (paste("rhelp:///page", package, topic, sep= "/"))
+ }
+ else {
+ return (paste("rhelp:///topic", topic, sep= "/"))
+ }
+ }
+ stop("Unexpected help information.")
+}
+
+#' Creates HTML help page for the given help page(s).
+#'
+#' @param x vector of help pages (as returns by original \code{help}
+#' @return HTML page for a single page, otherwise \code{NULL}
+#' @returnType character
+.getLiveHelp <- function(x) {
+ paths <- as.character(x)
+ if(!length(paths)) {
+ writeLines(c(gettextf("No documentation for '%s' in specified packages and libraries:",
+ topic),
+ gettextf("you could try '??%s'",
+ topic)))
+ return (invisible(NULL))
+ }
+
+ if (attr(x, "tried_all_packages", exact= TRUE)) {
+ paths <- unique(dirname(dirname(paths)))
+ msg <- gettextf("Help for topic '%s' is not in any loaded package but can be found in the following packages:",
+ topic)
+ writeLines(c(strwrap(msg), "",
+ paste(" ", formatDL(c(gettext("Package"), basename(paths)),
+ c(gettext("Library"), dirname(paths)),
+ indent= 22))))
+ return (invisible(NULL))
+ }
+
+ file <- NULL
+ if (length(paths) > 1L) {
+ p <- paths
+ msg <- gettextf("Help on topic '%s' was found in the following packages:",
+ topic)
+ paths <- dirname(dirname(paths))
+ txt <- formatDL(c("Package", basename(paths)),
+ c("Library", dirname(paths)),
+ indent= 22L)
+ writeLines(c(strwrap(msg), "", paste(" ", txt), ""))
+ if (interactive()) {
+ fp <- file.path(paths, "Meta", "Rd.rds")
+ tp <- basename(p)
+ titles <- tp
+ if(type == "html" || type == "latex")
+ tp <- tools::file_path_sans_ext(tp)
+ for (i in seq_along(fp)) {
+ tmp <- try(.readRDS(fp[i]))
+ titles[i] <- if(inherits(tmp, "try-error"))
+ "unknown title" else
+ tmp[tools::file_path_sans_ext(tmp$File) == tp[i], "Title"]
+ }
+ txt <- paste(titles, " {", basename(paths), "}", sep= "")
+ ## the default on menu() is currtently graphics = FALSE
+ res <- menu(txt, title= gettext("Choose one"),
+ graphics= getOption("menu.graphics"))
+ if (res > 0) {
+ file <- p[res]
+ } else {
+ file <- NULL
+ }
+ } else {
+ file <- paths[1L]
+ writeLines(gettext("\nUsing the first match ..."))
+ }
+ } else {
+ file <- paths
+ }
+
+ if (is.null(file)) {
+ return (invisible(NULL))
+ }
+
+ file <- sub("/html/([^/]*)\\.html$", "/help/\\1", file)
+ if (getRversion() < "2.11.0") {
+ rd <- .getHelpFile(file)
+ }
+ else {
+ rd <- utils:::.getHelpFile(file)
+ }
+
+ renderRd(rd, basename(dirname(dirname(file))))
+}
+
+.showHelp <- function(url) {
+ if (missing(url) || !is.character(url) || length(url) != 1) {
+ stop("Illegal argument: url")
+ }
+ .rj_ui.execCommand("r/showHelp", list(
+ url= url ), wait= FALSE)
+}
+
+#' Shows R help in StatET. This is a console command for R help in StatET
+#' mainly compatible to the original \code{help}.
+#'
+#' @seealso help
+#' @export
+statet.help <- function(topic, package= NULL, lib.loc= NULL,
+ verbose= getOption("verbose"),
+ try.all.packages= getOption("help.try.all.packages"), ...,
+ live= FALSE ) {
+ nextCall <- match.call(expand.dots= TRUE)
+ callName <- nextCall[[1]]
+
+ if (is.null(nextCall$topic) && !is.null(nextCall$package)) {
+ packageInfo <- list(name= nextCall$package)
+ class(packageInfo) <- "packageInfo"
+
+ result <- list(value= packageInfo, visible= TRUE)
+ }
+ else {
+ nextCall[[1]] <- substitute(utils::help)
+ nextCall$live <- NULL
+ nextCall$help_type <- "html"
+
+ result <- withVisible(eval(nextCall, envir= parent.frame()))
+
+ result.call <- attr(result$value, "call", exact= TRUE)
+ if (!is.null(result.call)) {
+ result.call[[1]] <- callName
+ attr(result$value, "call") <- result.call
+ }
+
+ }
+
+ if (live) {
+ help.statet <- .getLiveHelp(result$value)
+ if (!is.null(help.statet)) {
+ help.statet <- paste(help.statet, collapse= "\n")
+ help.statet <- paste("html:///", help.statet, sep= "")
+ }
+ }
+ else if (is.null(.rj.tmp$help)
+ || inherits(result$value, "packageInfo") ) {
+ help.statet <- .getRHelpUrl(result$value)
+ }
+ else {
+ return (resolveVisible(result))
+ }
+ if (is.character(help.statet) && !is.na(help.statet)) {
+ .showHelp(help.statet)
+ }
+ return (invisible())
+}
+
+#' Shows the R help start page in StatET. This is a console command for R help in StatET
+#' mainly compatible to the original \code{help.start}.
+#'
+#' At moment no argument functionality is supported.
+#'
+#' @param ... for compatibility
+#' @seealso help.start
+#' @export
+statet.help.start <- function(...) {
+ .showHelp("rhelp:///")
+ return (invisible())
+}
+
+
+statet.print.help <- function(x, ...) {
+ type <- attr(x, "type", exact= TRUE)
+ if (length(x) == 0
+ || (!is.null(type) && type != "html")
+ || is.null(.rj.tmp$help) ) {
+ # NextMethod ?
+ return (utils:::print.help_files_with_topic(x, ...))
+ }
+ help.statet <- .getRHelpUrl(x)
+ if (is.character(help.statet)
+ && length(help.statet) == 1 && !is.na(help.statet)) {
+ .showHelp(help.statet)
+ }
+ return (invisible(x))
+}
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_internal.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_internal.R
new file mode 100644
index 0000000..502d5e7
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_internal.R
@@ -0,0 +1,343 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## StatET utilities
+
+#' Estimates a value for the parameter max.level of \code{str}
+#' for the given R element.
+#'
+#' @param x the R element to show
+#' @param max.elements maximum elements to show
+#' @param max.levels maximum levels to show
+#' @returnType integer
+#' @return a value for max.level
+#' @author Stephan Wahlbrink <sw@wahlbrink.eu>
+#' @export
+estimateStrDepth <- function(x, max.elements = 2000L, max.levels = 10L) {
+ deeplength <- function(x, level = 0L) {
+ if (isS4(x)) {
+ xslots <- slotNames(class(x))
+ xlen <- length(xslots)
+ if (level == 0L || xlen == 0L) {
+ return (xlen)
+ }
+ else {
+ s <- 0L
+ for (xslot in xslots) {
+ s <- s + deeplength(slot(x, xslot), level = level-1L)
+ }
+ return (s)
+ }
+ }
+ if (is.list(x)) {
+ xlen <- length(x)
+ if (level == 0L || xlen == 0L || is.data.frame(x)) {
+ return (xlen)
+ }
+ else {
+ return (sum(sapply(x, deeplength, level = level-1L, USE.NAMES=FALSE)))
+ }
+ }
+ return (0L)
+ }
+
+ level <- -1L
+ s <- 0L
+ while (level < max.levels && s < max.elements) {
+ level <- level + 1L
+ s.level <- deeplength(x, level)
+ if (s.level == 0L) {
+ return (NA)
+ }
+ s <- s + s.level
+ }
+ return (level)
+}
+
+#' Captures output of \code{str} for the given R element.
+#' The output is limited to the specified number of R elements.
+#'
+#' @param x the R element to show
+#' @param limit maximum elements to show
+#' @returnType character
+#' @return output of \code{str}
+#' @author Stephan Wahlbrink <sw@wahlbrink.eu>
+#' @export
+.statet.captureStr <- function(x, limit = 2000L) {
+ savedOptions <- options(width = 10000L)
+ on.exit(options(savedOptions))
+ levels <- estimateStrDepth(x, max.elements = limit)
+ if (!is.na(levels) && levels <= 1L && getRversion() >= "2.11.0") {
+ output <- capture.output(str(x, max.level = 1L, list.len = limit - 1L))
+ }
+ else {
+ output <- capture.output(str(x, max.level = levels))
+ }
+ return (output)
+}
+
+
+.statet.prepareSrcfile <- function(filename, path) {
+ map <- .rj.tmp$statet.SrcfileMap
+ if (is.null(map)) {
+ map <- list()
+ }
+ map[[filename]] <- NULL
+ map[[filename]] <- path
+ if (length(map) > 20) {
+ map[[1]] <- NULL
+ }
+ .rj.tmp$statet.SrcfileMap <- map
+ return (invisible(NULL))
+}
+
+.statet.extSrcfile <- function(srcfile) {
+ map <- .rj.tmp$statet.SrcfileMap
+ path <- NULL
+ if (is.null(map) || is.null(srcfile$filename)) {
+ return (srcfile)
+ }
+ idx <- which(names(map) == srcfile$filename)
+ if (length(idx) != 1) {
+ return (srcfile)
+ }
+ path <- map[[idx]]
+
+ if (idx <= 10) {
+ map[[idx]] <- NULL
+ map[[srcfile$filename]] <- path
+ .rj.tmp$statet.SrcfileMap <- map
+ }
+
+ srcfile$statet.Path <- path
+ return (srcfile)
+}
+
+.addElementIds <- function(expr, elementIds) {
+ names <- names(elementIds)
+ for (i in seq_along(names)) {
+ if (!is.na(names[i])) {
+ path <- elementIds[[i]]
+ tryCatch(attr(expr[[path]], "statet.ElementId") <- names[i],
+ error = .rj.errorHandler )
+ }
+ }
+ return (expr)
+}
+
+.statet.prepareCommand <- function(lines, filename = "<text>",
+ srcfileAttributes, elementIds) {
+ # create srcfile object
+ srcfile <- srcfilecopy(filename, lines)
+ if (!missing(srcfileAttributes)) {
+ names <- names(srcfileAttributes)
+ for (i in seq_along(names)) {
+ if (!is.na(names[i])) {
+ assign(names[i], srcfileAttributes[[i]], envir= srcfile)
+ }
+ }
+ }
+
+ # parse command
+ expr <- parse(text= lines, srcfile= srcfile, encoding= "UTF-8")
+
+ # attach element ids
+ if (!missing(elementIds)) {
+ expr <- .addElementIds(expr, elementIds)
+ }
+
+ # finish
+ .rj.tmp$statet.CommandExpr <- expr
+ invisible(expr)
+}
+
+.statet.evalCommand <- function() {
+ expr <- .rj.tmp$statet.CommandExpr
+ if (is.null(expr)) {
+ stop("Commands not available.")
+ }
+ srcrefs <- attr(expr, "srcref", exact= TRUE)
+ exi <- call("{", expr[[1]])
+ if (1 <= length(srcrefs)) {
+ attr(exi, "srcref") <- list(NULL, srcrefs[[1]])
+ }
+ eval(exi, parent.frame())
+}
+
+.statet.prepareSource <- function(info) {
+ assign("statet.NextSourceInfo", info, envir= .rj.tmp)
+}
+
+.statet.extSource <- function(expr) {
+ info <- .rj.tmp$statet.NextSourceInfo
+ if (is.null(info)) {
+ return (expr)
+ }
+ on.exit(rm("statet.NextSourceInfo", envir= .rj.tmp))
+ if (is.null(expr)) {
+ return (expr)
+ }
+ srcfile <- attr(expr, "srcfile", exact= TRUE)
+ if (is.null(srcfile)
+ || is.null(srcfile$statet.Path) || is.null(srcfile$timestamp)
+ || srcfile$statet.Path != info$path
+ || (unclass(srcfile$timestamp) != info$timestamp
+ && abs(unclass(srcfile$timestamp) - info$timestamp) != 3600 )
+ || length(expr) != info$exprsLength ) {
+ return (expr)
+ }
+ expr <- .addElementIds(expr, info$elementIds)
+ return (expr)
+}
+
+
+.searchExpr <- function(expr, cond, max.depth= 5, depth= 1) {
+ if (expr[[1]] == "{") {
+ for (i in seq_along(expr)) {
+ if (cond(expr[[i]])) {
+ return (i);
+ }
+ }
+ }
+ for (i in seq_along(expr)) {
+ if (depth < max.depth && length(expr[[i]]) > 1) {
+ idx <- .searchExpr(expr= expr[[i]], cond= cond,
+ max.depth= max.depth, depth= depth + 1)
+ if (!is.null(idx)) {
+ return (c(i, idx))
+ }
+ }
+ }
+ return (NULL)
+}
+
+
+#### R env / R lib path (R pkg manager)
+
+renv.checkLibs <- function() {
+ libs <- .libPaths()
+ result <- file.info(libs)$mtime
+ names(result) <- libs
+
+ result
+}
+
+renv.getBioCVersion <- function() {
+ v <- tools:::.BioC_version_associated_with_R_version
+ if (is.function(v)) {
+ v <- v()
+ }
+ return (v)
+}
+
+renv.getAvailPkgs <- function(repo) {
+ fields= c('Package', 'Version', 'Priority', 'License',
+ 'Depends', 'Imports', 'LinkingTo', 'Suggests', 'Enhances')
+ result <- available.packages(contriburl= contrib.url(repo), fields= fields,
+ filter= c('R_version', 'OS_type', 'subarch') )
+ result[, fields, drop= FALSE]
+}
+
+renv.getInstPkgs <- function(lib) {
+ names <- list.files(lib)
+ fields <- c('Package', 'Version', 'Title', 'Built')
+ result <- matrix(NA_character_, nrow= length(names), ncol= length(fields))
+ num <- 0L
+ for (name in names) {
+ pkgpath <- file.path(lib, name)
+ if (file.access(pkgpath, 5L)) {
+ next
+ }
+ if (file.exists(file <- file.path(pkgpath, 'Meta', 'package.rds'))) {
+ md <- try(readRDS(file))
+ if (inherits(md, 'try-error')) {
+ next
+ }
+ descr <- md$DESCRIPTION[fields]
+ if (is.null(descr)) {
+ next
+ }
+ enc <- md$DESCRIPTION['Encoding']
+ if (!is.na(enc)) {
+ txt <- try(iconv(descr[3L], from= enc, to= "UTF-8"))
+ if (!inherits(txt, "try-error")) {
+ descr[3L] <- txt
+ }
+ }
+ descr[1L] <- name
+ result[num <- num + 1, ] <- descr
+ }
+ }
+ result[seq.int(from= 1L, length.out= num), , drop= FALSE]
+}
+
+renv.getInstPkgDetail <- function(lib, name) {
+ fields <- c('Priority', 'License',
+ 'Depends', 'Imports', 'LinkingTo', 'Suggests', 'Enhances' )
+ file <- file.path(lib, name, 'Meta', 'package.rds')
+ md <- readRDS(file)
+ md$DESCRIPTION[fields]
+}
+
+renv.isValidLibLoc <- function(path) {
+ # path <- normalizePath(path)
+ current <- path
+ repeat {
+ if (file.access(current, 0L) == 0L) { # exists
+ result <- file.access(current, 3L) # writable
+ names(result) <- path
+ return (result)
+ }
+ parent <- dirname(current)
+ if (nchar(parent) <= 1L || parent == current) {
+ return (-1L)
+ }
+ current <- parent
+ }
+}
+
+
+#### R help
+
+#' Returns the package description for the specified package
+#'
+#' @param lib the library location
+#' @param name the package name
+rhelp.loadPkgDescr <- function(lib, name) {
+ fields <- c('Version', 'Title', 'Description', 'Author', 'Maintainer', 'URL', 'Built')
+ file <- file.path(lib, name, 'Meta', 'package.rds')
+ md <- readRDS(file)
+ descr <- md$DESCRIPTION[fields]
+ if (is.null(descr)) {
+ return (NULL)
+ }
+ enc <- md$DESCRIPTION['Encoding']
+ if (!is.na(enc)) {
+ txt <- try(iconv(descr[2L:5L], from= enc, to= "UTF-8"))
+ if (!inherits(txt, "try-error")) {
+ descr[2L:5L] <- txt
+ }
+ }
+ return (descr)
+}
+
+#' Returns the help files for the specified package
+#'
+#' @param lib the library location
+#' @param name the package name
+rhelp.loadPkgRd <- function(lib, name) {
+ error("Operation not supported")
+}
+
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_workbench.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_workbench.R
new file mode 100644
index 0000000..af4525f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/statet_workbench.R
@@ -0,0 +1,106 @@
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## StatET workbench
+
+#' Opens a file in an editor in StatET
+#' @param filename name of file to open
+#'
+#' @export
+openInEditor <- function(name, fileName, elementName, filename) {
+ if (!missing(filename)) {
+ fileName <- filename
+ }
+ if (missing(name) && missing(fileName) && missing(elementName)) {
+ stop("Missing argument: name")
+ }
+ if (missing(fileName) && missing(elementName)) {
+ # auto
+ fileName <- NULL
+ elementName <- NULL
+ if (is.character(name) && length(name) == 1) {
+ fileName <- name
+ }
+ else {
+ elementName <- substitute(name)
+ }
+ }
+ else if (!missing(elementName)) {
+ fileName <- NULL
+ elementName # test, if it refers to an existing element
+ elementName <- substitute(elementName)
+ }
+ else if (!missing(fileName)) {
+ elementName <- NULL
+ }
+
+ if (!is.null(fileName)) {
+ if (!is.character(fileName) || length(fileName) != 1) {
+ stop("Illegal argument: fileName")
+ }
+ .rj_ui.execCommand("common/showFile", list(
+ filename= fileName ), wait= TRUE)
+ }
+ else {
+ elementName <- deparse(elementName, backtick= TRUE, control= c(),
+ width.cutoff= 500, nlines= 2L)
+ if (length(elementName) != 1) {
+ stop("Illegal argument: elementName")
+ }
+ .rj_ui.execCommand("showElement", list(
+ elementName= elementName ), wait= TRUE)
+ }
+ return (invisible())
+}
+
+#' Opens the package manager in StatET
+#'
+#' @export
+openPackageManager <- function() {
+ .rj_ui.execCommand("r/openPackageManager", wait= FALSE)
+ return (invisible())
+}
+
+#' Asks the user to choose a file using the StatET GUI.
+#'
+#' @param new if the choosen file can be new (does not yet exits)
+#' @export
+statet.chooseFile <- function(new = FALSE) {
+ if (!is.logical(new) || length(new) != 1) {
+ stop("Illegal argument: new")
+ }
+ answer <- .rj_ui.execCommand("common/chooseFile", list(
+ newResource= new ), wait= TRUE)
+ if (is.null(answer)) { # operation cancelled
+ return (invisible())
+ }
+ return (answer$filename)
+}
+
+#' Shows the Cmd History view in StatET
+#'
+#' @export
+statet.showHistory <- function() {
+ .rj_ui.execCommand("common/showHistory", wait= FALSE)
+ return (invisible())
+}
+
+
+.statet.initDebug <- function(...) {
+ dbg.init(...)
+}
+
+.statet.initHelp <- function(...) {
+}
diff --git a/core/org.eclipse.statet.rj.server.rpkg/pkg/R/uicommands.R b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/uicommands.R
new file mode 100644
index 0000000..a764c5f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server.rpkg/pkg/R/uicommands.R
@@ -0,0 +1,47 @@
+ #=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+
+
+## RJ UI
+
+#' Sends an UI command to the GUI which executes the command
+#' if it is supported
+#'
+#' @param commandId the id of the UI command
+#' @param args an optional list with arguments (meaning depends on UI command)
+#' @param wait if R must wait until the command is executed
+#' (necessary if you need a return value)
+#' @returnType char
+.rj_ui.execCommand <- function(commandId, args = list(), wait = TRUE) {
+ if (missing(commandId)) {
+ stop("Missing param: commandId")
+ }
+ if (!is.list(args)) {
+ stop("Illegal argument: args must be a list")
+ }
+ if (length(args) > 0) {
+ args.names <- names(args)
+ if (is.null(args.names) || any(is.na(args.names))) {
+ stop("Illegal argument: args must be named")
+ }
+ }
+
+ options <- 0L
+ if (wait) {
+ options <- options + 1L
+ }
+ .Call("Re_ExecJCommand", paste("ui", commandId, sep=":"), args, options,
+ PACKAGE= "(embedding)" )
+}
+
diff --git a/core/org.eclipse.statet.rj.server/.classpath b/core/org.eclipse.statet.rj.server/.classpath
new file mode 100644
index 0000000..3dfe0c4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+ <attributes>
+ <attribute name="owner.project.facets" value="java"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="srcEExtensions"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.server/.gitignore b/core/org.eclipse.statet.rj.server/.gitignore
new file mode 100644
index 0000000..ed620ff
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.gitignore
@@ -0,0 +1,3 @@
+/bin
+/target
+/doc
diff --git a/core/org.eclipse.statet.rj.server/.project b/core/org.eclipse.statet.rj.server/.project
new file mode 100644
index 0000000..d27385d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.project
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.server</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..73cd796
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="org.eclipse.statet.rj.server">
+ <wb-resource deploy-path="/" source-path="/src"/>
+ </wb-module>
+</project-modules>
diff --git a/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f4ef8aa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.server/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.server/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..6ae2bcb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/META-INF/MANIFEST.MF
@@ -0,0 +1,23 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.server;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Server - Core
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.swt;bundle-version="3.6.0";resolution:=optional,
+ com.cenqua.shaj;bundle-version="1.0.0";resolution:=optional
+Import-Package: org.osgi.framework;resolution:=optional,
+ org.eclipse.core.runtime;resolution:=optional
+Export-Package: org.eclipse.statet.rj,
+ org.eclipse.statet.rj.server,
+ org.eclipse.statet.rj.server.dbg,
+ org.eclipse.statet.rj.server.e.srvext,
+ org.eclipse.statet.rj.server.gr,
+ org.eclipse.statet.rj.server.osgi,
+ org.eclipse.statet.rj.server.srv,
+ org.eclipse.statet.rj.server.srv.engine,
+ org.eclipse.statet.rj.server.srvext,
+ org.eclipse.statet.rj.server.srvext.auth,
+ org.eclipse.statet.rj.server.util
diff --git a/core/org.eclipse.statet.rj.server/about.html b/core/org.eclipse.statet.rj.server/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.server/build.properties b/core/org.eclipse.statet.rj.server/build.properties
new file mode 100644
index 0000000..d33d5e2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/build.properties
@@ -0,0 +1,13 @@
+source..= src/,\
+ srcEExtensions/
+output..= bin/
+extra..= platform:/plugin/org.eclipse.core.runtime
+javacDefaultEncoding..= UTF-8
+
+bin.includes = META-INF/,\
+ plugin.xml,\
+ .,\
+ about.html,\
+ localhost.policy
+src.includes= .settings/org.eclipse.core.resources.prefs,\
+ schema/
diff --git a/core/org.eclipse.statet.rj.server/localhost.policy b/core/org.eclipse.statet.rj.server/localhost.policy
new file mode 100644
index 0000000..6e902c1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/localhost.policy
@@ -0,0 +1,7 @@
+grant codeBase "file:${{java.ext.dirs}}/*" {
+ permission java.security.AllPermission;
+};
+
+grant {
+ permission java.security.AllPermission;
+};
diff --git a/core/org.eclipse.statet.rj.server/plugin.xml b/core/org.eclipse.statet.rj.server/plugin.xml
new file mode 100644
index 0000000..41fd781
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/plugin.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+
+ <extension-point id="org.eclipse.statet.rj.RSetups"
+ name="R Setups (Installations and Libraries)"
+ schema="schema/RSetups.exsd"/>
+
+</plugin>
diff --git a/core/org.eclipse.statet.rj.server/schema/RSetups.exsd b/core/org.eclipse.statet.rj.server/schema/RSetups.exsd
new file mode 100644
index 0000000..8c9bf96
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/schema/RSetups.exsd
@@ -0,0 +1,300 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<schema targetNamespace="org.eclipse.statet.rj" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema id="rSetups"
+ plugin="org.eclipse.statet.rj.server"
+ name="R Setups (Installations and Libraries)"/>
+ </appinfo>
+ <documentation>
+ This extension-point allows the definition and supply of R setups by Eclipse plug-ins. The definitions can be used to setup a correct environment to start R. In StatET they appear as preconfigured R environments.
+<p>An R setup (<code>setup</code>) is identified by an unique id. It is composed of the base R installation and optional additional R library locations.
+An installation element (<code>base</code>) provides the valid R home location for one or multiple platforms. Via the library locations (<code>library</code>) it is possible to supply additional libraries with R packages to the R library path.</p>
+<p>
+To separate platform dependent resources (base or library locations), Eclipse offers two options:</p>
+<ul>
+<li>(A) Fragments and specification of platform filter: A plug-in and for each platform, which should be supported, one fragment must be created. In the plug-in, the resource location is specified as usual as a directory name, but it does not provide the resources. Each fragment is assigned to one platform by the Eclipse bundle manifest headers <code>Eclipse-PlatformFilter</code> for the variables 'osgi.os' and 'osgi.arch' and provides the platform dependent resources in the directory specified in the plug-in.</li>
+<li>(B) Platform specific directories: The resource location is specified as operation system dependend in the plug-in by prefixing <code>$os$/</code> to the directory name. When loading the resources, <code>$os$</code> is resolved to <code>os/&lt;osgi.os&gt;/&lt;osgi.arch&gt;</code>, whereas <code>&lt;osgi.os&gt;</code> and <code>&lt;osgi.arch&gt;</code> are replace by the known constants defining the platform.</li>
+</ul>
+<p>
+Both methods can also be combined. The method (A) allows separate installation and updates, while the handling with method (B) is more compact. Known constants for the operation systems ('osgi.os') and system architectures ('osgi.arch') can be found in the class <code>org.eclipse.core.runtime.Platform</code>.
+<p>
+Additional hints for bundles providing base or library elements:</p>
+<ul>
+<li>When integrating the plug-in or fragment in a feature set, it is recommend to enable <code>unpack</code> option for that bundle.</li>
+</ul>
+<p>
+The existence and documentation of this extension-point does not give any advice whether it is legal to distribute R and/or R packages together with other software in your individual situation.</p>
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <choice minOccurs="1" maxOccurs="unbounded">
+ <element ref="setup"/>
+ <element ref="base"/>
+ <element ref="library"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="setup">
+ <annotation>
+ <documentation>
+ The element presents a single R setup.
+It is identified by its unique id. To make it useful for a platform, it is necessary to register at least the base element for that R setup and platform.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ A unique id for the R setup.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string" use="required">
+ <annotation>
+ <documentation>
+ A name for the R setup.
+<p>
+The name is used in GUIs, so that the user can identify the R setup</p>
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="version" type="string">
+ <annotation>
+ <documentation>
+ The version string for the R version. This property is only for information like the name.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="inheritBase" type="string">
+ <annotation>
+ <documentation>
+ The id of an R setup, the base elements (R installations) are inherited from.
+<p>
+Using this attribute enables to reuse the base installations with other R libraries. It is recommend to inheret only from R setups controlled by you or defined cleary with version number.</p>
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.statet.rj.RSetups/setup/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="base">
+ <annotation>
+ <documentation>
+ The element provides a R base installation with a valid R home location (correponding to the environment variable <code>R_HOME</code>).
+<p>
+It is invalid to register multiple base installation for the same R setup. See general description how to provide installations for several platforms.</p>
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="setupId" type="string" use="required">
+ <annotation>
+ <documentation>
+ The id of the R setup.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.statet.rj.RSetups/setup/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="location" type="string" use="required">
+ <annotation>
+ <documentation>
+ The R home directory location of the base installation.
+The sub-directories are <code>bin</code>, <code>doc</code>, ...
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="resource"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="library">
+ <annotation>
+ <documentation>
+ The element provides an R library with R packages.
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="setupId" type="string" use="required">
+ <annotation>
+ <documentation>
+ The id of the R setup.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="identifier" basedOn="org.eclipse.statet.rj.RSetups/setup/@id"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ <attribute name="group">
+ <annotation>
+ <documentation>
+ The id of the group the library should be registered in. The ids correspond to the environment variables for the groups:<ul>
+<li><code>R_LIBS_SITE</code> - R site library</li>
+<li><code>R_LIBS</code> - Additional R library</li>
+<li><code>R_LIBS_USER</code> - R user library</li>
+</ul>
+If not specified, <code>R_LIBS</code> is used.
+ </documentation>
+ </annotation>
+ <simpleType>
+ <restriction base="string">
+ <enumeration value="R_LIBS_SITE">
+ </enumeration>
+ <enumeration value="R_LIBS">
+ </enumeration>
+ <enumeration value="R_LIBS_USER">
+ </enumeration>
+ </restriction>
+ </simpleType>
+ </attribute>
+ <attribute name="location" type="string" use="required">
+ <annotation>
+ <documentation>
+ The directory location of the R library.
+The sub-directories represent the R packages.
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="resource"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ 0.5.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ <i>Definition of an R setup, its base installation and an add-on:</i><br/>
+<br/>
+<i>1)</i> General definition of the R setup and definition of the location for the base installation, suppporting one or multiple platforms by using method (A). Both declared in the <code>plugin.xml</code>:
+<pre>
+<extension point="org.eclipse.statet.rj.RSetups">
+ <setup id="myapp.RSetup"
+ name="Integrated R Engine"
+ version="2.10.1">
+ </setup>
+ <base
+ setupId="myapp.RSetup"
+ location="rhome/">
+ </base>
+</extension>
+</pre>
+The R home directories can be provided directly in the same plug-in (only a single platform is possible) or by platform specified fragments. The directory named <code>rhome</code> is always located at the root of the plug-in or fragment.
+<br/>
+When using method (A) with fragments to support multiple platforms, a platform filter for 32-bit Windows in the <code>MANIFEST.MF</code> file of the fragment would be:
+<pre>
+Eclipse-PlatformFilter: (& (osgi.os=win32) (osgi.arch=x86))
+</pre>
+
+<br/>
+<i>2)</i> An application plug-in which provides an special analysis methods, can plug-in its R package to the R setup for several platforms by using method (B). Library declared in the <code>plugin.xml</code>:
+<pre>
+<extension point="org.eclipse.statet.rj.RSetups">
+ <library
+ setupId="myapp.RSetup"
+ location="$os$/rpackages/">
+ </library>
+</extension>
+</pre>
+
+The directory structure for the platfrom specific R libraries would look like:
+<pre>
+<plug-in root>
+ + os
+ + linux
+ + x86
+ + rpackages
+ - package1
+ - package2
+ + x86_64
+ + rpackages
+ - package1
+ - package2
+ + win32
+ + x86
+ + rpackages
+ - package1
+ - package2
+ + x86_64
+ + rpackages
+ - package1
+ - package2
+</pre>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+which is available at https://www.apache.org/licenses/LICENSE-2.0.
+
+SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+
+Contributors:
+ Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjClosedException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjClosedException.java
new file mode 100644
index 0000000..f31e282
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjClosedException.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+/**
+ * Exception indicating that the used connection (to R) is already closed
+ */
+public class RjClosedException extends RjException {
+
+
+ private static final long serialVersionUID= 5199233227969338152L;
+
+
+ public RjClosedException(final String message) {
+ super(message);
+ }
+
+ public RjClosedException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjException.java
new file mode 100644
index 0000000..39b10f4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjException.java
@@ -0,0 +1,32 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+public class RjException extends Exception{
+
+
+ private static final long serialVersionUID= -2512905056010292440L;
+
+
+ public RjException(final String message) {
+ super(message);
+ }
+
+ public RjException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInitFailedException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInitFailedException.java
new file mode 100644
index 0000000..113edf5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInitFailedException.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+/**
+ * Exception indicating that the initialization failed
+ */
+public class RjInitFailedException extends RjException {
+
+
+ private static final long serialVersionUID= -6199674887137008313L;
+
+
+ public RjInitFailedException(final String message) {
+ super(message);
+ }
+
+ public RjInitFailedException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInvalidConfigurationException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInvalidConfigurationException.java
new file mode 100644
index 0000000..77f55d6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/RjInvalidConfigurationException.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj;
+
+
+/**
+ * Exception indicating that setting the configuration failed because it is invalid
+ */
+public class RjInvalidConfigurationException extends RjException {
+
+
+ private static final long serialVersionUID= 6709030537472523580L;
+
+
+ public RjInvalidConfigurationException(final String message) {
+ super(message);
+ }
+
+ public RjInvalidConfigurationException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/AutoIdMap.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/AutoIdMap.java
new file mode 100644
index 0000000..bc89ecf
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/AutoIdMap.java
@@ -0,0 +1,55 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+final class AutoIdMap<E> {
+
+
+ private Object[] currentArray;
+
+
+ public AutoIdMap() {
+ this.currentArray= new Object[16];
+ }
+
+
+ public synchronized int put(final E e) {
+ final int size= this.currentArray.length;
+ for (int i= 1; i < size; i++) {
+ if (this.currentArray[i] == null) {
+ this.currentArray[i]= e;
+ return i;
+ }
+ }
+ final Object[] newArray= new Object[size+16];
+ System.arraycopy(this.currentArray, 0, newArray, 0, size);
+ newArray[size]= e;
+ this.currentArray= newArray;
+ return size;
+ }
+
+ @SuppressWarnings("unchecked")
+ public E get(final int id) {
+ return (E) this.currentArray[id];
+ }
+
+ public void remove(final int id) {
+ if (id > 0 && id < this.currentArray.length) {
+ this.currentArray[id]= null;
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/BinExchange.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/BinExchange.java
new file mode 100644
index 0000000..876f7df
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/BinExchange.java
@@ -0,0 +1,432 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.OutputStream;
+import java.rmi.Remote;
+
+import org.eclipse.statet.rj.RjException;
+
+
+/**
+ * Communication exchange object for a binary array/file
+ */
+public class BinExchange implements RjsComObject, Externalizable {
+
+ private final static int C2S= 0x00010000;
+ private final static int S2C= 0x00020000;
+ private final static int OM_2= 0x000f0000;
+ private final static int OC_2= ~OM_2;
+
+ private final static int UPLOAD= 0x00100000;
+ private final static int DOWNLOAD= 0x00200000;
+ private final static int OM_TYPE= 0x00f00000;
+
+ private static final int OM_CUSTOM= 0x0000ffff;
+
+ private final static int DEFAULT_BUFFER_SIZE= 8192;
+
+
+ private final static AutoIdMap<OutputStream> gCOutList= new AutoIdMap<>();
+
+
+ static RjsComConfig.PathResolver gSPathResolver= new RjsComConfig.PathResolver() {
+ @Override
+ public File resolve(final Remote client, final String path) throws RjException {
+ final File file= new File(path);
+ if (!file.isAbsolute()) {
+ throw new RjException("Relative path not supported.");
+ }
+ return file;
+ }
+ };
+
+
+ private int options;
+ private Remote ref;
+
+ private String remoteFilePath;
+ private RjsStatus status;
+
+ private long inputLength;
+ private InputStream inputStream;
+ private int outputId;
+ private byte[] bytes;
+
+
+ /**
+ * Constructor for clients to upload a file
+ * @param in input stream to read the content from
+ * @param length length
+ * @param path remote file path
+ */
+ public BinExchange(final InputStream in, final long length, final String path, final Remote ref, final int options) {
+ if (path == null || in == null || ref == null) {
+ throw new NullPointerException();
+ }
+ if (path.length() <= 0) {
+ throw new IllegalArgumentException("Invalid path: empty.");
+ }
+ if (length < 0) {
+ throw new IllegalArgumentException("Invalid length: negative.");
+ }
+
+ this.options= ((C2S | UPLOAD) | (OM_CUSTOM & options));
+ this.ref= ref;
+ this.remoteFilePath= path;
+ this.inputLength= length;
+ this.inputStream= in;
+ this.outputId= 0;
+ }
+
+ /**
+ * Constructor for clients to download a file
+ * @param out output stream to write the content to
+ * @param path remote file path
+ * @param options
+ */
+ public BinExchange(final OutputStream out, final String path, final Remote ref, final int options) {
+ if (path == null || out == null || ref == null) {
+ throw new NullPointerException();
+ }
+ if (path.length() == 0) {
+ throw new IllegalArgumentException("Illegal path argument.");
+ }
+
+ this.options= (C2S | DOWNLOAD) | (OM_CUSTOM & options);
+ this.ref= ref;
+ this.inputLength= -1;
+ this.inputStream= null;
+ this.outputId= gCOutList.put(out);
+ this.remoteFilePath= path;
+ }
+
+ /**
+ * Constructor for clients to download a file into a byte array
+ * @param path remote file path
+ * @param options
+ */
+ public BinExchange(final String path, final Remote ref, final int options) {
+ if (path == null || ref == null) {
+ throw new NullPointerException();
+ }
+ if (path.length() == 0) {
+ throw new IllegalArgumentException("Illegal path argument.");
+ }
+
+ this.options= (C2S | DOWNLOAD) | (OM_CUSTOM & options);
+ this.ref= ref;
+ this.inputLength= -1;
+ this.inputStream= null;
+ this.outputId= 0;
+ this.remoteFilePath= path;
+ }
+
+ /**
+ * Constructor for automatic deserialization
+ */
+ public BinExchange() {
+ }
+
+
+ @Override
+ public int getComType() {
+ return T_FILE_EXCHANGE;
+ }
+
+ public boolean isOK() {
+ return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+ }
+
+ public RjsStatus getStatus() {
+ return this.status;
+ }
+
+ public String getFilePath() {
+ return this.remoteFilePath;
+ }
+
+ public byte[] getBytes() {
+ return this.bytes;
+ }
+
+ public void clear() {
+ gCOutList.remove(this.outputId);
+ }
+
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ final int readOptions= in.readInt();
+ this.remoteFilePath= in.readUTF();
+
+ switch (readOptions & (OM_TYPE | OM_2)) {
+
+ case C2S | UPLOAD: {
+ this.ref= (Remote) in.readObject();
+ long length= this.inputLength= in.readLong();
+ FileOutputStream output= null;
+ try {
+ final File file= (gSPathResolver != null) ? gSPathResolver.resolve(this.ref, this.remoteFilePath) : new File(this.remoteFilePath);
+ output= new FileOutputStream(file, false);
+ final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+ while (length > 0L) {
+ final int n= in.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+ if (n == -1) {
+ throw new IOException("Unexcepted end of stream.");
+ }
+ output.write(buffer, 0, n);
+ length-= n;
+ }
+ this.status= RjsStatus.OK_STATUS;
+ }
+ catch (final RjException e) {
+ this.status= new RjsStatus(RjsStatus.ERROR, 0, e.getMessage());
+ throw new IOException("Failed to resolve file path.");
+ }
+ catch (final IOException e) {
+ this.status= new RjsStatus(RjsStatus.ERROR, 0, e.getMessage());
+ throw new IOException("Failed to write stream to file.");
+ }
+ finally {
+ if (output != null) {
+ try {
+ output.close();
+ }
+ catch (final IOException e) {}
+ }
+ }
+ this.options= (readOptions & OC_2) | S2C;
+ return; }
+
+ case C2S | DOWNLOAD: {
+ this.ref= (Remote) in.readObject();
+ this.outputId= in.readInt();
+ this.options= (readOptions & OC_2) | S2C;
+ return; }
+
+ case S2C | UPLOAD: {
+ this.status= new RjsStatus(in);
+ this.options= (readOptions & OC_2);
+ return; }
+
+ case S2C | DOWNLOAD: {
+ this.outputId= in.readInt();
+ this.status= new RjsStatus(in);
+ if (this.status.getSeverity() == RjsStatus.OK) {
+ long length= this.inputLength= in.readLong();
+ boolean writing= false;
+ try {
+ if (this.outputId > 0) {
+ final OutputStream out= gCOutList.get(this.outputId);
+ final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+ while (length > 0) {
+ final int n= in.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+ if (n == -1) {
+ throw new IOException("Unexcepted end of stream.");
+ }
+ length-= n;
+ writing= true;
+ out.write(buffer, 0, n);
+ writing= false;
+ }
+ }
+ else {
+ if (length > Integer.MAX_VALUE) {
+ throw new UnsupportedOperationException();
+ }
+ this.bytes= new byte[(int) length];
+ while (length > 0) {
+ final int n= in.read(this.bytes, (int) (this.inputLength-length), (int) length);
+ if (n == -1) {
+ throw new IOException("Unexcepted end of stream.");
+ }
+ length-= n;
+ }
+ }
+ }
+ catch (IOException e) {
+ if (writing) {
+ this.status= new RjsStatus(RjsStatus.ERROR, 0, "Writing download to stream failed: " + e.getMessage());
+ try {
+ while (length > 0) {
+ final long n= in.skip(length);
+ if (n == -1) {
+ throw new IOException("Unexcepted end of stream.");
+ }
+ length-= n;
+ }
+ return;
+ }
+ catch (final IOException e2) {
+ e= e2;
+ }
+ }
+ throw e;
+ }
+ }
+ this.options= (readOptions & OC_2);
+ return; }
+
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.options);
+ out.writeUTF(this.remoteFilePath);
+
+ switch (this.options & (OM_TYPE | OM_2)) {
+
+ case C2S | UPLOAD: {
+ out.writeObject(this.ref);
+ out.writeLong(this.inputLength);
+ if (this.inputStream != null) {
+ final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+ long length= this.inputLength;
+ while (length > 0) {
+ final int n= this.inputStream.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+ if (n == -1) {
+ throw new IOException("Unexcepted end of stream.");
+ }
+ out.write(buffer, 0, n);
+ length-= n;
+ }
+ }
+ else if (this.bytes != null) {
+ out.writeLong(this.inputLength);
+ out.write(this.bytes, 0, (int) this.inputLength);
+ }
+ else {
+ throw new IOException("Missing file content.");
+ }
+ return; }
+
+ case C2S | DOWNLOAD: {
+ out.writeObject(this.ref);
+ out.writeInt(this.outputId);
+ return; }
+
+ case S2C | UPLOAD: {
+ this.status.writeExternal(out);
+ return; }
+
+ case S2C | DOWNLOAD: {
+ out.writeInt(this.outputId);
+ FileInputStream input= null;
+ try {
+ final File file= (gSPathResolver != null) ? gSPathResolver.resolve(this.ref, this.remoteFilePath) : new File(this.remoteFilePath);
+ try {
+ input= new FileInputStream(file);
+ input.available();
+ }
+ catch (final IOException e) {
+ if (input != null) {
+ try {
+ input.close();
+ input= null;
+ }
+ catch (final IOException ignore) {}
+ }
+ if (!file.exists() || e instanceof FileNotFoundException) {
+ new RjsStatus(RjsStatus.ERROR, 0, "Failed to find file '"+ this.remoteFilePath + "'.").writeExternal(out);
+ }
+ else {
+ new RjsStatus(RjsStatus.ERROR, 0, "Failed to open file '"+ this.remoteFilePath + "'.").writeExternal(out);
+ }
+ }
+ if (input != null) {
+ RjsStatus.OK_STATUS.writeExternal(out);
+ long length= this.inputLength= file.length();
+ out.writeLong(length);
+ final byte[] buffer= new byte[DEFAULT_BUFFER_SIZE];
+ while (length > 0) {
+ final int n= input.read(buffer, 0, (int) Math.min(DEFAULT_BUFFER_SIZE, length));
+ if (n == -1) {
+ throw new IOException("Unexcepted end of file content.");
+ }
+ length-= n;
+ out.write(buffer, 0, n);
+ }
+ }
+ }
+ catch (final RjException e) {
+ this.status= new RjsStatus(RjsStatus.ERROR, 0, e.getMessage());
+ throw new IOException("Failed to resolve file path.");
+ }
+ finally {
+ if (input != null) {
+ try {
+ input.close();
+ }
+ catch (final IOException ignore) {}
+ }
+ }
+ return; }
+
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(128);
+ sb.append("DataCmdItem ");
+ switch (this.options & OM_TYPE) {
+ case UPLOAD:
+ sb.append("UPLOAD");
+ break;
+ case DOWNLOAD:
+ sb.append("DOWNLOAD");
+ break;
+ default:
+ sb.append((this.options & OM_TYPE));
+ break;
+ }
+ sb.append("\n\t").append("direction= ");
+ switch (this.options & OM_2) {
+ case C2S:
+ sb.append("CLIENT-2-SERVER");
+ break;
+ case S2C:
+ sb.append("SERVER-2-CLIENT");
+ break;
+ default:
+ sb.append((this.options & OM_2));
+ }
+ sb.append("\n\tlength= ");
+ sb.append(this.inputLength);
+ if (this.status != null) {
+ sb.append("\n<STATUS>\n");
+ this.status.getCode();
+ sb.append("\n</STATUS>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ComHandler.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ComHandler.java
new file mode 100644
index 0000000..5628389
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ComHandler.java
@@ -0,0 +1,26 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+
+
+public interface ComHandler {
+
+
+ public void processMainCmd(ObjectInput in) throws IOException;
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleMessageCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleMessageCmdItem.java
new file mode 100644
index 0000000..a4903bd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleMessageCmdItem.java
@@ -0,0 +1,105 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console messages.
+ */
+public final class ConsoleMessageCmdItem extends MainCmdItem {
+
+
+ private final String text;
+
+
+ public ConsoleMessageCmdItem(final String text) {
+ assert (text != null);
+ this.text= text;
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public ConsoleMessageCmdItem(final RJIO in) throws IOException, ClassNotFoundException {
+ this.text= in.readString();
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeString(this.text);
+ }
+
+
+ @Override
+ public byte getCmdType() {
+ return T_MESSAGE_ITEM;
+ }
+
+ @Override
+ public byte getOp() {
+ return 0;
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean isOK() {
+ return true;
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ return null;
+ }
+
+ @Override
+ public String getDataText() {
+ return this.text;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof ConsoleMessageCmdItem)) {
+ return false;
+ }
+ final ConsoleMessageCmdItem otherItem= (ConsoleMessageCmdItem) other;
+ if (this.options != otherItem.options) {
+ return false;
+ }
+ return (this.text.equals(otherItem.getDataText()));
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(128);
+ sb.append("ConsoleMessageCmdItem");
+ sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+ sb.append("\n<TEXT>\n");
+ sb.append(this.text);
+ sb.append("\n</TEXT>");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleReadCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleReadCmdItem.java
new file mode 100644
index 0000000..c4ae25f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleReadCmdItem.java
@@ -0,0 +1,135 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console prompt/input.
+ */
+public final class ConsoleReadCmdItem extends MainCmdItem {
+
+
+ public static final int O_ADD_TO_HISTORY= 0;
+
+
+ private static final int OV_WITHTEXT= 0x01000000;
+
+
+ private String text;
+
+
+ public ConsoleReadCmdItem(final int options, final String text) {
+ assert (text != null);
+ this.options= (options | (OV_WITHTEXT | OM_WAITFORCLIENT));
+ this.text= text;
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public ConsoleReadCmdItem(final RJIO in) throws IOException {
+ this.requestId= in.readInt();
+ this.options= in.readInt();
+ if ((this.options & OV_WITHTEXT) != 0) {
+ this.text= in.readString();
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.requestId);
+ out.writeInt(this.options);
+ if ((this.options & OV_WITHTEXT) != 0) {
+ out.writeString(this.text);
+ }
+ }
+
+
+ @Override
+ public byte getCmdType() {
+ return T_CONSOLE_READ_ITEM;
+ }
+
+ @Override
+ public byte getOp() {
+ return 0;
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+ }
+
+ public void setAnswer(final String text) {
+ assert (text != null);
+ this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHTEXT);
+ this.text= text;
+ }
+
+
+ @Override
+ public boolean isOK() {
+ return ((this.options & OM_STATUS) == RjsStatus.OK);
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ return null;
+ }
+
+ @Override
+ public String getDataText() {
+ return this.text;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof ConsoleReadCmdItem)) {
+ return false;
+ }
+ final ConsoleReadCmdItem otherItem= (ConsoleReadCmdItem) other;
+ if (this.options != otherItem.options) {
+ return false;
+ }
+ if (((this.options & OV_WITHTEXT) != 0)
+ && !this.text.equals(otherItem.getDataText())) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(128);
+ sb.append("ConsoleReadCmdItem");
+ sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+ if ((this.options & OV_WITHTEXT) != 0) {
+ sb.append("\n<TEXT>\n");
+ sb.append(this.text);
+ sb.append("\n</TEXT>");
+ }
+ else {
+ sb.append("\n<TEXT/>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleWriteCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleWriteCmdItem.java
new file mode 100644
index 0000000..1b36ab4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ConsoleWriteCmdItem.java
@@ -0,0 +1,114 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console output.
+ */
+public final class ConsoleWriteCmdItem extends MainCmdItem {
+
+
+ public static final byte R_OUTPUT= 1;
+ public static final byte R_ERROR= 2;
+ public static final byte SYS_OUTPUT= 5;
+
+
+ private final byte streamId;
+
+ private final String text;
+
+
+ public ConsoleWriteCmdItem(final byte streamId, final String text) {
+ assert (text != null);
+ this.streamId= streamId;
+ this.text= text;
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public ConsoleWriteCmdItem(final RJIO in) throws IOException {
+ this.streamId= in.readByte();
+ this.text= in.readString();
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeByte(this.streamId);
+ out.writeString(this.text);
+ }
+
+
+ @Override
+ public byte getCmdType() {
+ return T_CONSOLE_WRITE_ITEM;
+ }
+
+ @Override
+ public byte getOp() {
+ return this.streamId;
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean isOK() {
+ return true;
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ return null;
+ }
+
+ @Override
+ public String getDataText() {
+ return this.text;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof ConsoleWriteCmdItem)) {
+ return false;
+ }
+ final ConsoleWriteCmdItem otherItem= (ConsoleWriteCmdItem) other;
+ return (this.options == otherItem.options
+ && this.streamId == otherItem.streamId
+ && this.text.equals(otherItem.getDataText()) );
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(128);
+ sb.append("ConsoleWriteCmdItem (").append(this.streamId).append(")");
+ sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+ sb.append("\n<TEXT>\n");
+ sb.append(this.text);
+ sb.append("\n</TEXT>");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/CtrlCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/CtrlCmdItem.java
new file mode 100644
index 0000000..3b25b88
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/CtrlCmdItem.java
@@ -0,0 +1,108 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+/**
+ * Client-to-Server list with {@link MainCmdItem}s.
+ */
+public final class CtrlCmdItem implements RjsComObject, RJIOExternalizable, Externalizable {
+
+
+ public static final int REQUEST_CANCEL= 1;
+ public static final int REQUEST_HOT_MODE= 2;
+
+
+ private int ctrl;
+
+
+ public CtrlCmdItem(final int ctrlId) {
+ this.ctrl= ctrlId;
+ }
+
+ /**
+ * Constructor for automatic deserialization
+ */
+ public CtrlCmdItem() {
+ }
+
+ /**
+ * Constructor for automatic deserialization
+ * @throws IOException
+ */
+ public CtrlCmdItem(final RJIO in) throws IOException {
+ this.ctrl= in.readInt();
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ this.ctrl= in.readInt();
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.ctrl);
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeInt(this.ctrl);
+ }
+
+
+ @Override
+ public int getComType() {
+ return RjsComObject.T_CTRL;
+ }
+
+ public int getCtrlId() {
+ return this.ctrl;
+ }
+
+
+ public boolean testEquals(final CtrlCmdItem other) {
+ if (this.ctrl != other.ctrl) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(64);
+ sb.append("CtrlCmdItem ");
+ switch (this.ctrl) {
+ case REQUEST_CANCEL:
+ sb.append("REQUEST_CANCEL");
+ break;
+ case REQUEST_HOT_MODE:
+ sb.append("REQUEST_HOT_MODE");
+ break;
+ default:
+ sb.append(this.ctrl);
+ break;
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DataCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DataCmdItem.java
new file mode 100644
index 0000000..c403637
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DataCmdItem.java
@@ -0,0 +1,462 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RObjectFactory;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+
+
+/**
+ * Command item for main loop data exchange/evaluation
+ */
+public final class DataCmdItem extends MainCmdItem {
+
+
+ public static final class Operation {
+
+ public static final byte NONE= 0;
+ public static final byte EXPR= 1;
+ public static final byte POINTER= 2;
+ public static final byte FCALL= 3;
+ public static final byte RDATA= 4;
+
+ public final byte op;
+
+ public final String name;
+
+ public final byte source;
+ public final byte target;
+ public final boolean returnData;
+
+ private final boolean reqSourceExpr;
+ private final boolean reqRData;
+ private final boolean reqTargetExpr;
+
+ private Operation(final String name, final int op,
+ final byte source, final byte target, final boolean returnData) {
+ this.op= (byte) op;
+ this.name= name;
+ this.source= source;
+ this.target= target;
+ this.returnData= returnData;
+
+ this.reqSourceExpr= (source == EXPR || source == POINTER || source == FCALL);
+ this.reqRData= (source == FCALL || source == RDATA);
+ this.reqTargetExpr= (target == EXPR || target == POINTER);
+ }
+
+
+ @Override
+ public String toString() {
+ return this.name;
+ }
+
+ }
+
+
+ public static final Operation EVAL_EXPR_VOID= new Operation("EVAL_EXPR_VOID", 1, //$NON-NLS-1$
+ Operation.EXPR, Operation.NONE, false);
+ public static final Operation EVAL_FCALL_VOID= new Operation("EVAL_FCALL_VOID", 2, //$NON-NLS-1$
+ Operation.FCALL, Operation.NONE, false);
+
+ public static final Operation EVAL_EXPR_DATA= new Operation("EVAL_EXPR_DATA", 3, //$NON-NLS-1$
+ Operation.EXPR, Operation.NONE, true);
+ public static final Operation EVAL_FCALL_DATA= new Operation("EVAL_FCALL_DATA", 4, //$NON-NLS-1$
+ Operation.FCALL, Operation.NONE, true);
+ public static final Operation RESOLVE_DATA= new Operation("RESOLVE_DATA", 5, // EVAL_REF_DATA //$NON-NLS-1$
+ Operation.POINTER, Operation.NONE, true);
+
+ public static final Operation ASSIGN_DATA= new Operation("ASSIGN_DATA", 6, //$NON-NLS-1$
+ Operation.RDATA, Operation.EXPR, false);
+ public static final Operation ASSIGN_FCALL= new Operation("ASSIGN_FCALL", 7, //$NON-NLS-1$
+ Operation.FCALL, Operation.EXPR, false);
+
+ public static final int FIND_DATA_OP= 8;
+ public static final Operation FIND_DATA= new Operation("FIND_DATA", FIND_DATA_OP, //$NON-NLS-1$
+ Operation.EXPR, Operation.NONE, true);
+
+ public static final int EVAL_NAMESPACE_DATA_OP= 9;
+ public static final Operation EVAL_NAMESPACE_DATA= new Operation("EVAL_NAMESPACE_DATA", EVAL_NAMESPACE_DATA_OP, //$NON-NLS-1$
+ Operation.EXPR, Operation.NONE, false);
+ public static final int EVAL_NAMESPACE_EXPORTS_DATA_OP= 10;
+ public static final Operation EVAL_NAMESPACE_EXPORTS_DATA= new Operation("EVAL_NAMESPACE_EXPORTS_DATA", EVAL_NAMESPACE_EXPORTS_DATA_OP, //$NON-NLS-1$
+ Operation.EXPR, Operation.NONE, false);
+
+
+ private static final Operation[] OPERATIONS= new Operation[11];
+
+ private static final void addOp(final Operation operation) {
+ if (OPERATIONS[operation.op] != null) {
+ throw new IllegalArgumentException();
+ }
+ OPERATIONS[operation.op]= operation;
+ }
+
+ private static final Operation getOperation(final byte op) {
+ if (op <= 0 || op >= OPERATIONS.length) {
+ throw new UnsupportedOperationException("data op: " + op); //$NON-NLS-1$
+ }
+ return OPERATIONS[op];
+ }
+
+ static {
+ addOp(EVAL_EXPR_VOID);
+ addOp(EVAL_FCALL_VOID);
+ addOp(EVAL_EXPR_DATA);
+ addOp(EVAL_FCALL_DATA);
+ addOp(RESOLVE_DATA);
+ addOp(ASSIGN_DATA);
+ addOp(ASSIGN_FCALL);
+ addOp(FIND_DATA);
+ addOp(EVAL_NAMESPACE_DATA);
+ addOp(EVAL_NAMESPACE_EXPORTS_DATA);
+ }
+
+
+ private static final int OV_WITHDATA= 0x02000000;
+ private static final int OV_WITHRHO= 0x04000000;
+ private static final int OV_WITHSTATUS= 0x08000000;
+
+
+ public static final String DEFAULT_FACTORY_ID= "default"; //$NON-NLS-1$
+
+
+ static RObjectFactory gDefaultFactory;
+
+ static final Map<String, RObjectFactory> gFactories= new ConcurrentHashMap<>();
+
+ private static final RObjectFactory getFactory(final String id) {
+ final RObjectFactory factory= gFactories.get(id);
+ if (factory != null) {
+ return factory;
+ }
+ return gDefaultFactory;
+ }
+
+ static {
+ RjsComConfig.setDefaultRObjectFactory(DefaultRObjectFactory.INSTANCE);
+ }
+
+
+ private final Operation operation;
+
+ private byte depth;
+ private String sourceExpr;
+ private String targetExpr;
+ private RObject rdata;
+ private RObject rho;
+
+ private String factoryId;
+
+ private RjsStatus status;
+
+
+ /**
+ * Constructor for operations with returned data
+ */
+ public DataCmdItem(final Operation op, final int options, final byte depth,
+ final String sourceExpr, final RObject data, final String targetExpr,
+ final RObject rho,
+ final String factoryId) {
+ assert (op.reqSourceExpr == (sourceExpr != null));
+ assert (op.reqRData == (data != null));
+ assert (op.reqTargetExpr == (targetExpr != null));
+ assert (factoryId == null || gFactories.containsKey(factoryId));
+ this.operation= op;
+ this.sourceExpr= sourceExpr;
+ this.targetExpr= targetExpr;
+ this.options= (OV_WAITFORCLIENT | (options & OM_CUSTOM));
+ if (data != null) {
+ this.rdata= data;
+ this.options |= OV_WITHDATA;
+ }
+ if (rho != null) {
+ this.rho= rho;
+ this.options |= OV_WITHRHO;
+ }
+ this.depth= depth;
+ this.factoryId= (factoryId != null) ? factoryId : DEFAULT_FACTORY_ID;
+ }
+
+ /**
+ * Constructor for operations without returned data:
+ */
+ public DataCmdItem(final Operation op, final int options,
+ final String sourceExpr, final RObject data, final String targetExpr,
+ final RObject rho) {
+ assert (op.reqSourceExpr == (sourceExpr != null));
+ assert (op.reqRData == (data != null));
+ assert (op.reqTargetExpr == (targetExpr != null));
+ this.operation= op;
+ this.sourceExpr= sourceExpr;
+ this.targetExpr= targetExpr;
+ this.options= (OV_WAITFORCLIENT | (options & OM_CUSTOM));
+ if (data != null) {
+ this.rdata= data;
+ this.options |= OV_WITHDATA;
+ }
+ if (rho != null) {
+ this.rho= rho;
+ this.options |= OV_WITHRHO;
+ }
+ this.factoryId= "";
+ }
+
+
+ /**
+ * Constructor for deserialization
+ */
+ public DataCmdItem(final RJIO in) throws IOException {
+ this.requestId= in.readInt();
+ this.operation= getOperation(in.readByte());
+ this.options= in.readInt();
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ this.status= new RjsStatus(in);
+ return;
+ }
+ this.depth= in.readByte();
+ this.factoryId= in.readString();
+ if ((this.options & OV_ANSWER) == 0) { // request
+ if (this.operation.reqSourceExpr) {
+ this.sourceExpr= in.readString();
+ }
+ if (this.operation.reqRData) {
+ in.flags= 0;
+ this.rdata= gDefaultFactory.readObject(in);
+ }
+ if (this.operation.reqTargetExpr) {
+ this.targetExpr= in.readString();
+ }
+ if ((this.options & OV_WITHRHO) != 0) {
+ in.flags= 0;
+ this.rho= gDefaultFactory.readObject(in);
+ }
+ }
+ else { // answer
+ if ((this.options & OV_WITHDATA) != 0) {
+ in.flags= (this.options & 0xff);
+ this.rdata= getFactory(this.factoryId).readObject(in);
+ }
+ if ((this.options & OV_WITHRHO) != 0) {
+ in.flags= RObjectFactory.F_ONLY_STRUCT;
+ this.rho= getFactory(this.factoryId).readObject(in);
+ }
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.requestId);
+ out.writeByte(this.operation.op);
+ out.writeInt(this.options);
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ this.status.writeExternal(out);
+ return;
+ }
+ out.writeByte(this.depth);
+ out.writeString(this.factoryId);
+ if ((this.options & OV_ANSWER) == 0) { // request
+ if (this.operation.reqSourceExpr) {
+ out.writeString(this.sourceExpr);
+ }
+ if (this.operation.reqRData) {
+ out.flags= 0;
+ gDefaultFactory.writeObject(this.rdata, out);
+ }
+ if (this.operation.reqTargetExpr) {
+ out.writeString(this.targetExpr);
+ }
+ if ((this.options & OV_WITHRHO) != 0) {
+ out.flags= 0;
+ gDefaultFactory.writeObject(this.rho, out);
+ }
+ }
+ else { // anwser
+ if ((this.options & OV_WITHDATA) != 0) {
+ out.flags= (this.options & 0xff);
+ gDefaultFactory.writeObject(this.rdata, out);
+ }
+ if ((this.options & OV_WITHRHO) != 0) {
+ out.flags= RObjectFactory.F_ONLY_STRUCT;
+ gDefaultFactory.writeObject(this.rho, out);
+ }
+ }
+ }
+
+
+ @Override
+ public byte getCmdType() {
+ return T_DATA_ITEM;
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ assert (status != null);
+ if (status == RjsStatus.OK_STATUS) {
+ this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+ this.status= null;
+ this.sourceExpr= null;
+ this.rdata= null;
+ this.targetExpr= null;
+ this.rho= null;
+ }
+ else {
+ this.options= ((this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS));
+ this.status= status;
+ this.sourceExpr= null;
+ this.rdata= null;
+ this.targetExpr= null;
+ this.rho= null;
+ }
+ }
+
+ public void setAnswer(final RObject rdata, final RObject rho) {
+ this.options= ((this.options & OM_CLEARFORANSWER) | OV_ANSWER);
+ if (rdata != null) {
+ this.options |= OV_WITHDATA;
+ }
+ if (rho != null) {
+ this.options |= OV_WITHRHO;
+ }
+ this.status= null;
+ this.sourceExpr= null;
+ this.rdata= rdata;
+ this.targetExpr= null;
+ this.rho= rho;
+ }
+
+
+ @Override
+ public byte getOp() {
+ return this.operation.op;
+ }
+
+ public Operation getOperation() {
+ return this.operation;
+ }
+
+ @Override
+ public boolean isOK() {
+ return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ return this.status;
+ }
+
+ @Override
+ public String getDataText() {
+ return this.sourceExpr;
+ }
+
+ public RObject getData() {
+ return this.rdata;
+ }
+
+ public String getTargetExpr() {
+ return this.targetExpr;
+ }
+
+ public RObject getRho() {
+ return this.rho;
+ }
+
+ public byte getDepth() {
+ return this.depth;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof DataCmdItem)) {
+ return false;
+ }
+ final DataCmdItem otherItem= (DataCmdItem) other;
+ if (getOp() != otherItem.getOp()) {
+ return false;
+ }
+ if (this.options != otherItem.options) {
+ return false;
+ }
+ if (!((this.sourceExpr != null) ?
+ this.sourceExpr.equals(otherItem.sourceExpr) :
+ null == otherItem.sourceExpr )) {
+ return false;
+ }
+ if (!((this.rdata != null) ?
+ this.rdata.equals(otherItem.rdata) :
+ null == otherItem.rdata )) {
+ return false;
+ }
+ if (!((this.targetExpr != null) ?
+ this.targetExpr.equals(otherItem.targetExpr) :
+ null == otherItem.targetExpr )) {
+ return false;
+ }
+ if (!((this.rho != null) ?
+ this.rho.equals(otherItem.rho) :
+ null == otherItem.rho )) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(100);
+ sb.append("DataCmdItem ");
+ sb.append(this.operation.name);
+ sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+ if (this.sourceExpr != null) {
+ sb.append("\n<SOURCE-EXPR>\n");
+ sb.append(this.sourceExpr);
+ sb.append("\n</SOURCE-EXPR>");
+ }
+ else {
+ sb.append("\n<SOURCE-EXPR/>");
+ }
+ if ((this.options & OV_WITHDATA) != 0) {
+ sb.append("\n<DATA>\n");
+ sb.append(this.rdata.toString());
+ sb.append("\n</DATA>");
+ }
+ else {
+ sb.append("\n<DATA/>");
+ }
+ if (this.targetExpr != null) {
+ sb.append("\n<TARGET-EXPR>\n");
+ sb.append(this.targetExpr);
+ sb.append("\n</TARGET-EXPR>");
+ }
+ else {
+ sb.append("\n<TARGET-EXPR/>");
+ }
+ if ((this.options & OV_WITHRHO) != 0) {
+ sb.append("\n<RHO>\n");
+ sb.append(this.rho.toString());
+ sb.append("\n</RHO>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DbgCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DbgCmdItem.java
new file mode 100644
index 0000000..33a48ee
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/DbgCmdItem.java
@@ -0,0 +1,375 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.server.dbg.CallStack;
+import org.eclipse.statet.rj.server.dbg.CtrlReport;
+import org.eclipse.statet.rj.server.dbg.DbgEnablement;
+import org.eclipse.statet.rj.server.dbg.DbgFilterState;
+import org.eclipse.statet.rj.server.dbg.DbgRequest;
+import org.eclipse.statet.rj.server.dbg.ElementTracepointInstallationRequest;
+import org.eclipse.statet.rj.server.dbg.FlagTracepointInstallationRequest;
+import org.eclipse.statet.rj.server.dbg.FrameContext;
+import org.eclipse.statet.rj.server.dbg.FrameContextDetailRequest;
+import org.eclipse.statet.rj.server.dbg.SetDebugReport;
+import org.eclipse.statet.rj.server.dbg.SetDebugRequest;
+import org.eclipse.statet.rj.server.dbg.TracepointEvent;
+import org.eclipse.statet.rj.server.dbg.TracepointInstallationReport;
+import org.eclipse.statet.rj.server.dbg.TracepointStatesUpdate;
+
+
+/**
+ * Command item for main loop dbg operations (="op")
+ */
+public final class DbgCmdItem extends MainCmdItem implements RjsComObject, Externalizable {
+
+ // -- C2S sync
+ public static final byte OP_LOAD_FRAME_LIST= 0001;
+ public static final byte OP_LOAD_FRAME_CONTEXT= 0002;
+ public static final byte OP_SET_DEBUG= 0003;
+ public static final byte OP_REQUEST_SUSPEND= 0004;
+// public static final byte OP_CTRL_SUSPEND= 0010;
+ public static final byte OP_CTRL_RESUME= 0011;
+ public static final byte OP_CTRL_STEP_INTO= 0012;
+ public static final byte OP_CTRL_STEP_OVER= 0014;
+ public static final byte OP_CTRL_STEP_RETURN= 0016;
+ public static final byte OP_INSTALL_TP_FLAGS= 0020;
+ public static final byte OP_INSTALL_TP_POSITIONS= 0021;
+
+ // -- C2S sync + async
+ public static final byte OP_SET_ENABLEMENT= 0031;
+ public static final byte OP_RESET_FILTER_STATE= 0032;
+ public static final byte OP_UPDATE_TP_STATES= 0034;
+
+ public static final byte OP_C2S_S2C= 0040;
+
+ public static final byte OP_NOTIFY_TP_EVENT= 0x41;
+
+
+ private static final int OV_WITHDATA= 0x01000000;
+ private static final int OV_WITHSTATUS= 0x08000000;
+
+
+ public static interface CustomDataReader {
+
+ Object read(byte type, boolean answer, RJIO io) throws IOException;
+
+ }
+
+ private static Object readData(final RJIO io, final byte type, final boolean answer) throws IOException {
+ if (!answer) {
+ switch (type) {
+ case OP_LOAD_FRAME_LIST:
+ return null;
+ case OP_LOAD_FRAME_CONTEXT:
+ return new FrameContextDetailRequest(io);
+ case OP_SET_DEBUG:
+ return new SetDebugRequest(io);
+ case OP_REQUEST_SUSPEND:
+ return null;
+ case OP_CTRL_RESUME:
+ return new DbgRequest.Resume(io);
+ case OP_CTRL_STEP_INTO:
+ return new DbgRequest.StepInto(io);
+ case OP_CTRL_STEP_OVER:
+ return new DbgRequest.StepOver(io);
+ case OP_CTRL_STEP_RETURN:
+ return new DbgRequest.StepReturn(io);
+ case OP_SET_ENABLEMENT:
+ return new DbgEnablement(io);
+ case OP_RESET_FILTER_STATE:
+ return new DbgFilterState(io);
+ case OP_INSTALL_TP_FLAGS:
+ return new FlagTracepointInstallationRequest(io);
+ case OP_INSTALL_TP_POSITIONS:
+ return new ElementTracepointInstallationRequest(io);
+ case OP_UPDATE_TP_STATES:
+ return new TracepointStatesUpdate(io);
+ case OP_NOTIFY_TP_EVENT:
+ return new TracepointEvent(io);
+ default:
+ break;
+ }
+ throw new IOException("Unsupported type= " + type); //$NON-NLS-1$
+ }
+ else {
+ switch (type) {
+ case OP_LOAD_FRAME_LIST:
+ return new CallStack(io);
+ case OP_LOAD_FRAME_CONTEXT:
+ return new FrameContext(io);
+ case OP_SET_DEBUG:
+ return new SetDebugReport(io);
+ case OP_REQUEST_SUSPEND:
+ break; // status
+ case OP_CTRL_RESUME:
+ case OP_CTRL_STEP_INTO:
+ case OP_CTRL_STEP_OVER:
+ case OP_CTRL_STEP_RETURN:
+ return new CtrlReport(io);
+ case OP_SET_ENABLEMENT:
+ case OP_RESET_FILTER_STATE:
+ break; // status
+ case OP_INSTALL_TP_FLAGS:
+ case OP_INSTALL_TP_POSITIONS:
+ return new TracepointInstallationReport(io);
+ case OP_UPDATE_TP_STATES:
+ break; // status
+ default:
+ break;
+ }
+ throw new IOException("Unsupported type= " + type); //$NON-NLS-1$
+ }
+ }
+
+
+ private byte op;
+
+ private Object data;
+
+ private RjsStatus status;
+
+
+ /**
+ * Constructor for new commands
+ */
+ public DbgCmdItem(final byte op, final int options,
+ final RJIOExternalizable data) {
+ this.op= op;
+ this.options= (options & OM_CUSTOM);
+ if (data != null) {
+ this.options |= OV_WITHDATA;
+ }
+ if (op < OP_NOTIFY_TP_EVENT) {
+ this.options |= OV_WAITFORCLIENT;
+ }
+ this.data= data;
+ }
+
+ /**
+ * Constructor for automatic deserialization
+ */
+ public DbgCmdItem() {
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public DbgCmdItem(final RJIO io) throws IOException {
+ readExternal(io, null);
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public DbgCmdItem(final RJIO io, final CustomDataReader reader) throws IOException {
+ readExternal(io, reader);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.options);
+ io.writeByte(this.op);
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ this.status.writeExternal(io);
+ }
+ else if ((this.options & OV_WITHDATA) != 0) {
+ ((RJIOExternalizable) this.data).writeExternal(io);
+ }
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ final RJIO io= RJIO.get(out);
+ final int check= io.writeCheck1();
+ writeExternal(io);
+ io.writeCheck2(check);
+ io.disconnect(out);
+ }
+
+ private void readExternal(final RJIO io, final CustomDataReader reader) throws IOException {
+ this.options= io.readInt();
+ this.op= io.readByte();
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ this.status= new RjsStatus(io);
+ }
+ else if ((this.options & OV_WITHDATA) != 0) {
+ final boolean answer= ((this.options & OV_ANSWER) != 0);
+ if (reader != null) {
+ this.data= reader.read(this.op, answer, io);
+ if (this.data == null) {
+ this.data= readData(io, this.op, answer);
+ }
+ }
+ else {
+ this.data= readData(io, this.op, answer);
+ }
+ }
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ final RJIO io= RJIO.get(in);
+ final int check= io.readCheck1();
+ readExternal(io, null);
+ io.readCheck2(check);
+ io.disconnect(in);
+ }
+
+
+ @Override
+ public int getComType() {
+ return T_DBG;
+ }
+
+ @Override
+ public byte getCmdType() {
+ return T_DBG_ITEM;
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ assert (status != null);
+ if (status == RjsStatus.OK_STATUS) {
+ this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+ this.status= null;
+ this.data= null;
+ }
+ else {
+ this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS);
+ this.status= status;
+ this.data= null;
+ }
+ }
+
+ public void setAnswer(final RJIOExternalizable data) {
+ this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+ if (data != null) {
+ this.options |= OV_WITHDATA;
+ }
+ this.status= null;
+ this.data= data;
+ }
+
+
+ @Override
+ public byte getOp() {
+ return this.op;
+ }
+
+ @Override
+ public boolean isOK() {
+ return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ return this.status;
+ }
+
+ @Override
+ public String getDataText() {
+ return null;
+ }
+
+ public Object getData() {
+ return this.data;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof DbgCmdItem)) {
+ return false;
+ }
+ final DbgCmdItem otherItem= (DbgCmdItem) other;
+ if (getOp() != otherItem.getOp()) {
+ return false;
+ }
+ if (this.options != otherItem.options) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(100);
+ sb.append("DbgCmdItem "); //$NON-NLS-1$
+ switch (this.op) {
+ case OP_LOAD_FRAME_LIST:
+ sb.append("LOAD_FRAME_LIST"); //$NON-NLS-1$
+ break;
+ case OP_LOAD_FRAME_CONTEXT:
+ sb.append("LOAD_FRAME_CONTEXT"); //$NON-NLS-1$
+ break;
+ case OP_SET_DEBUG:
+ sb.append("SET_DEBUG"); //$NON-NLS-1$
+ break;
+ case OP_REQUEST_SUSPEND:
+ sb.append("REQUEST_SUSPEND"); //$NON-NLS-1$
+ break;
+ case OP_CTRL_RESUME:
+ sb.append("CTRL_RESUME"); //$NON-NLS-1$
+ break;
+ case OP_CTRL_STEP_INTO:
+ sb.append("CTRL_STEP_INTO"); //$NON-NLS-1$
+ break;
+ case OP_CTRL_STEP_OVER:
+ sb.append("CTRL_STEP_OVER"); //$NON-NLS-1$
+ break;
+ case OP_CTRL_STEP_RETURN:
+ sb.append("CTRL_STEP_RETURN"); //$NON-NLS-1$
+ break;
+ case OP_INSTALL_TP_FLAGS:
+ sb.append("INSTALL_TP_FLAGS"); //$NON-NLS-1$
+ break;
+ case OP_INSTALL_TP_POSITIONS:
+ sb.append("INSTALL_TP_POSITIONS"); //$NON-NLS-1$
+ break;
+ case OP_SET_ENABLEMENT:
+ sb.append("SET_ENABLEMENT"); //$NON-NLS-1$
+ break;
+ case OP_RESET_FILTER_STATE:
+ sb.append("RESET_FILTER_STATE"); //$NON-NLS-1$
+ break;
+ case OP_UPDATE_TP_STATES:
+ sb.append("UPDATE_TRACEPOINTS_STATES"); //$NON-NLS-1$
+ break;
+ case OP_NOTIFY_TP_EVENT:
+ sb.append("NOTIFY_TP_EVENT"); //$NON-NLS-1$
+ break;
+ default:
+ sb.append(this.op);
+ break;
+ }
+ sb.append("\n\t" + "options= 0x").append(Integer.toHexString(this.options)); //$NON-NLS-1$ //$NON-NLS-2$
+ if ((this.options & OV_WITHDATA) != 0) {
+ sb.append("\n<DATA>\n"); //$NON-NLS-1$
+ sb.append(this.data);
+ sb.append("\n</DATA>"); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ExtUICmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ExtUICmdItem.java
new file mode 100644
index 0000000..919c8b0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ExtUICmdItem.java
@@ -0,0 +1,172 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RList;
+
+
+/**
+ * Command item for main loop UI interaction.
+ */
+public final class ExtUICmdItem extends MainCmdItem {
+
+
+ private static final int OV_WITHMAP= 0x01000000;
+ private static final int OV_WITHSTATUS= 0x08000000;
+
+
+ private String command;
+ private RList data;
+
+ private RjsStatus status;
+
+
+ public ExtUICmdItem(final String command, final int options, final RList args, final boolean waitForClient) {
+ assert (command != null);
+ this.command= command;
+ this.options= (waitForClient) ?
+ (options | OM_WAITFORCLIENT) : (options);
+ if (args != null) {
+ this.options |= OV_WITHMAP;
+ this.data= args;
+ }
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public ExtUICmdItem(final RJIO io) throws IOException {
+ this.requestId= io.readInt();
+ this.command= io.readString();
+ this.options= io.readInt();
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ this.status= new RjsStatus(io);
+ return;
+ }
+ if ((this.options & OV_WITHMAP) != 0) {
+ io.flags= 0;
+ this.data= (RList) DataCmdItem.gDefaultFactory.readObject(io);
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.requestId);
+ out.writeString(this.command);
+ out.writeInt(this.options);
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ this.status.writeExternal(out);
+ return;
+ }
+ if ((this.options & OV_WITHMAP) != 0) {
+ out.flags= 0;
+ DataCmdItem.gDefaultFactory.writeObject(this.data, out);
+ }
+ }
+
+
+ @Override
+ public byte getCmdType() {
+ return T_EXTENDEDUI_ITEM;
+ }
+
+ @Override
+ public byte getOp() {
+ return 0;
+ }
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ assert (status != null);
+ if (status == RjsStatus.OK_STATUS) {
+ this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+ this.status= null;
+ }
+ else {
+ this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS);
+ this.status= status;
+ }
+ }
+
+ public void setAnswer(final RList answer) {
+ this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+ if (answer != null) {
+ this.options |= OV_WITHMAP;
+ }
+ this.status= null;
+ this.data= answer;
+ }
+
+
+ @Override
+ public boolean isOK() {
+ return (this.status == null || this.status.getSeverity() == RjsStatus.OK);
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ return this.status;
+ }
+
+ @Override
+ public String getDataText() {
+ return this.command;
+ }
+
+ public RList getDataArgs() {
+ return this.data;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof ExtUICmdItem)) {
+ return false;
+ }
+ final ExtUICmdItem otherItem= (ExtUICmdItem) other;
+ if (!getDataText().equals(otherItem.getDataText())) {
+ return false;
+ }
+ if (this.options != otherItem.options) {
+ return false;
+ }
+ if (((this.options & OV_WITHMAP) != 0)
+ && !getDataArgs().equals(otherItem.getDataArgs())) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(100);
+ sb.append("ExtUICmdItem ");
+ sb.append(this.command);
+ sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+ if ((this.options & OV_WITHMAP) != 0) {
+ sb.append("\n<ARGS>\n");
+ sb.append(this.data.toString());
+ sb.append("\n</ARGS>");
+ }
+ else {
+ sb.append("\n<ARGS/>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/FxCallback.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/FxCallback.java
new file mode 100644
index 0000000..3037f7d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/FxCallback.java
@@ -0,0 +1,60 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Serializable;
+
+import javax.security.auth.callback.Callback;
+
+
+/**
+ * Callback for authentication using file permission
+ */
+public class FxCallback implements Callback, Serializable {
+
+
+ private static final long serialVersionUID= 3559656299612581181L;
+
+
+ private final String filename;
+ private byte[] content;
+
+
+ public FxCallback(final String filename, final byte[] pendingKey) {
+ this.filename= filename;
+ this.content= pendingKey;
+ }
+
+
+ public String getFilename() {
+ return this.filename;
+ }
+
+ public byte[] createContent(final byte[] clientKey) {
+ if (clientKey == null) {
+ throw new NullPointerException();
+ }
+ final byte[] newContent= new byte[this.content.length+clientKey.length];
+ System.arraycopy(this.content, 0, newContent, 0, this.content.length);
+ System.arraycopy(clientKey, 0, newContent, this.content.length, clientKey.length);
+ this.content= clientKey;
+ return newContent;
+ }
+
+ public byte[] getContent() {
+ return this.content;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GDCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GDCmdItem.java
new file mode 100644
index 0000000..c5379cd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GDCmdItem.java
@@ -0,0 +1,1310 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command item for GD.
+ */
+public abstract class GDCmdItem extends MainCmdItem {
+
+
+ public static final byte SET_CLIP= 0x01;
+ public static final byte SET_COLOR= 0x02;
+ public static final byte SET_FILL= 0x03;
+ public static final byte SET_LINE= 0x04;
+ public static final byte SET_FONT= 0x05;
+
+ public static final byte DRAW_LINE= 0x11;
+ public static final byte DRAW_RECTANGLE= 0x12;
+ public static final byte DRAW_POLYLINE= 0x13;
+ public static final byte DRAW_POLYGON= 0x14;
+ public static final byte DRAW_PATH= 0x15;
+ public static final byte DRAW_CIRCLE= 0x16;
+ public static final byte DRAW_TEXT= 0x17;
+ public static final byte DRAW_RASTER= 0x18;
+
+ public static final byte CAPTURE= 0x1c;
+
+ public static final byte C_NEW_PAGE= 0x21;
+ public static final byte C_CLOSE_DEVICE= 0x22;
+ public static final byte C_GET_SIZE= 0x23;
+ public static final byte C_SET_ACTIVE_OFF= 0x24;
+ public static final byte C_SET_ACTIVE_ON= 0x25;
+ public static final byte C_SET_MODE= 0x26;
+ public static final byte C_GET_FONTMETRIC= 0x27;
+ public static final byte C_GET_STRINGWIDTH= 0x28;
+
+ public static final byte U_LOCATOR= 0x31;
+
+
+ private static final double[] NO_DATA= new double[0];
+
+
+ public static final class Answer extends GDCmdItem {
+
+
+ private static final int OM_WITHDATA= 0x07000000;
+ private static final int OV_WITHDOUBLE= 0x01000000;
+ private static final int OV_WITHBYTE= 0x02000000;
+
+ private final Object data;
+
+// use DoubleAnswer
+// public Answer(final byte requestId, final int devId, final double[] data) {
+// this.options= (data != null) ? (OV_WITHDOUBLE | OV_WAITFORCLIENT) : OV_WAITFORCLIENT;
+// this.devId= devId;
+// this.data= data;
+// this.requestId= requestId;
+// }
+
+ public Answer(final byte requestId, final int devId, final byte[] data) {
+ this.options= (data != null) ? (OV_WITHBYTE | OV_WAITFORCLIENT) : OV_WAITFORCLIENT;
+ this.devId= devId;
+ this.data= data;
+ this.requestId= requestId;
+ }
+
+ public Answer(final byte requestId, final int devId, final RjsStatus status) {
+ this.options= OV_WAITFORCLIENT | (status.getSeverity() << OS_STATUS);
+ this.devId= devId;
+ this.data= NO_DATA;
+ this.requestId= requestId;
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public Answer(final RJIO io) throws IOException, ClassNotFoundException {
+ this.options= io.readInt();
+ this.devId= io.readInt();
+ this.requestId= io.readByte();
+ switch (this.options & OM_WITHDATA) {
+ case OV_WITHDOUBLE: {
+ final double[] d= new double[io.readInt()];
+ io.readDoubleData(d, d.length);
+ this.data= d;
+ break; }
+ case OV_WITHBYTE: {
+ final byte[] b= new byte[io.readInt()];
+ io.readByteData(b, b.length);
+ this.data= b;
+ break; }
+ default:
+ this.data= null;
+ break;
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.options);
+ io.writeInt(this.devId);
+ io.writeByte(this.requestId);
+ switch (this.options & OM_WITHDATA) {
+ case OV_WITHDOUBLE: {
+ final double[] d= (double[]) this.data;
+ io.writeInt(d.length);
+ io.writeDoubleData(d, d.length);
+ break; }
+ case OV_WITHBYTE: {
+ final byte[] b= (byte[]) this.data;
+ io.writeInt(b.length);
+ io.writeByteData(b, b.length);
+ break; }
+ }
+ }
+
+
+ @Override
+ public double[] getDoubleData() {
+ return (double[]) this.data;
+ }
+
+ @Override
+ public byte[] getByteData() {
+ return (byte[]) this.data;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(100);
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=ANSWER");
+ sb.append(")");
+ sb.append("\n<GD-DATA>\n");
+ switch (this.options & OM_WITHDATA) {
+ case OV_WITHDOUBLE:
+ sb.append(Arrays.toString((double[]) this.data));
+ }
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DoubleAnswer extends GDCmdItem {
+
+
+ private final double[] data;
+
+
+ public DoubleAnswer(final byte requestId, final int devId, final double[] data) {
+ this.options= (data != null) ? (Answer.OV_WITHDOUBLE | OV_WAITFORCLIENT) : OV_WAITFORCLIENT;
+ this.devId= devId;
+ this.data= data;
+ this.requestId= requestId;
+ }
+
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.options);
+ io.writeInt(this.devId);
+ io.writeByte(this.requestId);
+ if (this.data != null) {
+ final int length= this.data.length;
+ io.writeInt(length);
+ io.writeDoubleData(this.data, length);
+ }
+ }
+
+
+ @Override
+ public double[] getDoubleData() {
+ return this.data;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(100);
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=ANSWER");
+ sb.append(")");
+ sb.append("\n<GD-DATA>\n");
+ sb.append(Arrays.toString(this.data));
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CInit extends GDCmdItem {
+
+
+ private final double w;
+ private final double h;
+ private final int canvasColor;
+ private final boolean active;
+
+
+ public CInit(final int devId, final double w, final double h, final int canvasColor,
+ final boolean activate, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.w= w;
+ this.h= h;
+ this.canvasColor= canvasColor;
+ this.active= activate;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(C_NEW_PAGE);
+ io.writeDouble(this.w);
+ io.writeDouble(this.h);
+ io.writeInt(this.canvasColor);
+ io.writeBoolean(this.active);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_NEW_PAGE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CCloseDevice extends GDCmdItem {
+
+
+ public CCloseDevice(final int devId, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(C_CLOSE_DEVICE);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_CLOSE_DEVICE);
+ sb.append(")\n<GD-DATA />");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CGetSize extends GDCmdItem {
+
+
+ public CGetSize(final int devId, final byte slot) {
+ this.options= OV_WAITFORCLIENT;
+ this.devId= devId;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt((OV_WAITFORCLIENT | this.devId));
+ io.writeByte(C_GET_SIZE);
+ io.writeByte(this.requestId);
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_GET_SIZE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CSetActiveOff extends GDCmdItem {
+
+
+ public CSetActiveOff(final int devId, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(C_SET_ACTIVE_OFF);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_SET_ACTIVE_OFF);
+ sb.append(")\n<GD-DATA />");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CSetActiveOn extends GDCmdItem {
+
+
+ public CSetActiveOn(final int devId, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(C_SET_ACTIVE_ON);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_SET_ACTIVE_ON);
+ sb.append(")\n<GD-DATA />");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CSetMode extends GDCmdItem {
+
+
+ private final byte mode;
+
+
+ public CSetMode(final int devId, final int mode, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.mode= (byte) mode;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(C_SET_MODE);
+ io.writeByte(this.mode);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_SET_MODE);
+ sb.append(")<GD-DATA>\nmode= ");
+ sb.append(this.mode);
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CGetFontMetric extends GDCmdItem {
+
+
+ private final int c;
+
+
+ public CGetFontMetric(final int devId, final int c, final byte slot) {
+ this.options= OV_WAITFORCLIENT;
+ this.devId= devId;
+ this.c= c;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt((OV_WAITFORCLIENT | this.devId));
+ io.writeByte(C_GET_FONTMETRIC);
+ io.writeByte(this.requestId);
+ io.writeInt(this.c);
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_GET_FONTMETRIC);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class CGetStrWidth extends GDCmdItem {
+
+
+ private final String text;
+
+
+ public CGetStrWidth(final int devId, final String text, final byte slot) {
+ this.options= OV_WAITFORCLIENT;
+ this.devId= devId;
+ this.text= text;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt((OV_WAITFORCLIENT | this.devId));
+ io.writeByte(C_GET_STRINGWIDTH);
+ io.writeByte(this.requestId);
+ io.writeString(this.text);
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(C_GET_STRINGWIDTH);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class SetClip extends GDCmdItem {
+
+
+ private final double x0;
+ private final double y0;
+ private final double x1;
+ private final double y1;
+
+
+ public SetClip(final int devId, final double x0, final double y0, final double x1, final double y1,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.x0= x0;
+ this.y0= y0;
+ this.x1= x1;
+ this.y1= y1;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(SET_CLIP);
+ io.writeDouble(this.x0);
+ io.writeDouble(this.y0);
+ io.writeDouble(this.x1);
+ io.writeDouble(this.y1);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(SET_CLIP);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class SetColor extends GDCmdItem {
+
+
+ private final int cc;
+
+
+ public SetColor(final int devId, final int cc, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.cc= cc;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(SET_COLOR);
+ io.writeInt(this.cc);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(SET_COLOR);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class SetFill extends GDCmdItem {
+
+
+ private final int cc;
+
+
+ public SetFill(final int devId, final int cc, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.cc= cc;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(SET_FILL);
+ io.writeInt(this.cc);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(SET_FILL);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class SetLine extends GDCmdItem {
+
+
+ private final int type;
+ private final float width;
+ private final byte cap;
+ private final byte join;
+ private final float joinMiterLimit;
+
+
+ public SetLine(final int devId, final int type, final float width,
+ final byte cap, final byte join, final float joinMiterLimit,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.type= type;
+ this.width= width;
+ this.cap= cap;
+ this.join= join;
+ this.joinMiterLimit= joinMiterLimit;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(SET_LINE);
+ io.writeInt(this.type);
+ io.writeFloat(this.width);
+ io.writeByte(this.cap);
+ io.writeByte(this.join);
+ io.writeFloat(this.joinMiterLimit);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(SET_LINE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class SetFont extends GDCmdItem {
+
+
+ private final String family;
+ private final int face;
+ private final float pointSize;
+ private final float lineHeight;
+
+
+ public SetFont(final int devId, final String family, final int face, final float pointSize,
+ final float lineHeight,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.family= family;
+ this.face= face;
+ this.pointSize= pointSize;
+ this.lineHeight= lineHeight;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(SET_FONT);
+ io.writeString(this.family);
+ io.writeInt(this.face);
+ io.writeFloat(this.pointSize);
+ io.writeFloat(this.lineHeight);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(SET_FONT);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawLine extends GDCmdItem {
+
+
+ private final double x0;
+ private final double y0;
+ private final double x1;
+ private final double y1;
+
+
+ public DrawLine(final int devId, final double x0, final double y0, final double x1, final double y1,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.x0= x0;
+ this.y0= y0;
+ this.x1= x1;
+ this.y1= y1;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_LINE);
+ io.writeDouble(this.x0);
+ io.writeDouble(this.y0);
+ io.writeDouble(this.x1);
+ io.writeDouble(this.y1);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_LINE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawRect extends GDCmdItem {
+
+
+ private final double x0;
+ private final double y0;
+ private final double x1;
+ private final double y1;
+
+
+ public DrawRect(final int devId, final double x0, final double y0, final double x1, final double y1,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.x0= x0;
+ this.y0= y0;
+ this.x1= x1;
+ this.y1= y1;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_RECTANGLE);
+ io.writeDouble(this.x0);
+ io.writeDouble(this.y0);
+ io.writeDouble(this.x1);
+ io.writeDouble(this.y1);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_RECTANGLE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawPolyline extends GDCmdItem {
+
+
+ private final double x[];
+ private final double y[];
+
+
+ public DrawPolyline(final int devId, final double x[], final double y[],
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.x= x;
+ this.y= y;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_POLYLINE);
+ final int length= this.x.length;
+ io.writeInt(length);
+ io.writeDoubleData(this.x, length);
+ io.writeDoubleData(this.y, length);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_POLYLINE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawPolygon extends GDCmdItem {
+
+
+ private final double x[];
+ private final double y[];
+
+
+ public DrawPolygon(final int devId, final double x[], final double y[],
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.x= x;
+ this.y= y;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_POLYGON);
+ final int length= this.x.length;
+ io.writeInt(length);
+ io.writeDoubleData(this.x, length);
+ io.writeDoubleData(this.y, length);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_POLYGON);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawPath extends GDCmdItem {
+
+
+ private final int[] n;
+ private final double x[];
+ private final double y[];
+ private final int mode;
+
+
+ public DrawPath(final int devId, final int[] n, final double x[], final double y[],
+ final int mode, final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.n= n;
+ this.x= x;
+ this.y= y;
+ this.mode= mode;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_PATH);
+ io.writeIntArray(this.n, this.n.length);
+ final int length= this.x.length;
+ io.writeInt(length);
+ io.writeDoubleData(this.x, length);
+ io.writeDoubleData(this.y, length);
+ io.writeInt(this.mode);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_PATH);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawCircle extends GDCmdItem {
+
+
+ private final double x;
+ private final double y;
+ private final double r;
+
+
+ public DrawCircle(final int devId, final double x, final double y, final double r,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+ this.x= x;
+ this.y= y;
+ this.r= r;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_CIRCLE);
+ io.writeDouble(this.x);
+ io.writeDouble(this.y);
+ io.writeDouble(this.r);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_CIRCLE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawText extends GDCmdItem {
+
+
+ private final String text;
+ private final double x, y;
+ private final double rDeg;
+ private final double hAdj;
+
+
+ public DrawText(final int devId, final String text,
+ final double x, final double y, final double rDeg, final double hAdj,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+
+ this.text= text;
+ this.x= x;
+ this.y= y;
+ this.rDeg= rDeg;
+ this.hAdj= hAdj;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_TEXT);
+ io.writeString(this.text);
+ io.writeDouble(this.x);
+ io.writeDouble(this.y);
+ io.writeDouble(this.rDeg);
+ io.writeDouble(this.hAdj);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_TEXT);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class DrawRaster extends GDCmdItem {
+
+
+ private final byte[] imgData;
+ private final boolean imgAlpha;
+ private final int imgW, imgH;
+ private final double x, y;
+ private final double w, h;
+ private final double rDeg;
+ private final boolean interpolate;
+
+
+ public DrawRaster(final int devId,
+ final byte[] imgData, final boolean imgAlpha, final int imgW, final int imgH,
+ final double x, final double y, final double w, final double h,
+ final double rDeg, final boolean interpolate,
+ final byte slot) {
+ this.options= 0;
+ this.devId= devId;
+
+ this.imgData= imgData;
+ this.imgAlpha= imgAlpha;
+ this.imgW= imgW;
+ this.imgH= imgH;
+ this.x= x;
+ this.y= y;
+ this.w= w;
+ this.h= h;
+ this.rDeg= rDeg;
+ this.interpolate= interpolate;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(DRAW_RASTER);
+ io.writeInt(this.imgData.length);
+ io.writeByteData(this.imgData, this.imgData.length);
+ io.writeBoolean(this.imgAlpha);
+ io.writeInt(this.imgW);
+ io.writeInt(this.imgH);
+ io.writeDouble(this.x);
+ io.writeDouble(this.y);
+ io.writeDouble(this.w);
+ io.writeDouble(this.h);
+ io.writeDouble(this.rDeg);
+ io.writeBoolean(this.interpolate);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(DRAW_RASTER);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class Capture extends GDCmdItem {
+
+
+ private final int w, h;
+
+
+ public Capture(final int devId,
+ final int w, final int h,
+ final byte slot) {
+ this.options= OV_WAITFORCLIENT;
+ this.devId= devId;
+
+ this.w= w;
+ this.h= h;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.devId);
+ io.writeByte(CAPTURE);
+ io.writeByte(this.requestId);
+ io.writeInt(this.w);
+ io.writeInt(this.h);
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(CAPTURE);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+ public static final class Locator extends GDCmdItem {
+
+
+ public Locator(final int devId,
+ final byte slot) {
+ this.options= OV_WAITFORCLIENT;
+ this.devId= devId;
+
+ this.slot= slot;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt((OV_WAITFORCLIENT | this.devId));
+ io.writeByte(U_LOCATOR);
+ io.writeByte(this.requestId);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer();
+ sb.append("GDCmdItem (options=0x");
+ sb.append(Integer.toHexString(this.options));
+ sb.append(", device=");
+ sb.append(this.devId);
+ sb.append(", commandId=");
+ sb.append(U_LOCATOR);
+ sb.append(")\n<GD-DATA>\n");
+ sb.append("\n</GD-DATA>");
+ return sb.toString();
+ }
+
+ }
+
+
+ protected int devId;
+
+
+ /**
+ * Constructor for automatic deserialization
+ */
+ protected GDCmdItem() {
+ }
+
+
+ @Override
+ public final byte getCmdType() {
+ return T_GRAPH_ITEM;
+ }
+
+ @Override
+ public byte getOp() {
+ return 0;
+ }
+
+ @Override
+ public final boolean isOK() {
+ return ((this.options & OM_STATUS) == RjsStatus.OK);
+ }
+
+ @Override
+ public final RjsStatus getStatus() {
+ return null;
+ }
+
+ public final int getDeviceId() {
+ return this.devId;
+ }
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ public double[] getDoubleData() {
+ throw new UnsupportedOperationException();
+ }
+
+ public byte[] getByteData() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public final String getDataText() {
+ return null;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof GDCmdItem)) {
+ return false;
+ }
+ final GDCmdItem otherItem= (GDCmdItem) other;
+ if (this.options != otherItem.options) {
+ return false;
+ }
+ if (getDeviceId() != otherItem.getDeviceId()) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GraOpCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GraOpCmdItem.java
new file mode 100644
index 0000000..dc64d83
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/GraOpCmdItem.java
@@ -0,0 +1,201 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.server.gr.Coord;
+import org.eclipse.statet.rj.server.gr.GraOp;
+
+
+/**
+ * Command item for main loop graphic operations (="op")
+ */
+public final class GraOpCmdItem extends MainCmdItem implements GraOp {
+
+
+ private static final int OV_WITHDATA= 0x01000000;
+ private static final int OV_WITHSTATUS= 0x08000000;
+
+
+ private final int devId;
+ private final byte op;
+
+ private RJIOExternalizable data;
+
+
+ /**
+ * Constructor for new commands
+ */
+ public GraOpCmdItem(final int devId, final byte op) {
+ this.devId= devId;
+ this.op= op;
+ }
+
+ /**
+ * Constructor for new commands
+ */
+ public GraOpCmdItem(final int devId, final byte op, final RJIOExternalizable data) {
+ this.devId= devId;
+ this.op= op;
+ if (data != null) {
+ this.data= data;
+ this.options |= OV_WITHDATA;
+ }
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public GraOpCmdItem(final RJIO in) throws IOException {
+ this.requestId= in.readInt();
+ this.options= in.readInt();
+ this.devId= in.readInt();
+ this.op= in.readByte();
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ this.data= new RjsStatus(in);
+ }
+ else if ((this.options & OV_WITHDATA) != 0) {
+ switch (this.op) {
+ case OP_CONVERT_DEV2USER:
+ this.data= new Coord(in);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.requestId);
+ out.writeInt(this.options);
+ out.writeInt(this.devId);
+ out.writeByte(this.op);
+ if ((this.options & (OV_WITHSTATUS | OV_WITHDATA)) != 0) {
+ this.data.writeExternal(out);
+ }
+ }
+
+
+ @Override
+ public byte getCmdType() {
+ return T_GRAPHICS_OP_ITEM;
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ assert (status != null);
+ if (status.getSeverity() == RjsStatus.OK) {
+ this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+ this.data= null;
+ }
+ else {
+ this.options= (this.options & OM_CLEARFORANSWER) | (OV_ANSWER | OV_WITHSTATUS);
+ this.data= status;
+ }
+ }
+
+ public void setAnswer(final RJIOExternalizable data) {
+ this.options= (this.options & OM_CLEARFORANSWER) | OV_ANSWER;
+ if (data != null) {
+ this.options |= OV_WITHDATA;
+ }
+ this.data= data;
+ }
+
+
+ public int getDevId() {
+ return this.devId;
+ }
+
+ @Override
+ public byte getOp() {
+ return this.op;
+ }
+
+ @Override
+ public boolean isOK() {
+ return ((this.options & OV_WITHSTATUS) == 0 || this.data == null);
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ if ((this.options & OV_ANSWER) != 0) {
+ return ((this.options & OV_WITHSTATUS) == 0) ? RjsStatus.OK_STATUS : (RjsStatus) this.data;
+ }
+ return null;
+ }
+
+ @Override
+ public String getDataText() {
+ return null;
+ }
+
+ public Object getData() {
+ return this.data;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof GraOpCmdItem)) {
+ return false;
+ }
+ final GraOpCmdItem otherItem= (GraOpCmdItem) other;
+ if (this.devId != otherItem.devId) {
+ return false;
+ }
+ if (this.op != otherItem.op) {
+ return false;
+ }
+ if (this.options != otherItem.options) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(128);
+ sb.append("GDOpCmdItem ");
+ switch (this.op) {
+ case OP_CLOSE:
+ sb.append("CLOSE");
+ break;
+ default:
+ sb.append(this.op);
+ break;
+ }
+ sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+ if ((this.options & OV_WITHSTATUS) != 0) {
+ sb.append("\nwith status: ");
+ sb.append((this.data == null) ? RjsStatus.OK_STATUS : this.data);
+ }
+ else if ((this.options & OV_WITHDATA) != 0) {
+ sb.append("\n<DATA>\n");
+ sb.append(this.data);
+ sb.append("\n</DATA>");
+ }
+ else {
+ sb.append("\n<DATA/>");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdC2SList.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdC2SList.java
new file mode 100644
index 0000000..d649bde
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdC2SList.java
@@ -0,0 +1,220 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Client-to-Server list with {@link MainCmdItem}s.
+ */
+public final class MainCmdC2SList implements RjsComObject, Externalizable {
+
+
+ private final RJIO privateIO;
+
+ private MainCmdItem first;
+
+
+ public MainCmdC2SList(final RJIO io) {
+ this.privateIO= io;
+ }
+
+ /**
+ * Constructor for automatic deserialization
+ */
+ public MainCmdC2SList() {
+ this.privateIO= null;
+ this.first= null;
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ final RJIO io;
+ if (this.privateIO != null) {
+ io= this.privateIO;
+ io.connect(out);
+ }
+ else {
+ io= RJIO.get(out);
+ }
+ final int check= io.writeCheck1();
+
+ MainCmdItem item= this.first;
+ if (item != null) {
+ do {
+ out.writeByte(item.getCmdType());
+ item.writeExternal(io);
+ } while ((item= item.next) != null);
+ }
+ out.writeByte(MainCmdItem.T_NONE);
+
+ io.writeCheck2(check);
+ io.disconnect(out);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ final RJIO io= RJIO.get(in);
+ final int check= io.readCheck1();
+
+ { // first
+ final byte type= in.readByte();
+ switch (type) {
+ case MainCmdItem.T_NONE:
+ this.first= null;
+ io.readCheck2(check);
+ io.disconnect(in);
+ return;
+ case MainCmdItem.T_CONSOLE_READ_ITEM:
+ this.first= new ConsoleReadCmdItem(io);
+ break;
+ case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+ this.first= new ConsoleWriteCmdItem(io);
+ break;
+ case MainCmdItem.T_MESSAGE_ITEM:
+ this.first= new ConsoleMessageCmdItem(io);
+ break;
+ case MainCmdItem.T_EXTENDEDUI_ITEM:
+ this.first= new ExtUICmdItem(io);
+ break;
+ case MainCmdItem.T_GRAPH_ITEM:
+ this.first= new GDCmdItem.Answer(io);
+ break;
+ case MainCmdItem.T_MAIN_CTRL_ITEM:
+ this.first= new MainCtrlCmdItem(io);
+ break;
+ case MainCmdItem.T_DATA_ITEM:
+ this.first= new DataCmdItem(io);
+ break;
+ case MainCmdItem.T_GRAPHICS_OP_ITEM:
+ this.first= new GraOpCmdItem(io);
+ break;
+ case MainCmdItem.T_DBG_ITEM:
+ this.first= new DbgCmdItem(io);
+ break;
+ default:
+ io.disconnect(in);
+ throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+ }
+ }
+
+ MainCmdItem item= this.first;
+ while (true) {
+ final byte type= in.readByte();
+ switch (type) {
+ case MainCmdItem.T_NONE:
+ io.readCheck2(check);
+ io.disconnect(in);
+ return;
+ case MainCmdItem.T_CONSOLE_READ_ITEM:
+ item= item.next= new ConsoleReadCmdItem(io);
+ continue;
+ case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+ item= item.next= new ConsoleWriteCmdItem(io);
+ continue;
+ case MainCmdItem.T_MESSAGE_ITEM:
+ item= item.next= new ConsoleMessageCmdItem(io);
+ continue;
+ case MainCmdItem.T_EXTENDEDUI_ITEM:
+ item= item.next= new ExtUICmdItem(io);
+ continue;
+ case MainCmdItem.T_GRAPH_ITEM:
+ item= item.next= new GDCmdItem.Answer(io);
+ continue;
+ case MainCmdItem.T_MAIN_CTRL_ITEM:
+ this.first= new MainCtrlCmdItem(io);
+ break;
+ case MainCmdItem.T_DATA_ITEM:
+ item= item.next= new DataCmdItem(io);
+ continue;
+ case MainCmdItem.T_GRAPHICS_OP_ITEM:
+ item= item.next= new GraOpCmdItem(io);
+ continue;
+ case MainCmdItem.T_DBG_ITEM:
+ item= item.next= new DbgCmdItem(io);
+ continue;
+ default:
+ io.disconnect(in);
+ throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+ }
+ }
+ }
+
+
+ public void clear() {
+ this.first= null;
+ }
+
+ public void setObjects(final MainCmdItem first) {
+ this.first= first;
+ }
+
+
+ @Override
+ public int getComType() {
+ return RjsComObject.T_MAIN_LIST;
+ }
+
+ public MainCmdItem getItems() {
+ return this.first;
+ }
+
+ public boolean testEquals(final MainCmdC2SList other) {
+ MainCmdItem thisItem= this.first;
+ MainCmdItem otherItem= other.first;
+ while (thisItem != null && otherItem != null) {
+ if (!thisItem.equals(otherItem)) {
+ return false;
+ }
+ thisItem= thisItem.next;
+ otherItem= otherItem.next;
+ }
+ if (thisItem != null || otherItem != null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(100);
+ sb.append("MainCmdC2SList (");
+ sb.append("):");
+ if (this.first == null) {
+ sb.append("\n<ITEM />");
+ }
+ else {
+ MainCmdItem item= this.first;
+ int i= 0;
+ while (item != null) {
+ sb.append("\n<ITEM i=\"");
+ sb.append(i);
+ sb.append("\">\n");
+ sb.append(item.toString());
+ sb.append("\n</ITEM>");
+ item= item.next;
+ i++;
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdItem.java
new file mode 100644
index 0000000..11bd36b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdItem.java
@@ -0,0 +1,138 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public abstract class MainCmdItem implements RJIOExternalizable {
+
+
+ public static final byte T_NONE= 0;
+
+ /**
+ * {@link ConsoleReadCmdItem}
+ */
+ public static final byte T_CONSOLE_READ_ITEM= 0x01;
+
+ /**
+ * {@link ConsoleWriteCmdItem}
+ */
+ public static final byte T_CONSOLE_WRITE_ITEM= 0x02;
+
+
+ /**
+ * {@link ConsoleMessageCmdItem}
+ */
+ public static final byte T_MESSAGE_ITEM= 0x04;
+
+ /**
+ * {@link ExtUICmdItem}
+ */
+ public static final byte T_EXTENDEDUI_ITEM= 0x05;
+
+ /**
+ * {@link GDCmdItem}
+ */
+ public static final byte T_GRAPH_ITEM= 0x07;
+
+ /**
+ * T_id < => initiated by server
+ * T_id > => initiated by client
+ */
+ public static final byte T_S2C_C2S= 9;
+
+ /**
+ * {@link MainCtrlCmdItem}
+ */
+ public static final byte T_MAIN_CTRL_ITEM= 0x10;
+
+ /**
+ * {@link DataCmdItem}
+ */
+ public static final byte T_DATA_ITEM= 0x11;
+
+ /**
+ * {@link GraOpCmdItem}
+ */
+ public static final byte T_GRAPHICS_OP_ITEM= 0x12;
+
+ /**
+ * {@link DbgCmdItem}
+ */
+ public static final byte T_DBG_ITEM= 0x14;
+
+
+ /**
+ * Inside server only
+ */
+ public static final byte T_SRV_ITEM= 0x20;
+
+
+ protected static final int OM_STATUS= 0x00f00000; // 0xf << OS_STATUS
+ protected static final int OS_STATUS= 20;
+
+ protected static final int OM_WITH= 0x0f000000;
+
+ public static final int OV_ANSWER= 0x40000000;
+ protected static final int OM_ANSWER= OV_ANSWER;
+ public static final int OV_WAITFORCLIENT= 0x80000000;
+ protected static final int OM_WAITFORCLIENT= OV_WAITFORCLIENT;
+ protected static final int OC_WAITFORCLIENT= ~(OM_WAITFORCLIENT);
+
+ public static final int OM_CUSTOM= 0x0000ffff;
+
+ protected static final int OM_CLEARFORANSWER= ~(OM_STATUS | OM_WITH);
+
+
+ protected int options;
+
+ public MainCmdItem next;
+
+ public int requestId;
+ public byte slot;
+
+
+ public abstract byte getCmdType();
+
+ public abstract byte getOp();
+
+ public final boolean waitForClient() {
+ return ((this.options & OM_WAITFORCLIENT) != 0);
+ }
+
+ public final boolean isAnswer() {
+ return ((this.options & OM_ANSWER) != 0);
+ }
+
+ public final int getCmdOption() {
+ return ((this.options & OM_CUSTOM));
+ }
+
+ public abstract void setAnswer(RjsStatus status);
+
+ public abstract boolean isOK();
+ public abstract RjsStatus getStatus();
+ public abstract String getDataText();
+
+ @Override
+ public abstract void writeExternal(RJIO io) throws IOException;
+
+ public abstract boolean testEquals(MainCmdItem other);
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdS2CList.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdS2CList.java
new file mode 100644
index 0000000..47980a9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCmdS2CList.java
@@ -0,0 +1,250 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Server-to-Client list with {@link MainCmdItem}s.
+ */
+public final class MainCmdS2CList implements RjsComObject, Externalizable {
+
+
+ static final AutoIdMap<ComHandler> gComHandlers= new AutoIdMap<>();
+
+
+ private int id;
+
+ private boolean isBusy;
+
+ private MainCmdItem first;
+
+
+ public MainCmdS2CList(final MainCmdItem first, final boolean isBusy) {
+ this.isBusy= isBusy;
+ this.first= first;
+ }
+
+ /**
+ * Constructor for automatic deserialization
+ */
+ public MainCmdS2CList() {
+ this.isBusy= false;
+ this.first= null;
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeShort(this.id);
+
+ out.writeBoolean(this.isBusy);
+
+ final RJIO io= RJIO.get(out);
+ final int check= io.writeCheck1();
+
+ MainCmdItem item= this.first;
+ if (item != null) {
+ do {
+ out.writeByte(item.getCmdType());
+ item.writeExternal(io);
+ } while ((item= item.next) != null);
+ }
+ out.writeByte(MainCmdItem.T_NONE);
+
+ io.writeCheck2(check);
+ io.disconnect(out);
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ this.id= in.readUnsignedShort();
+ if (this.id != 0) {
+ gComHandlers.get(this.id).processMainCmd(in);
+ return;
+ }
+
+ this.isBusy= in.readBoolean();
+
+ final RJIO io= RJIO.get(in);
+ final int check= io.readCheck1();
+
+ { // first
+ final byte type= in.readByte();
+ switch (type) {
+ case MainCmdItem.T_NONE:
+ this.first= null;
+ io.readCheck2(check);
+ io.disconnect(in);
+ return;
+ case MainCmdItem.T_CONSOLE_READ_ITEM:
+ this.first= new ConsoleReadCmdItem(io);
+ break;
+ case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+ this.first= new ConsoleWriteCmdItem(io);
+ break;
+ case MainCmdItem.T_MESSAGE_ITEM:
+ this.first= new ConsoleMessageCmdItem(io);
+ break;
+ case MainCmdItem.T_EXTENDEDUI_ITEM:
+ this.first= new ExtUICmdItem(io);
+ break;
+ case MainCmdItem.T_MAIN_CTRL_ITEM:
+ this.first= new MainCtrlCmdItem(io);
+ break;
+ case MainCmdItem.T_DATA_ITEM:
+ this.first= new DataCmdItem(io);
+ break;
+ case MainCmdItem.T_GRAPHICS_OP_ITEM:
+ this.first= new GraOpCmdItem(io);
+ break;
+ case MainCmdItem.T_DBG_ITEM:
+ this.first= new DbgCmdItem(io);
+ break;
+ default:
+ throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+ }
+ }
+
+ MainCmdItem item= this.first;
+ while (true) {
+ final byte type= in.readByte();
+ switch (type) {
+ case MainCmdItem.T_NONE:
+ io.readCheck2(check);
+ io.disconnect(in);
+ return;
+ case MainCmdItem.T_CONSOLE_READ_ITEM:
+ item= item.next= new ConsoleReadCmdItem(io);
+ continue;
+ case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+ item= item.next= new ConsoleWriteCmdItem(io);
+ continue;
+ case MainCmdItem.T_MESSAGE_ITEM:
+ item= item.next= new ConsoleMessageCmdItem(io);
+ continue;
+ case MainCmdItem.T_EXTENDEDUI_ITEM:
+ item= item.next= new ExtUICmdItem(io);
+ continue;
+ case MainCmdItem.T_MAIN_CTRL_ITEM:
+ this.first= new MainCtrlCmdItem(io);
+ break;
+ case MainCmdItem.T_DATA_ITEM:
+ item= item.next= new DataCmdItem(io);
+ continue;
+ case MainCmdItem.T_GRAPHICS_OP_ITEM:
+ item= item.next= new GraOpCmdItem(io);
+ continue;
+ case MainCmdItem.T_DBG_ITEM:
+ item= item.next= new DbgCmdItem(io);
+ continue;
+ default:
+ io.disconnect(in);
+ throw new ClassNotFoundException("Unknown cmdtype id: "+type);
+ }
+ }
+ }
+
+
+ public void clear() {
+ MainCmdItem item= this.first;
+ while (item != null) {
+ final MainCmdItem tmp= item;
+ item= item.next;
+ tmp.next= null;
+ }
+ this.first= null;
+ }
+
+ public boolean isEmpty() {
+ return (this.first == null);
+ }
+
+ public void setId(final int id) {
+ this.id= (short) id;
+ }
+
+ public void setBusy(final boolean isBusy) {
+ this.isBusy= isBusy;
+ }
+
+ public void setObjects(final MainCmdItem first) {
+ this.first= first;
+ }
+
+
+ @Override
+ public int getComType() {
+ return RjsComObject.T_MAIN_LIST;
+ }
+
+ public MainCmdItem getItems() {
+ return this.first;
+ }
+
+ public boolean isBusy() {
+ return this.isBusy;
+ }
+
+
+ public boolean testEquals(final MainCmdS2CList other) {
+ if (this.isBusy != other.isBusy()) {
+ return false;
+ }
+
+ MainCmdItem thisItem= this.first;
+ MainCmdItem otherItem= other.first;
+ while (thisItem != null && otherItem != null) {
+ if (!thisItem.equals(otherItem)) {
+ return false;
+ }
+ thisItem= thisItem.next;
+ otherItem= otherItem.next;
+ }
+ if (thisItem != null || otherItem != null) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(128);
+ sb.append("MainCmdS2CList (isBusy=");
+ sb.append(this.isBusy);
+ sb.append(')');
+ if (this.first != null) {
+ sb.append(':');
+ }
+ MainCmdItem item= this.first;
+ int i= 0;
+ while (item != null) {
+ sb.append("\n<ITEM i=\"");
+ sb.append(i);
+ sb.append("\">\n");
+ sb.append(item.toString());
+ sb.append("\n</ITEM>");
+ item= item.next;
+ i++;
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCtrlCmdItem.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCtrlCmdItem.java
new file mode 100644
index 0000000..99a9c13
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/MainCtrlCmdItem.java
@@ -0,0 +1,115 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+/**
+ * Command for main loop console prompt/input.
+ */
+public final class MainCtrlCmdItem extends MainCmdItem {
+
+
+ public static final byte OP_FINISH_TASK= 02;
+
+
+ private final byte op;
+
+
+ public MainCtrlCmdItem(final byte op, final int options) {
+ this.op= op;
+ this.options= (options | (OM_WAITFORCLIENT));
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public MainCtrlCmdItem(final RJIO in) throws IOException {
+ this.requestId= in.readInt();
+ this.options= in.readInt();
+ this.op= in.readByte();
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.requestId);
+ out.writeInt(this.options);
+ out.writeByte(this.op);
+ }
+
+
+ @Override
+ public byte getCmdType() {
+ return T_MAIN_CTRL_ITEM;
+ }
+
+ @Override
+ public byte getOp() {
+ return this.op;
+ }
+
+
+ @Override
+ public void setAnswer(final RjsStatus status) {
+ this.options= (this.options & OM_CLEARFORANSWER) | (status.getSeverity() << OS_STATUS);
+ }
+
+
+ @Override
+ public boolean isOK() {
+ return ((this.options & OM_STATUS) == RjsStatus.OK);
+ }
+
+ @Override
+ public RjsStatus getStatus() {
+ return null;
+ }
+
+ @Override
+ public String getDataText() {
+ return null;
+ }
+
+
+ @Override
+ public boolean testEquals(final MainCmdItem other) {
+ if (!(other instanceof MainCtrlCmdItem)) {
+ return false;
+ }
+ final MainCtrlCmdItem otherItem= (MainCtrlCmdItem) other;
+ return (getOp() == otherItem.getOp()
+ && this.options == otherItem.options );
+ }
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(128);
+ sb.append("MainCtrlCmdItem ");
+ switch (this.op) {
+ case OP_FINISH_TASK:
+ sb.append("FINISH_TASK");
+ break;
+ default:
+ sb.append(this.op);
+ break;
+ }
+ sb.append("\n\t").append("options= 0x").append(Integer.toHexString(this.options));
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Operation.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Operation.java
new file mode 100644
index 0000000..7ddd98c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Operation.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+/**
+ * Operation
+ */
+public interface Operation {
+
+
+ interface SyncOp extends Operation {
+
+ }
+
+ interface AsyncOp extends Operation {
+
+ }
+
+
+ byte getOp();
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/REngine.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/REngine.java
new file mode 100644
index 0000000..4fafd40
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/REngine.java
@@ -0,0 +1,78 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Map;
+
+
+/**
+ * Interface to the R console / REPL
+ */
+public interface REngine extends Remote {
+
+ /**
+ * Returns the public server reference
+ * Usually you got this server by the public server reference
+ *
+ * @return
+ * @throws RemoteException
+ */
+ Server getPublic() throws RemoteException;
+
+ /**
+ * Returns a collection of platform data.
+ * Current default items:
+ * <ul>
+ * <li><code>os.type</code> - {@link String}</li>
+ * <li><code>file.sep</code> - {@link String}</li>
+ * <li><code>path.sep</code> - {@link String}</li>
+ * <li><code>version.string</code> - {@link String}</li>
+ * </ul>
+ *
+ * @return the map with all available data
+ * @throws RemoteException
+ */
+ Map<String, Object> getPlatformData() throws RemoteException;
+
+ /**
+ * Sets RJ server properties
+ *
+ * @param properties map with properties to update
+ * @throws RemoteException
+ */
+ void setProperties(Map<String, ? extends Object> properties) throws RemoteException;
+
+ /**
+ * Disconnects the client from the server
+ * The client can reconnect using {@link #connect(long)}.
+ *
+ * @throws RemoteException
+ */
+ void disconnect() throws RemoteException;
+
+ RjsComObject runMainLoop(RjsComObject com) throws RemoteException;
+ RjsComObject runAsync(RjsComObject com) throws RemoteException;
+
+ /**
+ * Tests if the connection to R is closed
+ *
+ * @return <code>true</code> if engine is still valid, otherwise <code>false</code>
+ * @throws RemoteException
+ */
+ boolean isClosed() throws RemoteException;
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RJ.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RJ.java
new file mode 100644
index 0000000..4519631
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RJ.java
@@ -0,0 +1,120 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.statet.rj.server.gr.RjsGraphicManager;
+
+
+/**
+ * Interface from R to Java side of the RJ server
+ */
+public class RJ {
+
+
+ private static RJ instance;
+
+ protected byte currentSlot;
+
+ private final Object clientPropertiesLock= new Object();
+ private Map<String, Object>[] clientPropertiesMaps= new Map[2];
+
+
+ public final static RJ getInstance() {
+ return instance;
+ }
+
+
+ protected RJ() {
+ if (instance != null) {
+ throw new IllegalStateException();
+ }
+ instance= this;
+ }
+
+
+ public void onRExit() {
+ instance= null;
+ }
+
+ public byte getCurrentSlot() {
+ return this.currentSlot;
+ }
+
+ public RjsGraphicManager getGraphicManager() {
+ return null;
+ }
+
+ protected void setClientProperty(final byte slot, final String key, final Object value) {
+ Map<String, Object> map;
+ synchronized (this.clientPropertiesLock) {
+ if (slot >= this.clientPropertiesMaps.length) {
+ final Map<String, Object>[] newMaps= new Map[this.clientPropertiesMaps.length];
+ System.arraycopy(this.clientPropertiesMaps, 0, newMaps, 0, slot+1);
+ this.clientPropertiesMaps= newMaps;
+ }
+ map= this.clientPropertiesMaps[slot];
+ if (map == null) {
+ this.clientPropertiesMaps[slot]= new HashMap<>();
+ }
+ }
+ map.put(key, value);
+ }
+
+ protected void setClientProperties(final byte slot, final Map<String, ? extends Object> properties) {
+ Map<String, Object> map;
+ synchronized (this.clientPropertiesLock) {
+ if (slot >= this.clientPropertiesMaps.length) {
+ final Map<String, Object>[] newMaps= new Map[this.clientPropertiesMaps.length];
+ System.arraycopy(this.clientPropertiesMaps, 0, newMaps, 0, slot+1);
+ this.clientPropertiesMaps= newMaps;
+ }
+ map= this.clientPropertiesMaps[slot];
+ if (map == null) {
+ this.clientPropertiesMaps[slot]= map= new HashMap<>();
+ }
+ }
+ for (final Entry<String, ? extends Object> entry : properties.entrySet()) {
+ if (entry.getValue() != null) {
+ map.put(entry.getKey(), entry.getValue());
+ }
+ else {
+ map.remove(entry.getKey());
+ }
+ }
+ }
+
+ public Object getClientProperty(final byte slot, final String key) {
+ final Map<String, Object>[] clients= this.clientPropertiesMaps;
+ if (slot >= clients.length) {
+ return null;
+ }
+ final Map<String, Object> map= clients[slot];
+ if (map == null) {
+ return null;
+ }
+ synchronized (map) {
+ return map.get(key);
+ }
+ }
+
+ public MainCmdItem sendMainCmd(final MainCmdItem cmd) {
+ throw new UnsupportedOperationException();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComConfig.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComConfig.java
new file mode 100644
index 0000000..036ea5b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComConfig.java
@@ -0,0 +1,237 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.rmi.Remote;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMISocketFactory;
+import java.security.AccessControlException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.data.RObjectFactory;
+
+
+public class RjsComConfig {
+
+
+ public static final String RJ_COM_S2C_ID_PROPERTY_ID= "rj.com.s2c.id";
+
+ public static final String RJ_DATA_STRUCTS_LISTS_MAX_LENGTH_PROPERTY_ID= "rj.data.structs.lists.max_length";
+ public static final String RJ_DATA_STRUCTS_ENVS_MAX_LENGTH_PROPERTY_ID= "rj.data.structs.envs.max_length";
+
+
+ private static final Map<String, Object> PROPERTIES= new ConcurrentHashMap<>();
+
+
+ public static interface PathResolver {
+ File resolve(Remote client, String path) throws RjException;
+ }
+
+
+ public static void setServerPathResolver(final RjsComConfig.PathResolver resolver) {
+ BinExchange.gSPathResolver= resolver;
+ }
+
+
+ public static int registerClientComHandler(final ComHandler handler) {
+ if (handler == null) {
+ throw new NullPointerException();
+ }
+ final int id= MainCmdS2CList.gComHandlers.put(handler);
+ if (id < 0xffff) {
+ return id;
+ }
+ MainCmdS2CList.gComHandlers.remove(id);
+ throw new UnsupportedOperationException("Too much open clients");
+ }
+
+ public static void unregisterClientComHandler(final int id) {
+ MainCmdS2CList.gComHandlers.remove(id);
+ }
+
+
+ /**
+ * Registers an additional RObject factory
+ *
+ * Factory registration is valid for the current VM.
+ */
+ public static final void registerRObjectFactory(final String id, final RObjectFactory factory) {
+ if (id == null || factory == null) {
+ throw new NullPointerException();
+ }
+ if (id.equals(DataCmdItem.DEFAULT_FACTORY_ID)) {
+ throw new IllegalArgumentException();
+ }
+ DataCmdItem.gFactories.put(id, factory);
+ }
+
+ /**
+ * Sets the default RObject factory
+ *
+ * Factory registration is valid for the current VM.
+ */
+ public static final void setDefaultRObjectFactory(final RObjectFactory factory) {
+ if (factory == null) {
+ throw new NullPointerException();
+ }
+ DataCmdItem.gDefaultFactory= factory;
+ DataCmdItem.gFactories.put(DataCmdItem.DEFAULT_FACTORY_ID, factory);
+ }
+
+ public static final void setProperty(final String key, final Object value) {
+ PROPERTIES.put(key, value);
+ }
+
+ public static final Object getProperty(final String key) {
+ return PROPERTIES.get(key);
+ }
+
+
+ private static final ThreadLocal<RMIClientSocketFactory> gRMIClientSocketFactoriesInit= new ThreadLocal<>();
+ private static final ConcurrentHashMap<String, RMIClientSocketFactory> gRMIClientSocketFactories= new ConcurrentHashMap<>();
+
+
+ private static RMIClientSocketFactory getSystemRMIClientSocketFactory() {
+ RMIClientSocketFactory factory= RMISocketFactory.getSocketFactory();
+ if (factory == null) {
+ factory= RMISocketFactory.getDefaultSocketFactory();
+ }
+ return factory;
+ }
+
+ private static final class RjRMIClientSocketFactory implements RMIClientSocketFactory, Externalizable {
+
+
+ private static final long serialVersionUID= -2470426070934072117L;
+
+ private static String getLocalHostName() {
+ try {
+ return InetAddress.getLocalHost().getCanonicalHostName();
+ }
+ catch (final UnknownHostException e) {}
+ catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ }
+ return "unknown";
+ }
+
+
+ private String id;
+ private RMIClientSocketFactory resolvedFactory;
+
+
+ public RjRMIClientSocketFactory() {
+ }
+
+ public RjRMIClientSocketFactory(final String init) {
+ final StringBuilder sb= new StringBuilder(init);
+ sb.append(getLocalHostName());
+ sb.append('/').append(System.nanoTime()).append('/').append(Math.random());
+ this.id= sb.toString();
+ }
+
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeUTF(this.id);
+ }
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ this.id= in.readUTF();
+ }
+
+
+ @Override
+ public Socket createSocket(final String host, final int port) throws IOException {
+ RMIClientSocketFactory factory= null;
+ factory= gRMIClientSocketFactoriesInit.get();
+ if (factory != null) {
+ this.resolvedFactory= factory;
+ gRMIClientSocketFactories.put(this.id, factory);
+ }
+ else {
+ factory= this.resolvedFactory;
+ if (factory == null) {
+ factory= gRMIClientSocketFactories.get(this.id);
+ if (factory != null) {
+ this.resolvedFactory= factory;
+ }
+ else {
+ factory= getSystemRMIClientSocketFactory();
+ }
+ }
+ }
+ return factory.createSocket(host, port);
+ }
+
+
+ @Override
+ public int hashCode() {
+ return this.id.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (this == obj
+ || (obj instanceof RjRMIClientSocketFactory
+ && this.id.equals(((RjRMIClientSocketFactory) obj).id) ));
+ }
+
+ }
+
+ private final static boolean RMISERVER_CLIENTSOCKET_FACTORY_ENABLED;
+
+ private static RMIClientSocketFactory RMISERVER_CLIENTSOCKET_FACTORY;
+
+ static {
+ { boolean enabled= true;
+ try {
+ if ("true".equalsIgnoreCase(System.getProperty("org.eclipse.statet.rj.rmi.disableSocketFactory"))) {
+ enabled= false;
+ }
+ }
+ catch (final AccessControlException e) { // in RMI registry
+ }
+ RMISERVER_CLIENTSOCKET_FACTORY_ENABLED= enabled;
+ }
+ }
+
+ public static synchronized final RMIClientSocketFactory getRMIServerClientSocketFactory() {
+ if (RMISERVER_CLIENTSOCKET_FACTORY_ENABLED && RMISERVER_CLIENTSOCKET_FACTORY == null) {
+ RMISERVER_CLIENTSOCKET_FACTORY= new RjRMIClientSocketFactory("S/");
+ }
+ return RMISERVER_CLIENTSOCKET_FACTORY;
+ }
+
+ public static final void setRMIClientSocketFactory(RMIClientSocketFactory factory) {
+ if (factory == null) {
+ factory= getSystemRMIClientSocketFactory();
+ }
+ gRMIClientSocketFactoriesInit.set(factory);
+ }
+
+ public static final void clearRMIClientSocketFactory() {
+ gRMIClientSocketFactoriesInit.set(null);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComObject.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComObject.java
new file mode 100644
index 0000000..1c1d891
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsComObject.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+/**
+ * Interface for all communication exchange objects.
+ */
+public interface RjsComObject {
+
+ /**
+ * {@link RjsStatus}
+ */
+ public static final int T_STATUS= 1;
+
+ /**
+ * {@link RjsPing}
+ */
+ public static final int T_PING= 2;
+
+ /**
+ * {@link MainCmdS2CList}
+ */
+ public static final int T_MAIN_LIST= 3;
+
+ /**
+ * {@link BinExchange}
+ */
+ public static final int T_FILE_EXCHANGE= 4;
+
+ /**
+ * {@link CtrlCmdItem}
+ */
+ public static final int T_CTRL= 5;
+
+ /**
+ * {@link DbgCmdItem}
+ */
+ public static final int T_DBG= 6;
+
+
+ // Same value as in IStatus
+ public static final int V_OK= RjsStatus.OK;
+ public static final int V_INFO= RjsStatus.INFO;
+ public static final int V_WARNING= RjsStatus.WARNING;
+ public static final int V_ERROR= RjsStatus.ERROR;
+ public static final int V_CANCEL= RjsStatus.CANCEL;
+
+ public static final int V_FALSE= 0x0;
+ public static final int V_TRUE= 0x1;
+
+
+ public int getComType();
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsException.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsException.java
new file mode 100644
index 0000000..48a7dcc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsException.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+
+/**
+ * Exception indicating that RJ operation failed
+ */
+public class RjsException extends Exception {
+
+
+ private static final long serialVersionUID= 4433450430400305890L;
+
+
+ private final int code;
+
+
+ public RjsException(final int code, final String message) {
+ super(message);
+ this.code= code;
+ }
+
+ public RjsException(final int code, final String message, final Throwable cause) {
+ super(message, cause);
+ this.code= code;
+ }
+
+
+ public RjsStatus getStatus() {
+ return new RjsStatus(RjsStatus.ERROR, this.code, getMessage());
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsPing.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsPing.java
new file mode 100644
index 0000000..0828321
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsPing.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+
+/**
+ * Command for simple ping. Should be answered directly with a {@link RjsStatus}.
+ */
+public final class RjsPing implements RjsComObject, Externalizable {
+
+
+ public static final RjsPing INSTANCE= new RjsPing();
+
+
+ public RjsPing() {
+ }
+
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ }
+
+
+ @Override
+ public int getComType() {
+ return RjsComObject.T_PING;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return 1;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (obj instanceof RjsPing);
+ }
+
+
+ @Override
+ public String toString() {
+ return "RjsPing";
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsStatus.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsStatus.java
new file mode 100644
index 0000000..d479db2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/RjsStatus.java
@@ -0,0 +1,207 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public final class RjsStatus implements RjsComObject, Externalizable, RJIOExternalizable {
+
+
+ public static final int OK= 0x0;
+ public static final int INFO= 0x1;
+ public static final int WARNING= 0x2;
+ public static final int ERROR= 0x4;
+ public static final int CANCEL= 0x8;
+
+
+ public static final RjsStatus OK_STATUS= new RjsStatus(OK, 0);
+
+ public static final RjsStatus CANCEL_STATUS= new RjsStatus(CANCEL, 0);
+
+
+ private int severity;
+ private int code;
+ private String text;
+
+
+ /**
+ * Constructor to create a status object without a message
+ */
+ public RjsStatus(final int severity, final int code) {
+ this.severity= severity;
+ this.code= code;
+ this.text= null;
+ }
+
+ /**
+ * Constructor to create a status object with a message
+ */
+ public RjsStatus(final int severity, final int code, final String s) {
+ this.severity= severity;
+ this.code= code;
+ this.text= (s != null && s.length() > 0) ? s : null;
+ }
+
+ /**
+ * Constructor for automatic deserialization
+ */
+ public RjsStatus() {
+ }
+
+ /**
+ * Constructor for deserialization
+ */
+ public RjsStatus(final ObjectInput in) throws IOException {
+ readExternal(in);
+ }
+
+ public RjsStatus(final RJIO io) throws IOException {
+ if (io.readBoolean()) {
+ this.severity= io.readByte();
+ this.code= io.readInt();
+ this.text= io.readString();
+ }
+ else {
+ this.severity= io.readByte();
+ this.code= io.readInt();
+ this.text= null;
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ if (this.text != null) {
+ io.writeBoolean(true);
+ io.writeByte(this.severity);
+ io.writeInt(this.code);
+ io.writeString(this.text);
+ }
+ else {
+ io.writeBoolean(false);
+ io.writeByte(this.severity);
+ io.writeInt(this.code);
+ }
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException {
+ if (in.readBoolean()) {
+ this.severity= in.readByte();
+ this.code= in.readInt();
+ this.text= in.readUTF();
+ }
+ else {
+ this.severity= in.readByte();
+ this.code= in.readInt();
+ this.text= null;
+ }
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ if (this.text != null) {
+ out.writeBoolean(true);
+ out.writeByte(this.severity);
+ out.writeInt(this.code);
+ out.writeUTF(this.text);
+ }
+ else {
+ out.writeBoolean(false);
+ out.writeByte(this.severity);
+ out.writeInt(this.code);
+ }
+ }
+
+
+ @Override
+ public int getComType() {
+ return RjsComObject.T_STATUS;
+ }
+
+ public int getSeverity() {
+ return this.severity;
+ }
+
+ public int getCode() {
+ return this.code;
+ }
+
+ public String getMessage() {
+ return (this.text != null) ? this.text : "";
+ }
+
+
+ @Override
+ public int hashCode() {
+ return this.severity+this.code;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof RjsStatus)) {
+ return false;
+ }
+ final RjsStatus other= (RjsStatus) obj;
+ return (this.code == other.getCode() && this.severity == other.getSeverity()
+ && ((this.text != null) ? this.text.equals(other.text) : (null == other.text)) );
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuffer sb= new StringBuffer(100);
+ sb.append("RjsStatus (severity=");
+ switch (this.severity) {
+ case OK:
+ sb.append("OK");
+ break;
+ case INFO:
+ sb.append("INFO");
+ break;
+ case WARNING:
+ sb.append("WARNING");
+ break;
+ case ERROR:
+ sb.append("ERROR");
+ break;
+ case CANCEL:
+ sb.append("CANCEL");
+ break;
+ default:
+ sb.append(this.severity);
+ break;
+ }
+ sb.append(", code=0x");
+ sb.append(Integer.toHexString(this.code));
+ sb.append(")");
+ if (this.text != null) {
+ sb.append("\n<TEXT>\n");
+ sb.append(this.text);
+ sb.append("\n</TEXT>");
+ }
+ else {
+ sb.append("\n<TEXT />");
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Server.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Server.java
new file mode 100644
index 0000000..af50226
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/Server.java
@@ -0,0 +1,120 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import javax.security.auth.login.LoginException;
+
+
+/**
+ * Interface of the R server visible for the remote clients.
+ *
+ */
+public interface Server extends Remote {
+
+ /**
+ * Status code indicating, that the R engine is not yet started.
+ */
+ public static final int S_NOT_STARTED= 0x00011;
+
+ /**
+ * Status code indicating, that the R engine is started and a/the client is connected.
+ */
+ public static final int S_CONNECTED= 0x00014;
+
+ /**
+ * Status code indicating, that the R engine is started and the client is connected but
+ * not active during the last minutes.
+ */
+ public static final int S_CONNECTED_STALE= 0x00016;
+
+ /**
+ * Status code indicating, that the R engine is started and the client was disconnected.
+ */
+ public static final int S_DISCONNECTED= 0x00018;
+
+ /**
+ * Status code indicating, that R engine is started and the client-server connection was lost.
+ */
+ public static final int S_LOST= 0x00019;
+
+ /**
+ * Status code indicating, that the server was stopped.
+ */
+ public static final int S_STOPPED= 0x0001a;
+
+ public static final String C_CONSOLE_START= "console.start";
+
+ public static final String C_CONSOLE_CONNECT= "console.connect";
+
+ public static final String C_RSERVI_NODECONTROL= "rservi.nodecontrol";
+
+
+ /**
+ * Triple of API version of the this server
+ *
+ * @return the version number
+ * @throws RemoteException
+ */
+ int[] getVersion() throws RemoteException;
+
+ /**
+ * The current server information
+ *
+ * The information represents the state this method is call
+ * and is not updated. To check for updates the method must be
+ * called again.
+ *
+ * @return a server information object
+ * @throws RemoteException
+ */
+ ServerInfo getInfo() throws RemoteException;
+
+ /**
+ * Current state of this server. One of the constants with S_ prefix.
+ *
+ * @return current state
+ * @throws RemoteException
+ */
+ int getState() throws RemoteException;
+
+
+ /**
+ * Creates and returns the ServerLogin with all information necessary
+ * to login ({@link #execute(String, Map, ServerLogin)})
+ * to run the specified command
+ *
+ * @param the execute command constant the login will be for
+ * @return the server login for the command
+ * @throws RemoteException
+ */
+ ServerLogin createLogin(String command) throws RemoteException;
+
+
+ /**
+ * Universal method to executes a server command
+ *
+ * @param command a command, default are available as constants with C_ prefix.
+ * @param login the login creditals a answer of {@link #createConsoleLogin()}
+ * @return the return value of the command, see command description
+ * @throws LoginException if login failed
+ * @throws RemoteException
+ */
+ Object execute(String command, Map<String, ? extends Object> args, ServerLogin login) throws LoginException, RemoteException;
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerInfo.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerInfo.java
new file mode 100644
index 0000000..b12c9f4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerInfo.java
@@ -0,0 +1,75 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Serializable;
+
+
+public class ServerInfo implements Serializable {
+
+
+ private static final long serialVersionUID= -5411479269748201535L;
+
+ public static final String USER_OWNER= "owner";
+ public static final String USER_CONSOLE= "console";
+ public static final String USER_RSERVI= "rservi";
+
+
+ private final String name;
+ private final String[] userTypes;
+ private final String[] userNames;
+ private final String directory;
+ private final long timestamp;
+ private final int state;
+
+
+ public ServerInfo(final String name, final String directory, final long timestamp,
+ final String[] userTypes, final String[] userNames,
+ final int state) {
+ this.name= name;
+ this.userTypes= userTypes;
+ this.userNames= userNames;
+ this.directory= directory;
+ this.timestamp= timestamp;
+ this.state= state;
+ }
+
+
+ public String getName() {
+ return this.name;
+ }
+
+ public String getUsername(final String type) {
+ for (int i= 0; i < this.userTypes.length; i++) {
+ if (this.userTypes[i].equals(type)) {
+ return this.userNames[i];
+ }
+ }
+ return null;
+ }
+
+ public String getDirectory() {
+ return this.directory;
+ }
+
+ public long getTimestamp() {
+ return this.timestamp;
+ }
+
+ public int getState() {
+ return this.state;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerLogin.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerLogin.java
new file mode 100644
index 0000000..7b95942
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/ServerLogin.java
@@ -0,0 +1,184 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server;
+
+import java.io.Serializable;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.security.Key;
+import java.util.Arrays;
+
+import javax.crypto.Cipher;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.PasswordCallback;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+public final class ServerLogin implements Serializable {
+
+
+ private static final long serialVersionUID= -596748668244272719L;
+
+
+ private long id;
+
+ private Key pubkey;
+
+ private Callback[] callbacks;
+
+
+ public ServerLogin() {
+ }
+
+ public ServerLogin(final long id, final Key pubkey, final Callback[] callbacks) {
+ this.id= id;
+ this.pubkey= pubkey;
+ this.callbacks= callbacks;
+ }
+
+
+ public long getId() {
+ return this.id;
+ }
+
+ /**
+ * The callback items which should be handled by the client.
+ *
+ * @return an array with all callback objects
+ * @see CallbackHandler
+ */
+ public Callback[] getCallbacks() {
+ return this.callbacks;
+ }
+
+ /**
+ * Must be called by the client to create login data for authentification
+ * when connecting to server via {@link Server#start(ServerLogin, String[])}
+ * or {@link Server#connect(ServerLogin)}.
+ *
+ * @return the login data prepared to send to the server
+ * @throws RjException when creating login data failed
+ */
+ public ServerLogin createAnswer() throws RjException {
+ try {
+ Callback[] copy;
+ if (this.callbacks != null) {
+ copy= new Callback[this.callbacks.length];
+ System.arraycopy(this.callbacks, 0, copy, 0, this.callbacks.length);
+ if (this.pubkey != null) {
+ process(copy, Cipher.ENCRYPT_MODE, this.pubkey);
+ }
+ }
+ else {
+ copy= null;
+ }
+ return new ServerLogin(this.id, null, copy);
+ }
+ catch (final Exception e) {
+ throw new RjException("An error occurred when creating login data.", e);
+ }
+ }
+
+ /**
+ * Is called by server to decrypt data. By default it is called in
+ * {@link ServerAuthMethod#performLogin(ServerLogin)}.
+ *
+ * @param privateKey the key to decrypt the data
+ * @throws RjException when processing login data failed
+ */
+ public void readAnswer(final Key privateKey) throws RjException {
+ try {
+ if (privateKey != null) {
+ process(this.callbacks, Cipher.DECRYPT_MODE, privateKey);
+ }
+ }
+ catch (final Exception e) {
+ throw new RjException("An error occurred when processing login data.", e);
+ }
+ }
+
+ private void process(final Callback[] callbacks, final int mode, final Key key) throws Exception {
+ final Cipher with= Cipher.getInstance("RSA");
+ with.init(mode, key);
+ final Charset charset= Charset.forName("UTF-8");
+
+ for (int i= 0; i < callbacks.length; i++) {
+ if (callbacks[i] instanceof PasswordCallback) {
+ final PasswordCallback c= (PasswordCallback) callbacks[i];
+ final char[] orgPassword= c.getPassword();
+ if (orgPassword != null) {
+ final byte[] orgBytes;
+ if (mode == Cipher.ENCRYPT_MODE) {
+ orgBytes= charset.encode(CharBuffer.wrap(orgPassword)).array();
+ }
+ else {
+ orgBytes= new byte[orgPassword.length];
+ for (int j= 0; j < orgBytes.length; j++) {
+ orgBytes[j]= (byte) orgPassword[j];
+ }
+ }
+ final byte[] encBytes= with.doFinal(orgBytes);
+ final char[] encPassword;
+ if (mode == Cipher.ENCRYPT_MODE) {
+ encPassword= new char[encBytes.length];
+ for (int j= 0; j < encPassword.length; j++) {
+ encPassword[j]= (char) encBytes[j];
+ }
+ }
+ else {
+ encPassword= charset.decode(ByteBuffer.wrap(encBytes)).array();
+ }
+
+ if (mode == Cipher.ENCRYPT_MODE) {
+ final PasswordCallback copy= new PasswordCallback(c.getPrompt(), c.isEchoOn());
+ copy.setPassword(encPassword);
+ callbacks[i]= copy;
+ }
+ else {
+ c.clearPassword();
+ c.setPassword(encPassword);
+ }
+
+ Arrays.fill(orgBytes, (byte) 0);
+ Arrays.fill(orgPassword, (char) 0);
+ Arrays.fill(encBytes, (byte) 0);
+ Arrays.fill(encPassword, (char) 0);
+ }
+ continue;
+ }
+ }
+ }
+
+ /**
+ * Clear data, especially the password.
+ */
+ public void clearData() {
+ this.pubkey= null;
+ if (this.callbacks != null) {
+ for (int i= 0; i < this.callbacks.length; i++) {
+ if (this.callbacks[i] instanceof PasswordCallback) {
+ ((PasswordCallback) this.callbacks[i]).clearPassword();
+ }
+ this.callbacks[i]= null;
+ }
+ this.callbacks= null;
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CallStack.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CallStack.java
new file mode 100644
index 0000000..4c71804
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CallStack.java
@@ -0,0 +1,146 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class CallStack implements RJIOExternalizable {
+
+
+ public static final int FLAG_TOPFRAME= 0x00001000;
+
+ public static final int FLAG_NOSTEPPING= 0x00000100;
+
+ public static final int FLAG_SOURCE= 0x00000010;
+ public static final int FLAG_COMMAND= 0x00000020;
+
+
+ private final List<? extends Frame> frames;
+
+
+ public CallStack(final List<? extends Frame> list, final boolean setDefaultFlags) {
+ this.frames= list;
+ if (setDefaultFlags) {
+ setDefaultFlags();
+ }
+ }
+
+ public CallStack(final RJIO io) throws IOException {
+ final int l= io.readInt();
+ final ArrayList<Frame> list= new ArrayList<>(l);
+ for (int i= 0; i < l; i++) {
+ final Frame frame= new Frame(i, io.readString());
+ frame.handle= io.readLong();
+ frame.fileName= io.readString();
+ frame.fileTimestamp= io.readLong();
+ frame.exprSrcref= io.readIntArray();
+ frame.flags= io.readInt();
+ list.add(frame);
+ }
+ this.frames= list;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ final int l= this.frames.size();
+ io.writeInt(l);
+ for (int i= 0; i < l; i++) {
+ final Frame frame= this.frames.get(i);
+ io.writeString(frame.getCall());
+ io.writeLong(frame.handle);
+ io.writeString(frame.fileName);
+ io.writeLong(frame.fileTimestamp);
+ io.writeIntArray(frame.exprSrcref, (frame.exprSrcref != null) ? 6 : -1);
+ io.writeInt(frame.flags);
+ }
+ }
+
+ protected void setDefaultFlags() {
+ final int n= this.frames.size();
+ for (int i= 0; i < n; i++) {
+ final Frame frame0= this.frames.get(i);
+ if (frame0.getCall() != null) {
+ if (frame0.getCall().startsWith("source(")) { //$NON-NLS-1$
+ Frame frame1;
+ Frame frame2;
+ if (i+1 < n && (frame1= this.frames.get(i+1)).getCall() != null
+ && frame1.getCall().startsWith("eval.with.vis(") ) { //$NON-NLS-1$
+ frame0.addFlags((FLAG_SOURCE | 0));
+ frame1.addFlags((FLAG_SOURCE | 1));
+ i++;
+ if (i+1 < n && (frame2= this.frames.get(i+1)).getCall() != null
+ && frame2.getCall().startsWith("eval.with.vis(") ) { //$NON-NLS-1$
+ frame2.addFlags((FLAG_SOURCE | 2));
+ i++;
+ }
+ }
+ else if (i+2 < n && (frame1= this.frames.get(i+1)).getCall() != null
+ && frame1.getCall().startsWith("withVisible(") //$NON-NLS-1$
+ && (frame2= this.frames.get(i+2)).getCall() != null
+ && frame2.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+ frame0.addFlags((FLAG_SOURCE | 0));
+ frame1.addFlags((FLAG_SOURCE | 1));
+ frame2.addFlags((FLAG_SOURCE | 2));
+ i+= 2;
+ if (i+1 < n && (frame2= this.frames.get(i+1)).getCall() != null
+ && frame2.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+ frame2.addFlags((FLAG_SOURCE | 3));
+ i++;
+ }
+ }
+ }
+ else if (frame0.getCall().startsWith("rj:::.statet.evalCommand(") //$NON-NLS-1$
+ || frame0.getCall().startsWith(".statet.evalCommand(") ) { //$NON-NLS-1$
+ frame0.addFlags((FLAG_COMMAND | 0));
+ final Frame frame1;
+ if (i+1 < n && (frame1= this.frames.get(i+1)).getCall() != null
+ && frame1.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+ frame1.addFlags((FLAG_COMMAND | 1));
+ i++;
+ final Frame frame2;
+ if (i+1 < n && (frame2= this.frames.get(i+1)).getCall() != null
+ && frame2.getCall().startsWith("eval(") ) { //$NON-NLS-1$
+ frame2.addFlags((FLAG_COMMAND | 2));
+ i++;
+ }
+ }
+ }
+ }
+ }
+
+ this.frames.get(n-1).addFlags(FLAG_TOPFRAME);
+ }
+
+ public List<? extends Frame> getFrames() {
+ return this.frames;
+ }
+
+ public Frame findFrame(final long handle) {
+ for (int i= 0; i < this.frames.size(); i++) {
+ final Frame frame= this.frames.get(i);
+ if (frame.getHandle() == handle) {
+ return frame;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CtrlReport.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CtrlReport.java
new file mode 100644
index 0000000..cd24356
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/CtrlReport.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class CtrlReport implements RJIOExternalizable {
+
+
+ private final static int REQUEST_EXECUTED= 0x01000000;
+
+ private final static int ENGINE_EXECUTING= 0;
+ private final static int ENGINE_SUSPENDED= 0x02000000;
+
+ private final static int RESET_PROMPT= 0x00100000;
+
+
+ public static CtrlReport createRequestExecuted(final byte type) {
+ switch (type) {
+ case DbgRequest.RESUME:
+ case DbgRequest.STEP_INTO:
+ case DbgRequest.STEP_OVER:
+ case DbgRequest.STEP_RETURN:
+ return new CtrlReport(type | REQUEST_EXECUTED | ENGINE_EXECUTING);
+ default:
+ throw new IllegalArgumentException("type= " + type); //$NON-NLS-1$
+ }
+ }
+
+ public static CtrlReport createRequestNotApplicable(final boolean isEngineSuspended) {
+ return new CtrlReport((isEngineSuspended) ? ENGINE_SUSPENDED : ENGINE_EXECUTING);
+ }
+
+ public static CtrlReport createRequestNotSupported(final boolean isEngineSuspended) {
+ return new CtrlReport((isEngineSuspended) ? ENGINE_SUSPENDED : ENGINE_EXECUTING);
+ }
+
+
+ private final int code;
+
+
+ private CtrlReport(final int code) {
+ this.code= code;
+ }
+
+ public CtrlReport(final RJIO io) throws IOException {
+ this.code= io.readInt();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.code);
+ }
+
+
+ public byte getOp() {
+ return (byte) (this.code & 0xff);
+ }
+
+ public boolean isRequestExecuted() {
+ return ((this.code & REQUEST_EXECUTED) != 0);
+ }
+
+ public boolean isEngineSuspended() {
+ return ((this.code & ENGINE_SUSPENDED) != 0);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgEnablement.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgEnablement.java
new file mode 100644
index 0000000..dd2665f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgEnablement.java
@@ -0,0 +1,50 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class DbgEnablement implements RJIOExternalizable {
+
+
+ private static final int ENABLE_BREAKPOINTS= 0x00000001;
+
+
+ private final int properties;
+
+
+ public DbgEnablement(final boolean breakpointsEnabled) {
+ this.properties= (breakpointsEnabled) ? ENABLE_BREAKPOINTS : 0;
+ }
+
+ public DbgEnablement(final RJIO io) throws IOException {
+ this.properties= io.readInt();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.properties);
+ }
+
+
+ public boolean getBreakpointsEnabled() {
+ return ((this.properties & ENABLE_BREAKPOINTS) != 0);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgFilterState.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgFilterState.java
new file mode 100644
index 0000000..43e11e2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgFilterState.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class DbgFilterState implements RJIOExternalizable {
+
+
+ private final int stepFilterState;
+
+
+ public DbgFilterState(final boolean stepFilterEnabled) {
+ this.stepFilterState= (stepFilterEnabled) ? 0x1 : 0x0;
+ }
+
+ public DbgFilterState(final RJIO io) throws IOException {
+ this.stepFilterState= io.readInt();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.stepFilterState);
+ }
+
+
+ public boolean stepFilterEnabled() {
+ return ((this.stepFilterState & 0x1) != 0);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgListener.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgListener.java
new file mode 100644
index 0000000..17e8cbb
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgListener.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public interface DbgListener {
+
+
+ void handle(TracepointEvent event);
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgRequest.java
new file mode 100644
index 0000000..316219a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/DbgRequest.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+import org.eclipse.statet.rj.server.DbgCmdItem;
+import org.eclipse.statet.rj.server.Operation;
+
+
+public abstract class DbgRequest implements Operation, RJIOExternalizable {
+
+
+ public static final byte RESUME= DbgCmdItem.OP_CTRL_RESUME;
+ public static final byte STEP_INTO= DbgCmdItem.OP_CTRL_STEP_INTO;
+ public static final byte STEP_OVER= DbgCmdItem.OP_CTRL_STEP_OVER;
+ public static final byte STEP_RETURN= DbgCmdItem.OP_CTRL_STEP_RETURN;
+
+
+ private static final int FRAME_POSITION= 00000001;
+ private static final int FRAME_HANDLE= 00000002;
+
+
+ public static class Resume extends DbgRequest implements SyncOp {
+
+
+ public Resume() {
+ }
+
+ public Resume(final RJIO in) throws IOException {
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ }
+
+
+ @Override
+ public byte getOp() {
+ return RESUME;
+ }
+
+ }
+
+ public static class StepOver extends DbgRequest implements SyncOp {
+
+
+ public StepOver() {
+ }
+
+ public StepOver(final RJIO in) throws IOException {
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ }
+
+
+ @Override
+ public byte getOp() {
+ return STEP_OVER;
+ }
+
+ }
+
+ public static class StepInto extends DbgRequest implements SyncOp {
+
+
+ public StepInto() {
+ }
+
+ public StepInto(final RJIO in) throws IOException {
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ }
+
+
+ @Override
+ public byte getOp() {
+ return STEP_INTO;
+ }
+
+ }
+
+ public static class StepReturn extends DbgRequest implements SyncOp {
+
+
+ private final int detail;
+
+ private final RJIOExternalizable target;
+
+
+ public StepReturn(final FrameRef target) {
+ if (target instanceof FrameRef.ByPosition) {
+ this.detail= FRAME_POSITION;
+ }
+ else if (target instanceof FrameRef.ByHandle) {
+ this.detail= FRAME_HANDLE;
+ }
+ else {
+ throw new IllegalArgumentException("target"); //$NON-NLS-1$
+ }
+ this.target= target;
+ }
+
+ public StepReturn(final RJIO in) throws IOException {
+ this.detail= in.readInt();
+ switch (this.detail & 0xf) {
+ case FRAME_POSITION:
+ this.target= new FrameRef.ByPosition(in);
+ break;
+ case FRAME_HANDLE:
+ this.target= new FrameRef.ByHandle(in);
+ break;
+ default:
+ throw new IOException();
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.detail);
+ this.target.writeExternal(out);
+ }
+
+
+ @Override
+ public byte getOp() {
+ return STEP_RETURN;
+ }
+
+ public Object getTarget() {
+ return this.target;
+ }
+
+ }
+
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointInstallationRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointInstallationRequest.java
new file mode 100644
index 0000000..76b5189
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointInstallationRequest.java
@@ -0,0 +1,58 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class ElementTracepointInstallationRequest extends TracepointInstallationRequest {
+
+
+ private final List<? extends ElementTracepointPositions> requests;
+
+
+ public ElementTracepointInstallationRequest(
+ final List<? extends ElementTracepointPositions> checkedList) {
+ this.requests= checkedList;
+ }
+
+ public ElementTracepointInstallationRequest(final RJIO io) throws IOException {
+ final int l= io.readInt();
+ final List<ElementTracepointPositions> list= new ArrayList<>(l);
+ for (int i= 0; i < l; i++) {
+ list.add(new ElementTracepointPositions(io));
+ }
+ this.requests= list;
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ final int l= this.requests.size();
+ io.writeInt(l);
+ for (int i= 0; i < l; i++) {
+ this.requests.get(i).writeExternal(io);
+ }
+ }
+
+
+ public List<? extends ElementTracepointPositions> getRequests() {
+ return this.requests;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointPositions.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointPositions.java
new file mode 100644
index 0000000..727b69b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/ElementTracepointPositions.java
@@ -0,0 +1,102 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class ElementTracepointPositions implements RJIOExternalizable {
+
+
+ private final SrcfileData fileInfo;
+
+ private final String elementId;
+ private final int[] elementSrcref;
+
+ private final List<TracepointPosition> positions;
+
+
+ public ElementTracepointPositions(final SrcfileData fileInfo,
+ final String elementId, final int[] elementSrcref) {
+ if (fileInfo == null) {
+ throw new NullPointerException("fileInfo"); //$NON-NLS-1$
+ }
+ if (elementId == null) {
+ throw new NullPointerException("elementId"); //$NON-NLS-1$
+ }
+ this.fileInfo= fileInfo;
+ this.elementId= elementId;
+ this.elementSrcref= elementSrcref;
+ this.positions= new ArrayList<>(4);
+ }
+
+ public ElementTracepointPositions(final RJIO io) throws IOException {
+ this.fileInfo= new SrcfileData(io);
+ this.elementId= io.readString();
+ this.elementSrcref= io.readIntArray();
+ final int l= io.readInt();
+ this.positions= new ArrayList<>(l);
+ for (int i= 0; i < l; i++) {
+ this.positions.add(new TracepointPosition(io));
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ this.fileInfo.writeExternal(io);
+ io.writeString(this.elementId);
+ io.writeIntArray(this.elementSrcref, (this.elementSrcref != null) ? 6 : -1);
+ final int l= this.positions.size();
+ io.writeInt(l);
+ for (int i= 0; i < l; i++) {
+ this.positions.get(i).writeExternal(io);
+ }
+ }
+
+
+ public SrcfileData getSrcfile() {
+ return this.fileInfo;
+ }
+
+ public String getElementId() {
+ return this.elementId;
+ }
+
+ public int[] getElementSrcref() {
+ return this.elementSrcref;
+ }
+
+ public List<? extends TracepointPosition> getPositions() {
+ return this.positions;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder("ElementTracepointPositions"); //$NON-NLS-1$
+ sb.append(" for ").append(this.elementId); //$NON-NLS-1$
+ sb.append("\n").append("list (count= ").append(this.positions.size()).append("):"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ for (int i= 0; i < this.positions.size(); i++) {
+ sb.append("\n").append(this.positions.get(i).toString()); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FlagTracepointInstallationRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FlagTracepointInstallationRequest.java
new file mode 100644
index 0000000..302cf70
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FlagTracepointInstallationRequest.java
@@ -0,0 +1,60 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+
+
+public class FlagTracepointInstallationRequest extends TracepointInstallationRequest {
+
+
+ private final byte[] types;
+ private final int[] flags;
+
+
+ public FlagTracepointInstallationRequest(final byte[] types, final int[] flags) {
+ if (types.length != flags.length) {
+ throw new IllegalArgumentException("types.length != flags.length");
+ }
+ this.types= types;
+ this.flags= flags;
+ }
+
+ public FlagTracepointInstallationRequest(final RJIO in) throws IOException {
+ final int l= in.readInt();
+ this.types= in.readByteData(new byte[l], l);
+ this.flags= in.readIntData(new int[l], l);
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ final int l= this.types.length;
+ out.writeInt(l);
+ out.writeByteData(this.types, l);
+ out.writeIntData(this.flags, l);
+ }
+
+
+ public byte[] getTypes() {
+ return this.types;
+ }
+
+ public int[] getFlags() {
+ return this.flags;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Frame.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Frame.java
new file mode 100644
index 0000000..564ace6
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Frame.java
@@ -0,0 +1,93 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public class Frame {
+
+
+ private final int position;
+ private final String call;
+
+ protected long handle;
+
+ protected String fileName;
+ protected long fileTimestamp;
+
+ protected int[] exprSrcref;
+
+ protected int flags;
+
+
+ public Frame(final int position, final String call, final long handle,
+ final String fileName, final long fileTimestamp, final int[] exprSrcref) {
+ this.position= position;
+ this.call= call;
+ this.handle= handle;
+ this.fileName= fileName;
+ this.fileTimestamp= fileTimestamp;
+ this.exprSrcref= exprSrcref;
+ }
+
+ protected Frame(final int position, final String call) {
+ this.position= position;
+ this.call= call;
+ }
+
+
+ public int getPosition() {
+ return this.position;
+ }
+
+ public String getCall() {
+ return this.call;
+ }
+
+ public long getHandle() {
+ return this.handle;
+ }
+
+ public String getFileName() {
+ return this.fileName;
+ }
+
+ public long getFileTimestamp() {
+ return this.fileTimestamp;
+ }
+
+ public int[] getExprSrcref() {
+ return this.exprSrcref;
+ }
+
+
+ public int getFlags() {
+ return this.flags;
+ }
+
+ public void addFlags(final int flags) {
+ this.flags |= flags;
+ }
+
+ /** top frame */
+ public boolean isTopFrame() {
+ return ((this.flags & CallStack.FLAG_TOPFRAME) != 0);
+ }
+
+ /** frame of top level command */
+ public boolean isTopLevelCommand() {
+ return (this.position == 3 && (this.flags & 0xff) == (CallStack.FLAG_COMMAND | 2));
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContext.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContext.java
new file mode 100644
index 0000000..d1cd78b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContext.java
@@ -0,0 +1,156 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class FrameContext implements RJIOExternalizable {
+
+
+ public static final int SOURCETYPE_1_LINES= 1;
+ public static final int SOURCETYPE_1_FILE= 2;
+ public static final int SOURCETYPE_2_LINES= 3;
+ public static final int SOURCETYPE_3_DEPARSE= 4;
+
+
+ private final int position;
+ private final String call;
+
+ protected String fileName;
+ protected long fileTimestamp;
+ protected String fileEncoding;
+ protected String filePath;
+
+ protected int sourceType;
+ protected String sourceCode;
+ protected int[] sourceSrcref;
+
+ protected int[] firstSrcref;
+ protected int[] lastSrcref;
+ protected int[] exprSrcref;
+
+
+ public FrameContext(final int position, final String call,
+ final String fileName, final long fileTimestamp, final String fileEncoding,
+ final String filePath, final int sourceType, final String sourceCode, final int[] sourceSrcref,
+ final int[] firstSrcref, final int[] lastSrcref, final int[] exprSrcref) {
+ this.position= position;
+ this.call= call;
+
+ this.fileName= fileName;
+ this.fileTimestamp= fileTimestamp;
+ this.fileEncoding= fileEncoding;
+ this.filePath= filePath;
+
+ this.sourceType= sourceType;
+ this.sourceCode= sourceCode;
+ this.sourceSrcref= sourceSrcref;
+
+ this.firstSrcref= firstSrcref;
+ this.lastSrcref= lastSrcref;
+ this.exprSrcref= exprSrcref;
+ }
+
+ public FrameContext(final RJIO io) throws IOException {
+ this.position= io.readInt();
+ this.call= io.readString();
+
+ this.fileName= io.readString();
+ this.fileTimestamp= io.readLong();
+ this.fileEncoding= io.readString();
+ this.filePath= io.readString();
+
+ this.sourceType= io.readInt();
+ this.sourceCode= io.readString();
+ this.sourceSrcref= io.readIntArray();
+
+ this.firstSrcref= io.readIntArray();
+ this.lastSrcref= io.readIntArray();
+ this.exprSrcref= io.readIntArray();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.position);
+ io.writeString(this.call);
+
+ io.writeString(this.fileName);
+ io.writeLong(this.fileTimestamp);
+ io.writeString(this.fileEncoding);
+ io.writeString(this.filePath);
+
+ io.writeInt(this.sourceType);
+ io.writeString(this.sourceCode);
+ io.writeIntArray(this.sourceSrcref, (this.sourceSrcref != null) ? 6 : -1);
+
+ io.writeIntArray(this.firstSrcref, (this.firstSrcref != null) ? 6 : -1);
+ io.writeIntArray(this.lastSrcref, (this.lastSrcref != null) ? 6 : -1);
+ io.writeIntArray(this.exprSrcref, (this.exprSrcref != null) ? 6 : -1);
+ }
+
+
+ public int getPosition() {
+ return this.position;
+ }
+
+ public String getCall() {
+ return this.call;
+ }
+
+ public String getFileName() {
+ return this.fileName;
+ }
+
+ public long getFileTimestamp() {
+ return this.fileTimestamp;
+ }
+
+ public String getFileEncoding() {
+ return this.fileEncoding;
+ }
+
+ public String getFilePath() {
+ return this.filePath;
+ }
+
+ public int getSourceType() {
+ return this.sourceType;
+ }
+
+ public String getSourceCode() {
+ return this.sourceCode;
+ }
+
+ public int[] getSourceSrcref() {
+ return this.sourceSrcref;
+ }
+
+ public int[] getFirstSrcref() {
+ return this.firstSrcref;
+ }
+
+ public int[] getLastSrcref() {
+ return this.lastSrcref;
+ }
+
+ public int[] getExprSrcref() {
+ return this.exprSrcref;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContextDetailRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContextDetailRequest.java
new file mode 100644
index 0000000..733a51e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameContextDetailRequest.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class FrameContextDetailRequest implements RJIOExternalizable {
+
+
+ private final int position;
+
+
+ public FrameContextDetailRequest(final int position) {
+ this.position= position;
+ }
+
+ public FrameContextDetailRequest(final RJIO io) throws IOException {
+ this.position= io.readInt();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.position);
+ }
+
+
+ public int getPosition() {
+ return this.position;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameRef.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameRef.java
new file mode 100644
index 0000000..49e7709
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/FrameRef.java
@@ -0,0 +1,80 @@
+/*=============================================================================#
+ # Copyright (c) 2014, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+/**
+ * References a frame of the callstack.
+ */
+public abstract class FrameRef implements RJIOExternalizable {
+
+
+ public static final class ByPosition extends FrameRef {
+
+
+ private final int position;
+
+
+ public ByPosition(final int position) {
+ this.position= position;
+ }
+
+ public ByPosition(final RJIO in) throws IOException {
+ this.position= in.readInt();
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeInt(this.position);
+ }
+
+
+ public int getPosition() {
+ return this.position;
+ }
+
+ }
+
+ public static final class ByHandle extends FrameRef {
+
+
+ private final long handle;
+
+
+ public ByHandle(final long handle) {
+ this.handle= handle;
+ }
+
+ public ByHandle(final RJIO in) throws IOException {
+ this.handle= in.readLong();
+ }
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeLong(this.handle);
+ }
+
+
+ public long getHandle() {
+ return this.handle;
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugReport.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugReport.java
new file mode 100644
index 0000000..cc5d5ca
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugReport.java
@@ -0,0 +1,49 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class SetDebugReport implements RJIOExternalizable {
+
+
+ private static final int CHANGED= 0x000000001;
+
+
+ private final int resultCode;
+
+
+ public SetDebugReport(final boolean changed) {
+ this.resultCode= (changed) ? CHANGED : 0;
+ }
+
+ public SetDebugReport(final RJIO io) throws IOException {
+ this.resultCode= io.readInt();
+ }
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.resultCode);
+ }
+
+
+ public boolean isChanged() {
+ return ((this.resultCode & CHANGED) != 0);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugRequest.java
new file mode 100644
index 0000000..5ff2cac
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SetDebugRequest.java
@@ -0,0 +1,124 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class SetDebugRequest implements RJIOExternalizable {
+
+ public static final int FRAME= 1 << 0;
+ public static final int FUNCTION= 1 << 1;
+
+ private static final int ENABLED= 1 << 0 << 24;
+
+ private static final int TEMP= 1 << 8;
+
+
+ private final long frameId;
+ private final String fName;
+
+ private final int properties;
+
+
+ public SetDebugRequest(final long frameId, final boolean enable, final boolean temp) {
+ this.frameId= frameId;
+ this.fName= null;
+ int props= FRAME;
+ if (enable) {
+ props |= ENABLED;
+ }
+ if (temp) {
+ props |= TEMP;
+ }
+ this.properties= props;
+ }
+
+ public SetDebugRequest(final int position, final String fName, final boolean enable, final boolean temp) {
+ this.frameId= position;
+ this.fName= fName;
+ int props= FUNCTION;
+ if (enable) {
+ props |= ENABLED;
+ }
+ if (temp) {
+ props |= TEMP;
+ }
+ this.properties= props;
+ }
+
+ public SetDebugRequest(final RJIO io) throws IOException {
+ this.properties= io.readInt();
+ switch (this.properties & 0xf) {
+ case FRAME:
+ this.frameId= io.readLong();
+ this.fName= null;
+ break;
+ case FUNCTION:
+ this.frameId= io.readInt();
+ this.fName= io.readString();
+ break;
+ default:
+ this.frameId= 0;
+ this.fName= null;
+ break;
+ }
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.properties);
+ switch (this.properties & 0xf) {
+ case FRAME:
+ io.writeLong(this.frameId);
+ break;
+ case FUNCTION:
+ io.writeInt((int) this.frameId);
+ io.writeString(this.fName);
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ public int getType() {
+ return (this.properties & 0xf);
+ }
+
+ public long getHandle() {
+ return this.frameId;
+ }
+
+ public int getPosition() {
+ return (int) this.frameId;
+ }
+
+ public String getName() {
+ return this.fName;
+ }
+
+ public boolean isTemp() {
+ return ((this.properties & TEMP) != 0);
+ }
+
+ public int getDebug() {
+ return ((this.properties & 0xff000000) >>> 24);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SrcfileData.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SrcfileData.java
new file mode 100644
index 0000000..8b8c33c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/SrcfileData.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.Objects;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class SrcfileData implements RJIOExternalizable {
+
+
+ private final String path;
+ private final String name;
+ private final long timestamp;
+
+
+ public SrcfileData(final String path, final String name, final long timestamp) {
+ this.path= path;
+ this.name= name;
+ this.timestamp= timestamp;
+ }
+
+ public SrcfileData(final RJIO io) throws IOException {
+ this.path= io.readString();
+ this.name= io.readString();
+ this.timestamp= io.readLong();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeString(this.path);
+ io.writeString(this.name);
+ io.writeLong(this.timestamp);
+ }
+
+
+ /**
+ * Returns the file path in the application (e.g. path in Eclipse workspace)
+ * @return the path or <code>null</code>
+ */
+ public String getPath() {
+ return this.path;
+ }
+
+ /**
+ * Returns the complete standardized file path usually compatible with 'filename' properties in
+ * R.
+ * @return the path or <code>null</code>
+ */
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * Returns the modification timestamp of the file compatible with 'timestamp' properties in R
+ * (seconds, not milliseconds).
+ *
+ * @return the timestamp or <code>0</code>
+ */
+ public long getTimestamp() {
+ return this.timestamp;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(this.path) * 17
+ ^ Objects.hashCode(this.name)
+ ^ (int)(this.timestamp ^ (this.timestamp >>> 32));
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj instanceof SrcfileData) {
+ final SrcfileData other= (SrcfileData) obj;
+ return (Objects.equals(this.path, other.path)
+ && Objects.equals(this.name, other.name)
+ && this.timestamp == other.timestamp );
+ }
+ return super.equals(obj);
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder("SrcfileData"); //$NON-NLS-1$
+ sb.append("\n\t" + "path= ").append(this.path); //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append("\n\t" + "name= ").append(this.name); //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append("\n\t" + "timestamp= ").append(this.timestamp); //$NON-NLS-1$ //$NON-NLS-2$
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Srcref.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Srcref.java
new file mode 100644
index 0000000..bdaf9ed
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Srcref.java
@@ -0,0 +1,153 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public class Srcref {
+
+
+ public static final int BEGIN_LINE= 0;
+ public static final int BEGIN_COLUMN= 4;
+ public static final int BEGIN_BYTE= 1;
+
+ public static final int END_LINE= 2;
+ public static final int END_COLUMN= 5;
+ public static final int END_BYTE= 3;
+
+ public static final int NA= Integer.MIN_VALUE;
+
+
+ public static int[] diff(final int[] base, final int[] rel) {
+ final int[] diff= new int[6];
+
+ if (base[BEGIN_LINE] > 0 && rel[BEGIN_LINE] > 0) {
+ diff[BEGIN_LINE]= 1 + rel[BEGIN_LINE] - base[BEGIN_LINE];
+ if (diff[BEGIN_LINE] <= 0) {
+ return null;
+ }
+ }
+ else {
+ diff[BEGIN_LINE]= NA;
+ }
+ if (diff[BEGIN_LINE] == 1) {
+ if (base[BEGIN_COLUMN] > 0 && rel[BEGIN_COLUMN] > 0) {
+ diff[BEGIN_COLUMN]= 1 + rel[BEGIN_COLUMN] - base[BEGIN_COLUMN];
+ if (diff[BEGIN_COLUMN] <= 0) {
+ return null;
+ }
+ }
+ else {
+ diff[BEGIN_COLUMN]= NA;
+ }
+ if (base[BEGIN_BYTE] > 0 && rel[BEGIN_BYTE] > 0) {
+ diff[BEGIN_BYTE]= 1 + rel[BEGIN_BYTE] - base[BEGIN_BYTE];
+ if (diff[BEGIN_BYTE] <= 0) {
+ diff[BEGIN_BYTE]= NA;
+ }
+ }
+ else {
+ diff[BEGIN_BYTE]= NA;
+ }
+ }
+
+ if (base[BEGIN_LINE] > 0 && rel[END_LINE] > 0) {
+ diff[END_LINE]= 1 + rel[END_LINE] - base[BEGIN_LINE];
+ if (diff[END_LINE] <= 0) {
+ return null;
+ }
+ }
+ else {
+ diff[END_LINE]= NA;
+ }
+ if (diff[END_LINE] == 1) {
+ if (base[BEGIN_COLUMN] > 0 && rel[END_COLUMN] > 0) {
+ diff[END_COLUMN]= 1 + rel[END_COLUMN] - base[BEGIN_COLUMN];
+ if (diff[END_COLUMN] <= 0) {
+ return null;
+ }
+ }
+ else {
+ diff[END_COLUMN]= NA;
+ }
+ if (base[BEGIN_BYTE] > 0 && rel[END_BYTE] > 0) {
+ diff[END_BYTE]= 1 + rel[END_BYTE] - base[BEGIN_BYTE];
+ if (diff[END_BYTE] <= 0) {
+ diff[END_BYTE]= NA;
+ }
+ }
+ else {
+ diff[END_BYTE]= NA;
+ }
+ }
+
+ return diff;
+ }
+
+ public static int addLine(final int base, final int diff) {
+ if (base > 0 && diff > 0) {
+ return base + diff - 1;
+ }
+ else {
+ return NA;
+ }
+ }
+
+ public static int[] add(final int[] base, final int[] diff) {
+ final int[] sum= new int[6];
+
+ sum[BEGIN_LINE]= addLine(base[BEGIN_LINE], diff[BEGIN_LINE]);
+ if (diff[BEGIN_LINE] == 1) {
+ if (base[BEGIN_COLUMN] > 0 && diff[BEGIN_COLUMN] > 0) {
+ sum[BEGIN_COLUMN]= base[BEGIN_COLUMN] + diff[BEGIN_COLUMN] - 1;
+ }
+ else {
+ sum[BEGIN_COLUMN]= NA;
+ }
+ if (base[BEGIN_BYTE] > 0 && diff[BEGIN_BYTE] > 0) {
+ sum[BEGIN_BYTE]= base[BEGIN_BYTE] + diff[BEGIN_BYTE] - 1;
+ }
+ else {
+ sum[BEGIN_BYTE]= NA;
+ }
+ }
+ else {
+ sum[BEGIN_COLUMN]= base[BEGIN_COLUMN];
+ sum[BEGIN_BYTE]= base[BEGIN_BYTE];
+ }
+
+ sum[END_LINE]= addLine(base[BEGIN_LINE], diff[END_LINE]);
+ if (diff[END_LINE] == 1) {
+ if (base[BEGIN_COLUMN] > 0 && diff[END_COLUMN] > 0) {
+ sum[END_COLUMN]= base[BEGIN_COLUMN] + diff[END_COLUMN] - 1;
+ }
+ else {
+ sum[END_COLUMN]= NA;
+ }
+ if (base[BEGIN_BYTE] > 0 && diff[END_BYTE] > 0) {
+ sum[END_BYTE]= base[BEGIN_BYTE] + diff[END_BYTE] - 1;
+ }
+ else {
+ sum[END_BYTE]= NA;
+ }
+ }
+ else {
+ sum[END_COLUMN]= base[END_COLUMN];
+ sum[END_BYTE]= base[END_BYTE];
+ }
+
+ return sum;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Tracepoint.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Tracepoint.java
new file mode 100644
index 0000000..0552680
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/Tracepoint.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+
+public interface Tracepoint {
+
+ /** all breakpoint types */
+ byte TYPE_BREAKPOINT= 0x0_0000_000F;
+ /** function breakpoint */
+ byte TYPE_FB= 0x0_0000_0001;
+ /** line breakpoint */
+ byte TYPE_LB= 0x0_0000_0002;
+ /** toplevel line breakpoint */
+ byte TYPE_TB= 0x0_0000_0003;
+ /** exception breakpoint */
+ byte TYPE_EB= 0x0_0000_0005;
+
+ int TYPE_DELETED= 0x0_0100_0000;
+
+
+ int getType();
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointEvent.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointEvent.java
new file mode 100644
index 0000000..65abac1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointEvent.java
@@ -0,0 +1,99 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointEvent implements Tracepoint, RJIOExternalizable {
+
+
+ public static final byte KIND_ABOUT_TO_HIT= 0x01;
+
+
+ private final byte kind;
+
+ private final int type;
+
+ private final String filePath;
+ private final long id;
+
+ private final String label;
+ private final int flags;
+ private final String message;
+
+
+ public TracepointEvent(final byte kind, final int type, final String filePath, final long id,
+ final String label, final int flags, final String message) {
+ this.kind= kind;
+ this.type= type;
+ this.filePath= filePath;
+ this.id= id;
+ this.label= label;
+ this.flags= flags;
+ this.message= message;
+ }
+
+ public TracepointEvent(final RJIO io) throws IOException {
+ this.kind= io.readByte();
+ this.type= io.readInt();
+ this.filePath= io.readString();
+ this.id= io.readLong();
+ this.label= io.readString();
+ this.flags= io.readInt();
+ this.message= io.readString();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeByte(this.kind);
+ io.writeInt(this.type);
+ io.writeString(this.filePath);
+ io.writeLong(this.id);
+ io.writeString(this.label);
+ io.writeInt(this.flags);
+ io.writeString(this.message);
+ }
+
+
+ public byte getKind() {
+ return this.kind;
+ }
+
+ @Override
+ public int getType() {
+ return this.type;
+ }
+
+ public String getFilePath() {
+ return this.filePath;
+ }
+
+ public long getId() {
+ return this.id;
+ }
+
+ public String getLabel() {
+ return this.label;
+ }
+
+ public int getFlags() {
+ return this.flags;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationReport.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationReport.java
new file mode 100644
index 0000000..109a091
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationReport.java
@@ -0,0 +1,53 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointInstallationReport implements RJIOExternalizable {
+
+
+ public static final int NOTFOUND= 1;
+ public static final int FOUND_UNCHANGED= 2;
+ public static final int FOUND_UNSET= 3;
+ public static final int FOUND_SET= 4;
+
+
+ private final int[] results;
+
+
+ public TracepointInstallationReport(final int[] resultCodes) {
+ this.results= resultCodes;
+ }
+
+ public TracepointInstallationReport(final RJIO io) throws IOException {
+ this.results= io.readIntArray();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeIntArray(this.results, this.results.length);
+ }
+
+
+ public int[] getInstallationResults() {
+ return this.results;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationRequest.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationRequest.java
new file mode 100644
index 0000000..f1b384e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointInstallationRequest.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public abstract class TracepointInstallationRequest implements RJIOExternalizable {
+
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointPosition.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointPosition.java
new file mode 100644
index 0000000..9ce6cba
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointPosition.java
@@ -0,0 +1,129 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointPosition implements Tracepoint, Comparable<TracepointPosition>,
+ RJIOExternalizable {
+
+
+ private final int type;
+
+ private final long id;
+
+ protected int[] exprIndex;
+ protected int[] exprSrcref;
+
+
+ public TracepointPosition(final int type, final long id,
+ final int[] index, final int[] srcref) {
+ this.type= type;
+ this.id= id;
+ this.exprIndex= index;
+ this.exprSrcref= srcref;
+ }
+
+ TracepointPosition(final RJIO io) throws IOException {
+ this.type= io.readInt();
+ this.id= io.readLong();
+ this.exprIndex= io.readIntArray();
+ this.exprSrcref= io.readIntArray();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.type);
+ io.writeLong(this.id);
+ io.writeIntArray(this.exprIndex, this.exprIndex.length);
+ io.writeIntArray(this.exprSrcref, (this.exprSrcref != null) ? 6 : -1);
+ }
+
+
+ @Override
+ public int getType() {
+ return this.type;
+ }
+
+ public long getId() {
+ return this.id;
+ }
+
+ public int[] getIndex() {
+ return this.exprIndex;
+ }
+
+ public int[] getSrcref() {
+ return this.exprSrcref;
+ }
+
+
+ @Override
+ public int compareTo(final TracepointPosition other) {
+ for (int i= 0; i < this.exprIndex.length; i++) {
+ if (i < other.exprIndex.length) {
+ final int diff= this.exprIndex[i] - other.exprIndex[i];
+ if (diff != 0) {
+ return diff;
+ }
+ else {
+ continue;
+ }
+ }
+ return 1; // this deeper
+ }
+ if (this.exprIndex.length != other.exprIndex.length) {
+ return -1; // other deeper
+ }
+ return this.type - other.type;
+ }
+
+ @Override
+ public int hashCode() {
+ int h= this.type;
+ for (int i= 0; i < this.exprIndex.length; i++) {
+ h= this.exprIndex[i] * 128 * (i + 1) ^ 2;
+ }
+ return h;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof TracepointPosition)) {
+ return false;
+ }
+ final TracepointPosition other= (TracepointPosition) obj;
+ return (this.type == other.type
+ && Arrays.equals(this.exprIndex, other.exprIndex) );
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder("TracepointPosition"); //$NON-NLS-1$
+ sb.append(" (type= ").append(this.type).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append("\n\t" + "exprIndex= ").append(Arrays.toString(this.exprIndex)); //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append("\n\t" + "exprSrcref= ").append(Arrays.toString(this.exprSrcref)); //$NON-NLS-1$ //$NON-NLS-2$
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointState.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointState.java
new file mode 100644
index 0000000..a2705a0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointState.java
@@ -0,0 +1,286 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointState implements Tracepoint, Comparable<TracepointState>, RJIOExternalizable {
+
+
+ static final List<TracepointState> readList(final RJIO io) throws IOException {
+ final int l= io.readInt();
+ final List<TracepointState> list= new ArrayList<>(l);
+ String filePath= null;
+ String elementId= null;
+ for (int i= 0; i < l; i++) {
+ final TracepointState state= new TracepointState();
+ list.add(state);
+ state.type= io.readInt();
+ state.id= io.readLong();
+ state.filePath= io.readString();
+ if (state.filePath != null) {
+ filePath= state.filePath;
+ }
+ else {
+ state.filePath= filePath;
+ }
+ if (state.type == TYPE_DELETED) {
+ continue;
+ }
+ state.elementId= io.readString();
+ if (state.elementId != null) {
+ elementId= state.elementId;
+ }
+ else {
+ state.elementId= elementId;
+ }
+ state.index= io.readIntArray();
+ state.elementLabel= io.readString();
+ state.flags= io.readInt();
+ state.expr= io.readString();
+ }
+ return list;
+ }
+
+ static final void writeList(final List<TracepointState> list, final RJIO io) throws IOException {
+ final int l= list.size();
+ io.writeInt(l);
+ String filePath= null;
+ String elementId= null;
+ for (int i= 0; i < l; i++) {
+ final TracepointState state= list.get(i);
+ io.writeInt(state.type);
+ io.writeLong(state.id);
+ if (state.filePath.equals(filePath)) {
+ io.writeString(null);
+ }
+ else {
+ filePath= state.filePath;
+ io.writeString(filePath);
+ }
+ if (state.type == TYPE_DELETED) {
+ continue;
+ }
+ if (state.elementId.equals(elementId)) {
+ io.writeString(null);
+ }
+ else {
+ elementId= state.elementId;
+ io.writeString(elementId);
+ }
+ io.writeIntArray(state.index, state.index.length);
+ io.writeString(state.elementLabel);
+ io.writeInt(state.flags);
+ io.writeString(state.expr);
+ }
+ }
+
+
+ public static final int FLAG_ENABLED= 0x00000001;
+
+ public static final int FLAG_MB_ENTRY= 0x00010000;
+ public static final int FLAG_MB_EXIT= 0x00020000;
+
+ public static final int FLAG_EXPR_INVALID= 0x01000000;
+ public static final int FLAG_EXPR_EVAL_FAILED= 0x02000000;
+
+ public static final String EB_FILEPATH= "exception"; //$NON-NLS-1$
+
+
+ private static final int[] NO_IDX= new int[0];
+
+
+ private int type;
+
+ private String filePath;
+ private long id;
+
+ private String elementId;
+ private int[] index;
+
+ protected String elementLabel;
+ protected int flags;
+ protected String expr;
+
+
+ public TracepointState(final int type,
+ final String filePath, final long id, final String elementId, final int[] index,
+ final String elementLabel, final int flags, final String expr) {
+ if (filePath == null || elementId == null || index == null) {
+ throw new NullPointerException();
+ }
+ this.type= type;
+ this.filePath= filePath;
+ this.id= id;
+ this.elementId= elementId;
+ this.index= index;
+ this.elementLabel= elementLabel;
+ this.flags= flags;
+ this.expr= expr;
+ }
+
+ public TracepointState(final int type,
+ final String filePath, final long id, final String elementId,
+ final String elementLabel, final int flags, final String expr) {
+ if (filePath == null || elementId == null) {
+ throw new NullPointerException();
+ }
+ this.type= type;
+ this.filePath= filePath;
+ this.id= id;
+ this.elementId= elementId;
+ this.index= NO_IDX;
+ this.elementLabel= elementLabel;
+ this.flags= flags;
+ this.expr= expr;
+ }
+
+ public TracepointState(final int type,
+ final String filePath, final long id) {
+ if (type != TYPE_DELETED) {
+ throw new IllegalArgumentException("type= " + type); //$NON-NLS-1$
+ }
+ this.type= type;
+ this.filePath= filePath;
+ this.id= id;
+ }
+
+ private TracepointState() {
+ }
+
+ public TracepointState(final RJIO io) throws IOException {
+ this.type= io.readInt();
+ this.id= io.readLong();
+ this.filePath= io.readString();
+ if (this.type == TYPE_DELETED) {
+ return;
+ }
+ this.elementId= io.readString();
+ this.index= io.readIntArray();
+ this.elementLabel= io.readString();
+ this.flags= io.readInt();
+ this.expr= io.readString();
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.type);
+ io.writeLong(this.id);
+ io.writeString(this.filePath);
+ if (this.type == TYPE_DELETED) {
+ return;
+ }
+ io.writeString(this.elementId);
+ io.writeIntArray(this.index, this.index.length);
+ io.writeString(this.elementLabel);
+ io.writeInt(this.flags);
+ io.writeString(this.expr);
+ }
+
+ @Override
+ public TracepointState clone() {
+ return new TracepointState(this.type,
+ this.filePath, this.id, this.elementId, this.index,
+ this.elementLabel, this.flags, this.expr );
+ }
+
+
+ @Override
+ public int getType() {
+ return this.type;
+ }
+
+ public String getFilePath() {
+ return this.filePath;
+ }
+
+ public long getId() {
+ return this.id;
+ }
+
+ public String getElementId() {
+ return this.elementId;
+ }
+
+ public int[] getIndex() {
+ return this.index;
+ }
+
+ public boolean isEnabled() {
+ return ((this.flags & FLAG_ENABLED) != 0);
+ }
+
+ public String getElementLabel() {
+ return this.elementLabel;
+ }
+
+ public int getFlags() {
+ return this.flags;
+ }
+
+ public String getExpr() {
+ return this.expr;
+ }
+
+
+ @Override
+ public int compareTo(final TracepointState other) {
+ { final int diff= this.filePath.compareTo(other.filePath);
+ if (diff != 0) {
+ return diff;
+ }
+ }
+ if (this.elementId != null) {
+ if (other.elementId != null) {
+ final int diff= this.elementId.compareTo(other.elementId);
+ if (diff != 0) {
+ return diff;
+ }
+ }
+ else {
+ return 0x1000;
+ }
+ }
+ else if (other.elementId != null) {
+ return -0x1000;
+ }
+ return (this.id < other.id) ? -0x1 : 0x1;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (this.filePath.hashCode() * this.id);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof TracepointState)) {
+ return false;
+ }
+ final TracepointState other= (TracepointState) obj;
+ return (this.id == other.id
+ && this.filePath.equals(other.filePath) );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointStatesUpdate.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointStatesUpdate.java
new file mode 100644
index 0000000..b9842c8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/dbg/TracepointStatesUpdate.java
@@ -0,0 +1,61 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.dbg;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+public class TracepointStatesUpdate implements RJIOExternalizable {
+
+
+ private final static int RESET= 0x00000001;
+
+
+ private final List<TracepointState> states;
+
+ private final int properties;
+
+
+ public TracepointStatesUpdate(final List<TracepointState> states,
+ final boolean reset) {
+ this.states= states;
+ this.properties= (reset) ? RESET : 0;
+ }
+
+ public TracepointStatesUpdate(final RJIO io) throws IOException {
+ this.properties= io.readInt();
+ this.states= TracepointState.readList(io);
+ }
+
+ @Override
+ public void writeExternal(final RJIO io) throws IOException {
+ io.writeInt(this.properties);
+ TracepointState.writeList(this.states, io);
+ }
+
+
+ public boolean getReset() {
+ return ((this.properties & RESET) != 0);
+ }
+
+ public List<TracepointState> getStates() {
+ return this.states;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/Coord.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/Coord.java
new file mode 100644
index 0000000..db08267
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/Coord.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+import java.io.IOException;
+
+import org.eclipse.statet.rj.data.RJIO;
+import org.eclipse.statet.rj.data.RJIOExternalizable;
+
+
+/**
+ * Single R graphic coordinate
+ */
+public class Coord implements RJIOExternalizable {
+
+
+ private double x;
+ private double y;
+
+
+ public Coord(final double x, final double y) {
+ this.x= x;
+ this.y= y;
+ }
+
+ public Coord(final RJIO in) throws IOException {
+ this.x= in.readDouble();
+ this.y= in.readDouble();
+ }
+
+
+ @Override
+ public void writeExternal(final RJIO out) throws IOException {
+ out.writeDouble(this.x);
+ out.writeDouble(this.y);
+ }
+
+
+ public void setX(final double x) {
+ this.x= x;
+ }
+
+ public void setY(final double y) {
+ this.y= y;
+ }
+
+ public double getX() {
+ return this.x;
+ }
+
+ public double getY() {
+ return this.y;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/GraOp.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/GraOp.java
new file mode 100644
index 0000000..bc3c99a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/GraOp.java
@@ -0,0 +1,32 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+
+/**
+ * Graphic operations
+ */
+public interface GraOp {
+
+
+ // -- C2S sync
+ byte OP_CLOSE= 0x01;
+
+ byte OP_REQUEST_RESIZE= 0x08;
+
+ byte OP_CONVERT_DEV2USER= 0x10;
+ byte OP_CONVERT_USER2DEV= 0x11;
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphic.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphic.java
new file mode 100644
index 0000000..29f402d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphic.java
@@ -0,0 +1,243 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+import org.eclipse.statet.rj.server.GDCmdItem;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.RJ;
+
+
+public final class RjsGraphic {
+
+
+ public static final int STATE_CLOSED= -1;
+ public static final int STATE_OPENED= 1;
+ public static final int STATE_PAGED= 2;
+
+
+ private final RJ rj;
+ private final RjsGraphicManager manager;
+
+ private final byte slot;
+
+ private int devId;
+ int state;
+
+ private int cachedStrWidthChar;
+ private double[] cachedStrWidthCharResult;
+ private String cachedStrWidthStr;
+ private double[] cachedStrWidthStrResult;
+
+
+ public RjsGraphic() {
+ this.rj= RJ.getInstance();
+ this.manager= this.rj.getGraphicManager();
+ this.slot= this.rj.getCurrentSlot();
+ }
+
+
+ public byte getSlot() {
+ return this.slot;
+ }
+
+ public int getDevId() {
+ return this.devId;
+ }
+
+ public int getState() {
+ return this.state;
+ }
+
+
+ public void initPage(final int devId, final int state, final double width, final double height,
+ final int canvasColor, final boolean isActive) {
+ if (this.devId != devId || this.state < STATE_OPENED) {
+ this.devId= devId;
+ this.manager.registerGraphic(this);
+ }
+ this.state= state;
+
+ this.cachedStrWidthChar= -1;
+ this.cachedStrWidthStr= null;
+
+ this.rj.sendMainCmd(new GDCmdItem.CInit(
+ this.devId, width, height, canvasColor, isActive, this.slot ));
+ }
+
+ public void close() {
+ this.state= STATE_CLOSED;
+ this.manager.unregisterGraphic(this);
+ this.rj.sendMainCmd(new GDCmdItem.CCloseDevice(
+ this.devId, this.slot ));
+ }
+
+ public void setMode(final int mode) {
+ if (this.state > 0) {
+ this.rj.sendMainCmd(new GDCmdItem.CSetMode(
+ this.devId, mode, this.slot ));
+ }
+ }
+
+ public void activate() {
+ if (this.state > 0) {
+ this.manager.activate(this);
+ }
+ }
+
+ public void deactivate() {
+ if (this.state > 0) {
+ this.manager.deactivate(this);
+ }
+ }
+
+ public boolean newPageConfirm() {
+ return false;
+ }
+
+ public double[] newPagePPI() {
+ return (double[]) this.rj.getClientProperty(this.slot, "display.ppi");
+ }
+
+ public double[] newPageSize() {
+ final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetSize(
+ this.devId, this.slot ));
+ return (answer instanceof GDCmdItem && answer.isOK() ) ?
+ ((GDCmdItem) answer).getDoubleData() : null;
+ }
+
+
+ public void setColor(final int color) {
+ this.rj.sendMainCmd(new GDCmdItem.SetColor(
+ this.devId, color, this.slot ));
+ }
+
+ public void setFill(final int color) {
+ this.rj.sendMainCmd(new GDCmdItem.SetFill(
+ this.devId, color, this.slot ));
+ }
+
+ public void setLine(final int lty, final float lwd,
+ final byte cap, final byte join, final float joinMiterLimit) {
+ this.rj.sendMainCmd(new GDCmdItem.SetLine(
+ this.devId, lty, lwd, cap, join, joinMiterLimit, this.slot ));
+ }
+
+ public void setClip(final double x0, final double x1, final double y0, final double y1) {
+ this.rj.sendMainCmd(new GDCmdItem.SetClip(
+ this.devId, x0, y0, x1, y1, this.slot ));
+ }
+
+ public void drawLine(final double x0, final double y0, final double x1, final double y1) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawLine(
+ this.devId, x0, y0, x1, y1, this.slot ));
+ }
+
+ public void drawRect(final double x0, final double y0, final double x1, final double y1) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawRect(
+ this.devId, x0, y0, x1, y1, this.slot ));
+ }
+
+ public void drawPolyline(final double[] x, final double[] y) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawPolyline(
+ this.devId, x, y, this.slot ));
+ }
+
+ public void drawPolygon(final double[] x, final double[] y) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawPolygon(
+ this.devId, x, y, this.slot ));
+ }
+
+ public void drawPath(final int[] n, final double[] x, final double[] y, final int mode) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawPath(
+ this.devId, n, x, y, mode, this.slot ));
+ }
+
+ public void drawCircle(final double x, final double y, final double r) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawCircle(
+ this.devId, x, y, r, this.slot ));
+ }
+
+
+ public void setFont(final String family, final int face, final float pointSize,
+ final float lineheight) {
+ this.rj.sendMainCmd(new GDCmdItem.SetFont(
+ this.devId, family, face, pointSize, lineheight, this.slot ));
+
+ this.cachedStrWidthChar= -1;
+ this.cachedStrWidthStr= null;
+ }
+
+ public double[] getStrWidth(final String str) {
+ if (str.length() == 1) {
+ final int ch= str.charAt(0);
+ if (ch == this.cachedStrWidthChar) {
+ return this.cachedStrWidthCharResult;
+ }
+ final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetStrWidth(
+ this.devId, str, this.slot ));
+ this.cachedStrWidthCharResult= (answer instanceof GDCmdItem && answer.isOK() ) ?
+ ((GDCmdItem) answer).getDoubleData() : null;
+ this.cachedStrWidthChar= ch;
+ return this.cachedStrWidthCharResult;
+ }
+ else {
+ if (str.equals(this.cachedStrWidthStr)) {
+ return this.cachedStrWidthStrResult;
+ }
+ final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetStrWidth(
+ this.devId, str, this.slot ));
+ this.cachedStrWidthStrResult= (answer instanceof GDCmdItem && answer.isOK() ) ?
+ ((GDCmdItem) answer).getDoubleData() : null;
+ this.cachedStrWidthStr= str;
+ return this.cachedStrWidthStrResult;
+ }
+ }
+
+ public double[] getMetricInfo(final int ch) {
+ final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.CGetFontMetric(
+ this.devId, ch, this.slot ));
+ return (answer instanceof GDCmdItem && answer.isOK() ) ?
+ ((GDCmdItem) answer).getDoubleData() : null;
+ }
+
+ public void drawText(final String str, final double x, final double y, final double rDeg, final double hAdj) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawText(
+ this.devId, str, x, y, rDeg, hAdj, this.slot ));
+ }
+
+
+ public void drawRaster(final byte[] imgData, final boolean imgAlpha, final int imgW, final int imgH,
+ final double x, final double y, final double w, final double h,
+ final double rDeg, final boolean interpolate) {
+ this.rj.sendMainCmd(new GDCmdItem.DrawRaster(this.devId, imgData, imgAlpha, imgW, imgH, x, y, w, h,
+ rDeg, interpolate, this.slot ));
+ }
+
+ public byte[] capture(final int[] dim) {
+ final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.Capture(this.devId,
+ dim[0], dim[1], this.slot ));
+ return (answer instanceof GDCmdItem && answer.isOK() ) ?
+ ((GDCmdItem) answer).getByteData() : null;
+ }
+
+
+ public double[] execLocator() {
+ final MainCmdItem answer= this.rj.sendMainCmd(new GDCmdItem.Locator(
+ this.devId, this.slot ));
+ return (answer instanceof GDCmdItem && answer.isOK() ) ?
+ ((GDCmdItem) answer).getDoubleData() : null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphicManager.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphicManager.java
new file mode 100644
index 0000000..b167f5a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/gr/RjsGraphicManager.java
@@ -0,0 +1,134 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.gr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.statet.rj.server.GDCmdItem;
+import org.eclipse.statet.rj.server.RJ;
+
+
+public class RjsGraphicManager {
+
+
+ private static final Comparator<RjsGraphic> GRAPHIC_COMPARATOR= new Comparator<RjsGraphic>() {
+
+ @Override
+ public int compare(final RjsGraphic o1, final RjsGraphic o2) {
+ return o1.getDevId() - o2.getDevId();
+ }
+
+ };
+
+
+ private final List<RjsGraphic> graphicList= new ArrayList<>();
+
+ private RjsGraphic activeGraphic;
+
+ private int inOperation;
+ private RjsGraphic inOperationActiveGraphic;
+
+ private final RJ rj;
+
+
+ public RjsGraphicManager(final RJ rj) {
+ this.rj= rj;
+ }
+
+
+ void registerGraphic(final RjsGraphic graphic) {
+ final int idx= Collections.binarySearch(this.graphicList, graphic, GRAPHIC_COMPARATOR);
+ if (idx >= 0) {
+ this.graphicList.set(idx, graphic);
+ }
+ else {
+ this.graphicList.add(-(idx+1), graphic);
+ }
+ }
+
+ void unregisterGraphic(final RjsGraphic graphic) {
+ if (this.activeGraphic == graphic) {
+ this.activeGraphic= null;
+ }
+ if (this.inOperationActiveGraphic == graphic) {
+ this.inOperationActiveGraphic= null;
+ }
+ this.graphicList.remove(graphic);
+ }
+
+ void activate(final RjsGraphic graphic) {
+ this.activeGraphic= graphic;
+ if (this.inOperation == 0) {
+ this.rj.sendMainCmd(new GDCmdItem.CSetActiveOn(
+ graphic.getDevId(), graphic.getSlot() ));
+ }
+ }
+
+ void deactivate(final RjsGraphic graphic) {
+ if (this.activeGraphic == graphic) {
+ this.activeGraphic= null;
+ }
+ if (this.inOperation == 0) {
+ this.rj.sendMainCmd(new GDCmdItem.CSetActiveOff(
+ graphic.getDevId(), graphic.getSlot() ));
+ }
+ }
+
+
+ public RjsGraphic getGraphic(final int devId) {
+ for (int i= 0; i < this.graphicList.size(); i++) {
+ final RjsGraphic graphic= this.graphicList.get(i);
+ if (graphic.getDevId() < devId) {
+ continue;
+ }
+ else if (graphic.getDevId() > devId) {
+ break;
+ }
+ else {
+ return graphic;
+ }
+ }
+ return null;
+ }
+
+
+ protected void beginOperation() {
+ if (this.inOperation == 0) {
+ this.inOperationActiveGraphic= this.activeGraphic;
+ }
+ this.inOperation++;
+ }
+
+ protected void endOperation() {
+ this.inOperation--;
+ if (this.inOperation == 0) {
+ if (this.inOperationActiveGraphic != this.activeGraphic) {
+ if (this.inOperationActiveGraphic != null) {
+ this.rj.sendMainCmd(new GDCmdItem.CSetActiveOff(
+ this.inOperationActiveGraphic.getDevId(), this.inOperationActiveGraphic.getSlot() ));
+ }
+ if (this.activeGraphic != null) {
+ this.rj.sendMainCmd(new GDCmdItem.CSetActiveOn(
+ this.activeGraphic.getDevId(), this.activeGraphic.getSlot() ));
+ }
+ }
+ this.inOperationActiveGraphic= null;
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/CliUtil.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/CliUtil.java
new file mode 100644
index 0000000..b16d89b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/CliUtil.java
@@ -0,0 +1,135 @@
+/*=============================================================================#
+ # Copyright (c) 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class CliUtil {
+
+
+ public static final int EXIT_ARGS_MISSING= ServerControl.EXIT_ARGS | 1;
+ public static final int EXIT_ARGS_INVALID= ServerControl.EXIT_ARGS | 2;
+
+
+ private final String command;
+
+ private final String name;
+
+ private final Map<String, String> options;
+
+
+ public CliUtil(final String[] args) {
+ int idx= 0;
+ if (args.length <= idx || args[idx].startsWith("-")) {
+ invalidArgs("Missing server command");
+ }
+ this.command= args[idx++];
+ if (!isValidCommand(this.command)) {
+ invalidArgs("Invalid server command '" + this.command + "'");
+ }
+
+ if (isNameCommand(this.command) && args.length <= idx) {
+ invalidArgs("Missing server name");
+ }
+ this.name= args[idx++];
+
+ this.options= new HashMap<>();
+ while (idx < args.length) {
+ final String arg= args[idx++];
+ if (arg.length() == 0 || arg.charAt(0) != '-') {
+ continue;
+ }
+ final int split= arg.indexOf('=');
+ if (split > 1) {
+ this.options.put(arg.substring(1, split), arg.substring(split + 1));
+ }
+ else if (split < 0) {
+ this.options.put(arg.substring(1), null);
+ }
+ }
+
+ checkGlobalOptions();
+ }
+
+
+ protected boolean isValidCommand(final String command) {
+ return (command.equals("start") || command.equals("clean"));
+ }
+
+ protected boolean isNameCommand(final String command) {
+ return true;
+ }
+
+ protected void checkGlobalOptions() {
+ if (Boolean.parseBoolean(System.getProperty("org.eclipse.statet.rj.verbose"))
+ || Boolean.parseBoolean(System.getProperty("org.eclipse.statet.rj.debug")) ) {
+ this.options.put("verbose", "true");
+ }
+ if (this.options.containsKey("log")) {
+ try {
+ final String fileName= this.options.get("log");
+ final File file= new File((fileName != null) ? fileName : "out.log");
+ final PrintStream stream= new PrintStream(file);
+ stream.println("(RServi) R node log");
+ stream.flush();
+ System.setOut(stream);
+ System.setErr(stream);
+ }
+ catch (final Throwable e) {
+ e.printStackTrace();
+ RMIServerControl.exit(ServerControl.EXIT_INIT_LOGGING_ERROR);
+ }
+ }
+ }
+
+
+ public String getCommand() {
+ return this.command;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public Map<String, String> getOptions() {
+ return this.options;
+ }
+
+
+ public void invalidArgs(final String message) {
+ System.err.println(message);
+ printHelp();
+ RMIServerControl.exit(EXIT_ARGS_INVALID);
+ }
+
+ public void printHelp() {
+ System.out.println("= Usage of RJserver command line control ================");
+ System.out.println("commands:");
+ System.out.println(" start <name> adds server to RMIregistry");
+ System.out.println(" clean <name> stops server/remove from RMIregistry");
+ System.out.println("name: unique name in RMIregistry");
+ System.out.println("options:");
+ System.out.println(" -verbose verbose logging");
+ System.out.println(" -server class name of server implementation");
+ System.out.println(" -plugins=<..> list of plugins");
+ System.out.println(" -auth=<..> authetification method");
+ }
+
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIAddress.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIAddress.java
new file mode 100644
index 0000000..b9455f0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIAddress.java
@@ -0,0 +1,309 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.registry.Registry;
+
+
+/**
+ * Address for RMI naming
+ */
+class RMIAddress {
+
+
+ public static final InetAddress LOOPBACK;
+
+ public static void validate(final String address) throws MalformedURLException {
+ try {
+ new RMIAddress(address, false);
+ }
+ catch (final UnknownHostException e) {
+ }
+ }
+
+
+ private static String checkChars(final String s) throws MalformedURLException {
+ for (int i= 0; i < s.length(); i++) {
+ final char c= s.charAt(i);
+ if (c == '?' || c == '#' || c == '[' || c == ']' || c == '@'
+ || c == '!' || c == '$' || c == '&' || c == '\'' || c == '(' || c == ')'
+ || c == '*' || c == '+' || c == ',' || c == ';' || c == '='
+ || c == '"' || c == '\\') {
+ throw new MalformedURLException("Character '"+c+"' is not allowed.");
+ }
+ }
+ return s;
+ }
+
+ private static int checkPort(final String port) throws MalformedURLException {
+ final int portNum;
+ try {
+ portNum= (port != null) ? Integer.parseInt(port) : Registry.REGISTRY_PORT;
+ }
+ catch (final NumberFormatException e) {
+ throw new MalformedURLException("Invalid port, " + e.getMessage());
+ }
+ return checkPort(portNum);
+ }
+
+ private static int checkPort(final int portNum) throws MalformedURLException {
+ if (portNum < 0 || portNum > 65535) {
+ throw new MalformedURLException("Invalid port, " + "Value must be in range 0-65535");
+ }
+ return portNum;
+ }
+
+ private static String build(final String host, final int portNum, final String name) {
+ final StringBuilder sb= new StringBuilder("//"); //$NON-NLS-1$
+ if (host != null) {
+ sb.append(host);
+ }
+ sb.append(':');
+ if (portNum >= 0) {
+ sb.append(Integer.toString(portNum));
+ }
+ sb.append('/');
+ if (name != null) {
+ sb.append(name);
+ }
+ return sb.toString();
+ }
+
+
+ static {
+ InetAddress loopbackAddress;
+ try {
+ loopbackAddress= InetAddress.getByAddress("localhost", new byte[] { 127, 0, 0, 1 }); //$NON-NLS-1$
+ }
+ catch (final UnknownHostException e) {
+ loopbackAddress= null;
+ e.printStackTrace();
+ }
+ LOOPBACK= loopbackAddress;
+ }
+
+
+ private final String host;
+ private InetAddress hostAddress;
+ private final String port;
+ private final int portNum;
+ private final boolean ssl;
+ private final String path;
+
+ private String address;
+ private String ser;
+
+
+ public RMIAddress(final String address) throws UnknownHostException, MalformedURLException {
+ this(address, true);
+ }
+
+ public RMIAddress(final String host, final int portNum, final String name) throws UnknownHostException, MalformedURLException {
+ this(build(host, portNum, name), true);
+ }
+
+ public RMIAddress(final InetAddress address, final int port, final String name)
+ throws MalformedURLException {
+ this(address.getHostAddress(), address, Integer.toString(port), checkPort(port), false,
+ (name != null) ? checkChars(name) : "");
+ }
+
+ public RMIAddress(final InetAddress address, final int port, final boolean ssl, final String name)
+ throws MalformedURLException {
+ this(address.getHostAddress(), address, Integer.toString(port), checkPort(port), ssl,
+ (name != null) ? checkChars(name) : "");
+ }
+
+ public RMIAddress(final RMIAddress registry, final String name) throws MalformedURLException {
+ this(registry.host, registry.hostAddress, registry.port, registry.portNum, registry.ssl,
+ (name != null) ? checkChars(name) : "");
+ }
+
+ private RMIAddress(String address, final boolean resolve) throws UnknownHostException, MalformedURLException {
+ address= checkChars(address);
+
+ if (address.startsWith("ssl:")) { //$NON-NLS-1$
+ address= address.substring(4);
+ this.ssl= true;
+ }
+ else {
+ this.ssl= false;
+ }
+ if (address.startsWith("rmi:")) { //$NON-NLS-1$
+ address= address.substring(4);
+ }
+ if (!address.startsWith("//")) { //$NON-NLS-1$
+ address= "//"+address; //$NON-NLS-1$
+ }
+
+ final int idxPort= address.indexOf(':', 2);
+ final int idxPath= address.indexOf('/', 2);
+ if (idxPort > 0) {
+ if (idxPath <= idxPort) {
+ throw new IllegalArgumentException();
+ }
+ this.host= (2 < idxPort) ? address.substring(2, idxPort) : null;
+ this.port= (idxPort+1 < idxPath) ? address.substring(idxPort+1, idxPath) : null;
+ this.path= address.substring(idxPath+1);
+ }
+ else if (idxPath > 0){
+ this.host= (2 < idxPath) ? address.substring(2, idxPath) : null;
+ this.port= null;
+ this.path= address.substring(idxPath+1);
+ }
+ else {
+ this.host= null;
+ this.port= null;
+ this.path= address.substring(2);
+ }
+ try {
+ this.portNum= checkPort(this.port);
+ }
+ catch (final NumberFormatException e) {
+ throw new MalformedURLException("Invalid port, " + e.getLocalizedMessage());
+ }
+ if (resolve) {
+ this.hostAddress= (this.host != null) ? InetAddress.getByName(this.host) : LOOPBACK;
+ }
+ }
+
+ private RMIAddress(final String host, final InetAddress hostAddress, final String port,
+ final int portNum, final boolean ssl, final String path) {
+ this.host= host;
+ this.hostAddress= hostAddress;
+ this.port= port;
+ this.portNum= portNum;
+ this.ssl= ssl;
+ this.path= path;
+ }
+
+
+ /**
+ * @return the host as specified when creating the address
+ */
+ public String getHost() {
+ return (this.host != null) ? this.host : this.hostAddress.getHostAddress();
+ }
+
+ public InetAddress getHostAddress() {
+ return this.hostAddress;
+ }
+
+ public boolean isLocalHost() {
+ if (this.hostAddress.isLoopbackAddress()) {
+ return true;
+ }
+ try {
+ final InetAddress localhost= InetAddress.getLocalHost();
+ if (this.hostAddress.equals(localhost)) {
+ return true;
+ }
+ }
+ catch (final UnknownHostException e) {}
+ catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ }
+
+ return false;
+ }
+
+ /**
+ * @return the port
+ */
+ public String getPort() {
+ return this.port;
+ }
+
+ public int getPortNum() {
+ return this.portNum;
+ }
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return this.path;
+ }
+
+ /**
+ * Standard string presentation to use for rmi
+ * @return
+ */
+ public String getAddress() {
+ if (this.address == null) {
+ final StringBuilder sb= new StringBuilder(32);
+ sb.append("rmi://"); //$NON-NLS-1$
+ if (this.host != null) {
+ sb.append(this.host);
+ }
+ if (this.portNum != Registry.REGISTRY_PORT) {
+ sb.append(':');
+ sb.append(this.port);
+ }
+ sb.append('/');
+ sb.append(this.path);
+ this.address= sb.toString();
+ }
+ return this.address;
+ }
+
+ public RMIAddress getRegistryAddress() {
+ return new RMIAddress(this.host, this.hostAddress, this.port, this.portNum, this.ssl, "");
+ }
+
+ /**
+ *
+ * @return if SSL is enabled
+ *
+ * @since 1.4
+ */
+ public boolean isSSL() {
+ return this.ssl;
+ }
+
+
+ @Override
+ public String toString() {
+ if (this.ser == null) {
+ final String address= getAddress();
+ if (this.ssl) {
+ this.ser= "ssl:" + address;
+ }
+ else {
+ this.ser= address;
+ }
+ }
+ return this.ser;
+ }
+
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof RMIAddress)) {
+ return false;
+ }
+ final RMIAddress other= (RMIAddress) obj;
+ return (this.hostAddress.equals(other.hostAddress)
+ && this.portNum == other.portNum
+ && this.ssl == other.ssl
+ && this.path.equals(other.path) );
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIServerControl.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIServerControl.java
new file mode 100644
index 0000000..3c33c5d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/RMIServerControl.java
@@ -0,0 +1,410 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.io.StreamCorruptedException;
+import java.lang.reflect.Constructor;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.UnmarshalException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.text.MessageFormat;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srv.engine.SrvEngineServer;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+public class RMIServerControl extends ServerControl {
+
+
+ public static final int EXIT_REGISTRY_PROBLEM= 150;
+ public static final int EXIT_REGISTRY_INVALID_ADDRESS= 151;
+ public static final int EXIT_REGISTRY_CONNECTING_ERROR= 151;
+ public static final int EXIT_REGISTRY_SERVER_STILL_ACTIVE= 152;
+ public static final int EXIT_REGISTRY_ALREADY_BOUND= 153;
+ public static final int EXIT_REGISTRY_CLEAN_FAILED= 155;
+ public static final int EXIT_REGISTRY_BIND_FAILED= 156;
+ public static final int EXIT_START_RENGINE_ERROR= 161;
+
+
+ protected final String logPrefix;
+
+ private final RMIAddress rmiAddress;
+
+ private Server mainServer;
+ private boolean isPublished;
+
+
+ public RMIServerControl(final String name, final Map<String, String> options) {
+ super(options);
+ final int lastSegment= name.lastIndexOf('/');
+ this.logPrefix= "[Control:"+((lastSegment >= 0) ? name.substring(lastSegment+1) : name)+"]";
+
+ { RMIAddress address= null;
+ Exception error= null;
+ try {
+ address= new RMIAddress(name);
+ }
+ catch (final MalformedURLException e) {
+ error= e;
+ }
+ catch (final UnknownHostException e) {
+ error= e;
+ }
+ if (address == null) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} the server address ''{1}'' is invalid.");
+ record.setParameters(new Object[] { this.logPrefix, name });
+ record.setThrown(error);
+ LOGGER.log(record);
+
+ exit(EXIT_REGISTRY_INVALID_ADDRESS);
+ }
+ this.rmiAddress= address;
+ }
+
+ if (options != null) {
+ if (options.containsKey("verbose")) {
+ initVerbose();
+ }
+ }
+ }
+
+
+ public SrvEngineServer initServer() {
+ LOGGER.log(Level.INFO, "{0} Initializing R engine server...", this.logPrefix);
+ try {
+ final String serverType= getOptions().get("server"); //$NON-NLS-1$
+ if (serverType == null) {
+ final ServerAuthMethod auth= createServerAuth(getOptions().remove("auth")); //$NON-NLS-1$
+ return new SrvEngineServer(this, auth);
+ }
+ else {
+ final Class<SrvEngineServer> serverClass= (Class<SrvEngineServer>) Class.forName(serverType);
+ final Constructor<SrvEngineServer> constructor= serverClass.getConstructor(RMIServerControl.class);
+ return constructor.newInstance(this);
+ }
+ }
+ catch (final Exception e) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} Failed to initialize R engine server.");
+ record.setParameters(new Object[] { this.logPrefix });
+ record.setThrown(e);
+ LOGGER.log(record);
+
+ exit(EXIT_INIT_RENGINE_ERROR);
+ throw new RuntimeException();
+ }
+ }
+
+ protected Registry getRegistry() throws RemoteException {
+ RMIClientSocketFactory csf= null;
+ if (this.rmiAddress.isSSL()) {
+ csf= new SslRMIClientSocketFactory();
+ }
+ return LocateRegistry.getRegistry(this.rmiAddress.getHost(), this.rmiAddress.getPortNum(), csf);
+ }
+
+ public String getName() {
+ return this.rmiAddress.getName();
+ }
+
+ public Remote exportObject(final Remote obj) throws RemoteException {
+ RMIClientSocketFactory csf= RjsComConfig.getRMIServerClientSocketFactory();
+ RMIServerSocketFactory ssf= null;
+ if (this.rmiAddress.isSSL()) {
+ csf= new SslRMIClientSocketFactory();
+ ssf= new SslRMIServerSocketFactory(null, null, true);
+ }
+ return UnicastRemoteObject.exportObject(obj, 0, csf, ssf);
+ }
+
+
+ protected void publishServer(final SrvEngineServer server) {
+ try {
+ System.setSecurityManager(new SecurityManager());
+ final Registry registry= getRegistry();
+ Server stub= (Server) exportObject(server);
+ this.mainServer= server;
+ try {
+ registry.bind(getName(), stub);
+ }
+ catch (final AlreadyBoundException boundException) {
+ if (server.getConfigUnbindOnStartup() && unbindDead() == 0) {
+ registry.bind(getName(), stub);
+ }
+ else {
+ throw boundException;
+ }
+ }
+ catch (final RemoteException remoteException) {
+ if (remoteException.getCause() instanceof UnmarshalException
+ && remoteException.getCause().getCause() instanceof StreamCorruptedException
+ && RjsComConfig.getRMIServerClientSocketFactory() != null) {
+ stub= null;
+ try {
+ UnicastRemoteObject.unexportObject(server, true);
+ stub= (Server) UnicastRemoteObject.exportObject(server, 0, null, null);
+ }
+ catch (final Exception testException) {}
+ if (stub != null) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} caught StreamCorruptedException \nretrying without socket factory to reveal other potential problems.");
+ record.setParameters(new Object[] { this.logPrefix });
+ record.setThrown(remoteException);
+ LOGGER.log(record);
+ registry.bind(getName(), stub);
+ registry.unbind(getName());
+ throw new RjException("No error without socket factory, use the Java property 'org.eclipse.statet.rj.rmi.disableSocketFactory' to disable the factory.");
+ }
+ }
+ throw remoteException;
+ }
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ checkCleanup();
+ }
+ });
+ this.isPublished= true;
+ LOGGER.log(Level.INFO, "{0} server is added to registry - ready.", this.logPrefix);
+
+ return;
+ }
+ catch (final Exception e) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} init server failed.");
+ record.setParameters(new Object[] { this.logPrefix });
+ record.setThrown(e);
+ LOGGER.log(record);
+
+ if (e instanceof AlreadyBoundException) {
+ exit(EXIT_REGISTRY_ALREADY_BOUND);
+ }
+
+ checkCleanup();
+ exit(EXIT_REGISTRY_BIND_FAILED);
+ }
+ }
+
+ /**
+ * @return <code>true</code> if it was removed, otherwise <code>false</code>
+ */
+ protected int unbindDead() {
+ Remote remote;
+ try {
+ final Registry registry= getRegistry();
+ remote= registry.lookup(getName());
+ }
+ catch (final NotBoundException lookupException) {
+ return 0;
+ }
+ catch (final RemoteException lookupException) {
+ return EXIT_REGISTRY_CONNECTING_ERROR;
+ }
+ if (!(remote instanceof Server)) {
+ return 2;
+ }
+ try {
+ ((Server) remote).getInfo();
+ return EXIT_REGISTRY_SERVER_STILL_ACTIVE;
+ }
+ catch (final RemoteException deadException) {
+ try {
+ final Registry registry= getRegistry();
+ registry.unbind(getName());
+ LOGGER.log(Level.INFO,
+ "{0} dead server removed from registry.",
+ this.logPrefix);
+ return 0;
+ }
+ catch (final Exception unbindException) {
+ return EXIT_REGISTRY_CLEAN_FAILED;
+ }
+ }
+ }
+
+ public void checkCleanup() {
+ if (this.mainServer == null) {
+ return;
+ }
+ LOGGER.log(Level.INFO, "{0} cleaning up server resources...", this.logPrefix);
+ try {
+ final Registry registry= getRegistry();
+ registry.unbind(getName());
+ }
+ catch (final NotBoundException e) {
+ // ok
+ }
+ catch (final Exception e) {
+ final LogRecord record= new LogRecord(this.isPublished ? Level.SEVERE : Level.INFO,
+ "{0} cleaning up server resources failed.");
+ record.setParameters(new Object[] { this.logPrefix });
+ record.setThrown(e);
+ LOGGER.log(record);
+ }
+ try {
+ UnicastRemoteObject.unexportObject(this.mainServer, true);
+ }
+ catch (final NoSuchObjectException e) {
+ // ok
+ }
+ this.mainServer= null;
+ System.gc();
+ }
+
+ public ServerAuthMethod createServerAuth(final String config) throws RjException {
+ // auth
+ final String authType;
+ final String authConfig;
+ try {
+ final String[] auth= ServerUtils.getArgSubValue(config);
+ if (auth[0].length() == 0) {
+ throw new RjInvalidConfigurationException("Missing 'auth' configuration");
+ }
+ else if (auth[0].equals("none")) {
+ authType= "org.eclipse.statet.rj.server.srvext.auth.NoAuthMethod";
+ }
+ else if (auth[0].equals("name-pass")) {
+ authType= "org.eclipse.statet.rj.server.srvext.auth.SimpleNamePassAuthMethod";
+ }
+ else if (auth[0].equals("fx")) {
+ authType= "org.eclipse.statet.rj.server.srvext.auth.FxAuthMethod";
+ }
+ else if (auth[0].equals("local-shaj")) {
+ authType= "org.eclipse.statet.rj.server.srvext.auth.LocalShajAuthMethod";
+ }
+ else {
+ authType= auth[0];
+ }
+ authConfig= auth[1];
+ }
+ catch (final Exception e) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} init authentication method failed.");
+ record.setParameters(new Object[] { this.logPrefix });
+ record.setThrown(e);
+ LOGGER.log(record);
+ throw new RjInvalidConfigurationException("Init authentication method failed.", e);
+ }
+ try {
+ final Class<ServerAuthMethod> authClazz= (Class<ServerAuthMethod>) Class.forName(authType);
+ final ServerAuthMethod authMethod= authClazz.newInstance();
+ authMethod.init(authConfig);
+ return authMethod;
+ }
+ catch (final Exception e) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} init authentication method ''{1}'' failed.");
+ record.setParameters(new Object[] { this.logPrefix, authType });
+ record.setThrown(e);
+ LOGGER.log(record);
+ throw new RjException(MessageFormat.format("Init authentication method failed ''{0}''.", authType), e);
+ }
+ }
+
+
+ public void start(final SrvEngineServer server) {
+ try {
+ server.start(new ServerRuntimePlugin() {
+
+ @Override
+ public String getSymbolicName() {
+ return "rmi";
+ }
+
+ @Override
+ public void rjIdle() throws Exception {
+ }
+
+ @Override
+ public void rjStop(final int state) throws Exception {
+ if (state == 0) {
+ try {
+ Thread.sleep(1000);
+ }
+ catch (final InterruptedException e) {
+ }
+ }
+ checkCleanup();
+ };
+
+ });
+ }
+ catch (final Exception e) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} Starting R engine server failed.");
+ record.setParameters(new Object[] { this.logPrefix });
+ record.setThrown(e);
+ LOGGER.log(record);
+
+ exit(EXIT_INIT_RENGINE_ERROR | 8);
+ }
+
+ publishServer(server);
+ }
+
+ public void clean() {
+ final int dead= unbindDead();
+ if (dead == 0) {
+ exit(0);
+ return;
+ }
+ if (dead == EXIT_REGISTRY_SERVER_STILL_ACTIVE && !getOptions().containsKey("force")) {
+ exit(EXIT_REGISTRY_SERVER_STILL_ACTIVE);
+ }
+ try {
+ final Registry registry= getRegistry();
+ registry.unbind(getName());
+ LOGGER.log(Level.INFO,
+ "{0} server removed from registry.",
+ this.logPrefix);
+ }
+ catch (final NotBoundException e) {
+ exit(0);
+ }
+ catch (final RemoteException e) {
+ final LogRecord record= new LogRecord(Level.SEVERE,
+ "{0} removing server from registry failed.");
+ record.setParameters(new Object[] { this.logPrefix });
+ record.setThrown(e);
+ LOGGER.log(record);
+
+ exit(EXIT_REGISTRY_CONNECTING_ERROR);
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/ServerControl.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/ServerControl.java
new file mode 100644
index 0000000..623e6fa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/ServerControl.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv;
+
+import java.util.Map;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+public abstract class ServerControl {
+
+
+ public static final int EXIT_ARGS= 130;
+
+ public static final int EXIT_INIT= 140;
+
+ public static final int EXIT_INIT_LOGGING_ERROR= EXIT_INIT | 1;
+ public static final int EXIT_INIT_AUTHMETHOD_ERROR= EXIT_INIT | 3;
+ public static final int EXIT_INIT_RENGINE_ERROR= EXIT_INIT | 5;
+
+
+ private static boolean VERBOSE= false;
+ private static boolean VERBOSE_ON_ERROR= true;
+
+ public static void initVerbose() {
+ if (VERBOSE) {
+ return;
+ }
+ VERBOSE= true;
+
+ LOGGER.setLevel(Level.ALL); // default is Level.INFO
+// System.setProperty("java.rmi.server.logCalls", "true");
+// RemoteServer.setLog(System.err);
+ ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);
+
+ Logger logger= LOGGER;
+ SEARCH_CONSOLE: while (logger != null) {
+ for (final Handler handler : logger.getHandlers()) {
+ if (handler instanceof ConsoleHandler) {
+ handler.setLevel(Level.ALL);
+ break SEARCH_CONSOLE;
+ }
+ }
+ if (!logger.getUseParentHandlers()) {
+ break SEARCH_CONSOLE;
+ }
+ logger= logger.getParent();
+ }
+
+ final StringBuilder sb= new StringBuilder(256);
+
+ LOGGER.log(Level.CONFIG, "verbose mode enabled.");
+
+ sb.setLength(0);
+ sb.append("java properties:");
+ ServerUtils.prettyPrint(System.getProperties(), sb);
+ LOGGER.log(Level.CONFIG, sb.toString());
+
+ sb.setLength(0);
+ sb.append("env variables:");
+ ServerUtils.prettyPrint(System.getenv(), sb);
+ LOGGER.log(Level.CONFIG, sb.toString());
+ }
+
+ public static void exit(final int status) {
+ try {
+ if (status != 0 && VERBOSE_ON_ERROR) {
+ initVerbose();
+ }
+ System.err.flush();
+ System.out.flush();
+ }
+ finally {
+ System.exit(status);
+ }
+ }
+
+
+ protected static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server");
+
+
+
+ private final Map<String, String> options;
+
+
+ public ServerControl(final Map<String, String> options) {
+ this.options= options;
+ }
+
+
+ public Map<String, String> getOptions() {
+ return this.options;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/REngineImpl.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/REngineImpl.java
new file mode 100644
index 0000000..1afe71f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/REngineImpl.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import org.eclipse.statet.rj.server.REngine;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srvext.Client;
+
+
+public final class REngineImpl implements REngine {
+
+
+ private final Server publicServer;
+ private final SrvEngine srvEngine;
+ private final Client client;
+
+
+ public REngineImpl(final Server publicServer, final SrvEngine srvEngine, final Client client) {
+ this.publicServer= publicServer;
+ this.srvEngine= srvEngine;
+ this.client= client;
+ }
+
+
+ @Override
+ public Server getPublic() throws RemoteException {
+ return this.publicServer;
+ }
+
+ @Override
+ public Map<String, Object> getPlatformData() {
+ return this.srvEngine.getPlatformData();
+ }
+
+ @Override
+ public void setProperties(final Map<String, ? extends Object> properties) throws RemoteException {
+ this.srvEngine.setProperties(this.client, properties);
+ }
+
+ @Override
+ public void disconnect() throws RemoteException {
+ this.srvEngine.disconnect(this.client);
+ }
+
+ @Override
+ public RjsComObject runAsync(final RjsComObject com) throws RemoteException {
+ return this.srvEngine.runAsync(this.client, com);
+ }
+
+ @Override
+ public RjsComObject runMainLoop(final RjsComObject com) throws RemoteException {
+ return this.srvEngine.runMainLoop(this.client, com);
+ }
+
+ @Override
+ public boolean isClosed() throws RemoteException {
+ return (this.srvEngine.getCurrentClient() != this.client);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngine.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngine.java
new file mode 100644
index 0000000..d3deef1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngine.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import java.rmi.RemoteException;
+import java.util.Map;
+
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srv.RMIServerControl;
+import org.eclipse.statet.rj.server.srvext.Client;
+
+
+public interface SrvEngine {
+
+
+ void init(RMIServerControl control, Server publicServer, Map<String, Object> more) throws Exception;
+
+ int[] getVersion();
+
+ int getState();
+ Client getCurrentClient();
+ Map<String, Object> getPlatformData();
+
+ Object start(Client client, Map<String, ? extends Object> properties) throws RemoteException;
+ Object connect(Client client, Map<String, ? extends Object> properties) throws RemoteException;
+ void disconnect(Client client) throws RemoteException;
+ void setProperties(Client client, Map<String, ? extends Object> properties) throws RemoteException;
+
+ RjsComObject runMainLoop(Client client, RjsComObject com) throws RemoteException;
+ RjsComObject runAsync(Client client, RjsComObject com) throws RemoteException;
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEnginePluginExtension.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEnginePluginExtension.java
new file mode 100644
index 0000000..c8a4344
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEnginePluginExtension.java
@@ -0,0 +1,31 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+
+
+/**
+ * Interface for {@link Server} for local (none-exported) methods
+ */
+public interface SrvEnginePluginExtension {
+
+
+ public void addPlugin(ServerRuntimePlugin plugin);
+
+ public void removePlugin(ServerRuntimePlugin plugin);
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngineServer.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngineServer.java
new file mode 100644
index 0000000..7b26d51
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srv/engine/SrvEngineServer.java
@@ -0,0 +1,293 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srv.engine;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.MISSING_ANSWER_STATUS;
+
+import java.io.File;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.server.DataCmdItem;
+import org.eclipse.statet.rj.server.MainCmdC2SList;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.MainCmdS2CList;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.RjsException;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.ServerInfo;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.server.srv.RMIServerControl;
+import org.eclipse.statet.rj.server.srvext.Client;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+
+
+public class SrvEngineServer implements Server, RjsComConfig.PathResolver {
+
+
+ private static final List<Remote> clients= new CopyOnWriteArrayList<>();
+
+ public static void removeClient(final Remote remote) {
+ clients.add(remote);
+ }
+ public static void addClient(final Remote remote) {
+ clients.add(remote);
+ }
+ public static boolean isValid(final Remote remote) {
+ return clients.contains(remote);
+ }
+
+
+ protected static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server");
+
+ protected final RMIServerControl control;
+ protected SrvEngine srvEngine;
+
+ private final String[] userTypes;
+ private String[] userNames;
+ protected String workingDirectory;
+ protected long timestamp;
+
+ protected ServerAuthMethod authMethod;
+
+ protected final Client serverClient= new Client("rservi", "dummy", (byte) 1);
+ private final MainCmdC2SList serverC2SList= new MainCmdC2SList();
+
+
+ public SrvEngineServer(final RMIServerControl control, final ServerAuthMethod authMethod) {
+ if (control == null) {
+ throw new NullPointerException();
+ }
+
+ this.control= control;
+
+ this.userTypes= createUserTypes();
+ this.userNames= new String[this.userTypes.length];
+ setUserName(ServerInfo.USER_OWNER, System.getProperty("user.name"));
+
+ this.workingDirectory= System.getProperty("user.dir");
+
+ this.authMethod= authMethod;
+ }
+
+
+ protected String[] createUserTypes() {
+ return new String[] { ServerInfo.USER_OWNER, ServerInfo.USER_CONSOLE };
+ }
+
+ protected void setUserName(final String type, final String name) {
+ for (int i= 0; i < this.userTypes.length; i++) {
+ if (this.userTypes[i].equals(type)) {
+ if ((this.userNames[i] != null) ? !this.userNames[i].equals(name) : name != null) {
+ final String[] newNames= new String[this.userTypes.length];
+ System.arraycopy(this.userNames, 0, newNames, 0, this.userTypes.length);
+ newNames[i]= name;
+ this.userNames= newNames;
+ }
+ return;
+ }
+ }
+ }
+
+
+ public boolean getConfigUnbindOnStartup() {
+ return true;
+ }
+
+ public void setEngine(final SrvEngine engine) {
+ if (this.srvEngine != null) {
+ throw new IllegalStateException();
+ }
+
+ this.srvEngine= engine;
+ }
+
+ public void start(final ServerRuntimePlugin runtimePlugin) throws Exception {
+ if (this.srvEngine instanceof SrvEnginePluginExtension) {
+ ((SrvEnginePluginExtension) this.srvEngine).addPlugin(runtimePlugin);
+ }
+ }
+
+
+ @Override
+ public int getState() throws RemoteException {
+ return this.srvEngine.getState();
+ }
+
+ @Override
+ public int[] getVersion() throws RemoteException {
+ final int[] internalVersion= this.srvEngine.getVersion();
+ final int[] version= new int[internalVersion.length];
+ System.arraycopy(internalVersion, 0, version, 0, internalVersion.length);
+ return version;
+ }
+
+ @Override
+ public ServerInfo getInfo() throws RemoteException {
+ return new ServerInfo(this.control.getName(), this.workingDirectory, this.timestamp,
+ this.userTypes, this.userNames,
+ this.srvEngine.getState());
+ }
+
+
+ protected ServerAuthMethod getAuthMethod(final String command) {
+ if (command.startsWith("console.")) {
+ return this.authMethod;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final ServerLogin createLogin(final String command) throws RemoteException {
+ final ServerAuthMethod authMethod= getAuthMethod(command);
+ try {
+ return authMethod.createLogin();
+ }
+ catch (final RjException e) {
+ final String message= "Initializing login failed.";
+ LOGGER.log(Level.SEVERE, message, e);
+ throw new RemoteException(message, e);
+ }
+ }
+
+ protected Client connectClient(final String command, final ServerLogin login) throws RemoteException, LoginException {
+ final ServerAuthMethod authMethod= getAuthMethod(command);
+ try {
+ return authMethod.performLogin(login);
+ }
+ catch (final RjException e) {
+ final String message= "Performing login failed.";
+ LOGGER.log(Level.SEVERE, message, e);
+ throw new RemoteException(message, e);
+ }
+ }
+
+ @Override
+ public Object execute(final String command, final Map<String, ? extends Object> properties, final ServerLogin login) throws RemoteException, LoginException {
+ try {
+ if (command.equals(C_CONSOLE_START)) {
+ final Client client= connectClient(command, login);
+ final Object r= this.srvEngine.start(client, properties);
+ final Object startupTime= properties.get("rj.session.startup.time");
+ if (startupTime instanceof Long) {
+ this.timestamp= ((Long) startupTime).longValue();
+ }
+ return r;
+ }
+ if (command.equals(C_CONSOLE_CONNECT)) {
+ final Client client= connectClient(command, login);
+ final Object r= this.srvEngine.connect(client, properties);
+ return r;
+ }
+ return null;
+ }
+ finally {
+ final Client client= this.srvEngine.getCurrentClient();
+ setUserName(ServerInfo.USER_CONSOLE, ((client != null) ? client.getUsername() : null));
+ }
+ }
+
+
+ protected RObject runServerLoopCommand(RjsComObject sendCom, final DataCmdItem sendItem) throws RjException {
+ if (sendCom != null) {
+ throw new UnsupportedOperationException("sendComd");
+ }
+ DataCmdItem answer= null;
+ try {
+ this.serverC2SList.setObjects(sendItem);
+ sendCom= this.serverC2SList;
+
+ WAIT_FOR_ANSWER: while (true) {
+ final RjsComObject receivedCom= runMainLoop(sendCom, null);
+ sendCom= null;
+
+ COM_TYPE: switch (receivedCom.getComType()) {
+ case RjsComObject.T_PING:
+ sendCom= RjsStatus.OK_STATUS;
+ break COM_TYPE;
+ case RjsComObject.T_STATUS:
+ final RjsStatus status= (RjsStatus) receivedCom;
+ switch (status.getSeverity()) {
+ case RjsStatus.OK:
+ break COM_TYPE;
+ case RjsStatus.INFO:
+ break COM_TYPE;
+ case RjsStatus.ERROR:
+ if (status.getCode() == RjsStatus.ERROR) {
+ break WAIT_FOR_ANSWER;
+ }
+ throw new RjsException(status.getCode(), status.getMessage());
+ default:
+ break COM_TYPE;
+ }
+ case RjsComObject.T_MAIN_LIST:
+ final MainCmdS2CList list= (MainCmdS2CList) receivedCom;
+ MainCmdItem item= list.getItems();
+ while (item != null) {
+ if (item == sendItem) {
+ answer= sendItem;
+ break COM_TYPE;
+ }
+ item= item.next;
+ }
+ break COM_TYPE;
+ }
+ }
+ this.serverC2SList.clear();
+ if (answer == null || !answer.isOK()) {
+ final RjsStatus status= (answer != null) ? answer.getStatus() : MISSING_ANSWER_STATUS;
+ throw new RjException("R commands failed: "+status.getMessage()+".");
+ }
+ return answer.getData();
+ }
+ catch (final Exception e) {
+ if (e instanceof RjException) {
+ throw (RjException) e;
+ }
+ throw new RjException("An error when executing R command.", e);
+ }
+ }
+
+ protected RjsComObject runMainLoop(final RjsComObject com, final Object caller) throws RemoteException {
+ return this.srvEngine.runMainLoop(this.serverClient, com);
+ }
+
+ @Override
+ public File resolve(final Remote ref, final String path) throws RjException {
+ final File file= new File(path);
+ if (!SrvEngineServer.isValid(ref)) {
+ throw new RjException("Invalid access.");
+ }
+ if (file.isAbsolute()) {
+ return file;
+ }
+ final RObject rwd= runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_DATA, 0,
+ (byte) -1, "getwd()", null, null, null, null ));
+ return new File(rwd.getData().getChar(0), file.getPath());
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/Client.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/Client.java
new file mode 100644
index 0000000..916e774
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/Client.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext;
+
+
+public final class Client {
+
+
+ private final String username;
+ final String clientId;
+
+ public final byte slot;
+
+
+ public Client(final String username, final String clientId, final byte slot) {
+ this.username= username;
+ this.clientId= clientId;
+ this.slot= slot;
+ }
+
+ public String getUsername() {
+ return this.username;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerAuthMethod.java
new file mode 100644
index 0000000..929b87d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerAuthMethod.java
@@ -0,0 +1,274 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext;
+
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+import java.util.Locale;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.ChoiceCallback;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.LanguageCallback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+import javax.security.auth.callback.TextOutputCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.server.ServerLogin;
+
+
+/**
+ * Abstract class for authentication methods.
+ *
+ * An authentication method must extend this class and implement the
+ * abstract methods:
+ * <li>{@link #doInit(String)}</li>
+ * <li>{@link #doCreateLogin()}</li>
+ * <li>{@link #doPerformLogin(Callback[])}</li>
+ */
+public abstract class ServerAuthMethod {
+
+
+ protected static void copyAnswer(final Callback[] from, final Callback[] to) throws UnsupportedCallbackException {
+ assert (from.length == to.length);
+ for (int i= 0; i < from.length; i++) {
+ if (from[i] instanceof TextOutputCallback) {
+ continue;
+ }
+ if (from[i] instanceof NameCallback) {
+ ((NameCallback) to[i]).setName(((NameCallback) from[i]).getName());
+ continue;
+ }
+ if (from[i] instanceof PasswordCallback) {
+ ((PasswordCallback) to[i]).setPassword(((PasswordCallback) from[i]).getPassword());
+ ((PasswordCallback) from[i]).clearPassword();
+ continue;
+ }
+ if (from[i] instanceof TextInputCallback) {
+ ((TextInputCallback) to[i]).setText(((TextInputCallback) from[i]).getText());
+ continue;
+ }
+ if (from[i] instanceof ChoiceCallback) {
+ final int[] selectedIndexes= ((ChoiceCallback) from[i]).getSelectedIndexes();
+ if (((ChoiceCallback) from[i]).allowMultipleSelections()) {
+ ((ChoiceCallback) to[i]).setSelectedIndexes(selectedIndexes);
+ }
+ else if (selectedIndexes.length == 1) {
+ ((ChoiceCallback) to[i]).setSelectedIndex(selectedIndexes[0]);
+ }
+ continue;
+ }
+ if (from[i] instanceof ConfirmationCallback) {
+ ((ConfirmationCallback) to[i]).setSelectedIndex(((ConfirmationCallback) from[i]).getSelectedIndex());
+ continue;
+ }
+ if (from[i] instanceof LanguageCallback) {
+ ((LanguageCallback) to[i]).setLocale(Locale.getDefault());
+ continue;
+ }
+ throw new UnsupportedCallbackException(to[i]);
+ }
+ }
+
+
+ private static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server.auth");
+ private final String logPrefix;
+
+
+ private final String id;
+
+ private Random randomGenerator;
+
+ private final boolean usePubkeyExchange;
+ private KeyPairGenerator keyPairGenerator;
+
+ private String pendingLoginClient;
+ private long pendingLoginId;
+ private KeyPair pendingLoginKeyPair;
+
+ private String expliciteClient;
+
+
+ /**
+ *
+ * @param usePubkeyExchange enables default encryption of secret data (password)
+ */
+ protected ServerAuthMethod(final String id, final boolean usePubkeyExchange) {
+ this.usePubkeyExchange= usePubkeyExchange;
+ this.id= id;
+ this.logPrefix= "[Auth:"+id+"]";
+ }
+
+
+ public void setExpliciteClient(final String client) {
+ this.expliciteClient= client;
+ }
+
+ private String getCallingClient() throws ServerNotActiveException {
+ if (this.expliciteClient != null) {
+ return this.expliciteClient;
+ }
+ return RemoteServer.getClientHost();
+ }
+
+ public boolean isValid(final Client client) {
+ try {
+ return (getCallingClient().equals(client.clientId));
+ }
+ catch (final ServerNotActiveException e) {
+ return false;
+ }
+ }
+
+ public final void init(final String arg) throws RjException {
+ try {
+ if (this.usePubkeyExchange) {
+ this.keyPairGenerator= KeyPairGenerator.getInstance("RSA");
+ this.keyPairGenerator.initialize(2048);
+ }
+
+ this.randomGenerator= new SecureRandom();
+
+ doInit(arg);
+ }
+ catch (final Exception e) {
+ final RjException rje= (e instanceof RjException) ? (RjException) e :
+ new RjInitFailedException("An error occurred when initializing authentication method '"+this.id+"'.", e);
+ throw rje;
+ }
+ }
+
+ protected final Random getRandom() {
+ return this.randomGenerator;
+ }
+
+ /**
+ * Is called when the server is started
+ *
+ * @param arg configuration argument
+ *
+ * @throws RjException
+ */
+ protected abstract void doInit(String arg) throws RjException;
+
+ public final ServerLogin createLogin() throws RjException {
+ try {
+ final String client= getCallingClient();
+ final boolean same= client.equals(this.pendingLoginClient);
+ this.pendingLoginClient= client;
+
+ LOGGER.log(Level.INFO, "{0} creating new login ({1}).",
+ new Object[] { this.logPrefix, client });
+
+ long nextId;
+ do {
+ nextId= this.randomGenerator.nextLong();
+ } while (nextId == this.pendingLoginId);
+ this.pendingLoginId= nextId;
+ if (this.usePubkeyExchange) {
+ if (this.pendingLoginKeyPair == null || !same) {
+ this.pendingLoginKeyPair= this.keyPairGenerator.generateKeyPair();
+ }
+ }
+
+ return createNewLogin(doCreateLogin());
+ }
+ catch (final Exception e) {
+ final RjException rje= (e instanceof RjException) ? (RjException) e :
+ new RjException("An unexpected error occurred when preparing login process.", e);
+ throw rje;
+ }
+ }
+
+ /**
+ * Is called when client initiates a login process.
+ *
+ * @return login callbacks to handle by the client
+ *
+ * @throws RjException
+ */
+ protected abstract Callback[] doCreateLogin() throws RjException;
+
+ private ServerLogin createNewLogin(final Callback[] callbacks) {
+ if (this.usePubkeyExchange) {
+ return new ServerLogin(this.pendingLoginId, this.pendingLoginKeyPair.getPublic(), callbacks);
+ }
+ else {
+ return new ServerLogin(this.pendingLoginId, null, callbacks);
+ }
+ }
+
+ public final Client performLogin(final ServerLogin login) throws RjException, LoginException {
+ String client= null;
+ try {
+ client= getCallingClient();
+ if (login.getId() != this.pendingLoginId ||
+ !client.equals(this.pendingLoginClient)) {
+ throw new FailedLoginException("Login process was interrupted by another client.");
+ }
+
+ login.readAnswer(this.usePubkeyExchange ? this.pendingLoginKeyPair.getPrivate() : null);
+ this.pendingLoginKeyPair= null;
+ final String name= doPerformLogin(login.getCallbacks());
+
+ LOGGER.log(Level.INFO, "{0} performing login completed successfull: {1} ({2}).",
+ new Object[] { this.logPrefix, name, client });
+ return new Client(name, getCallingClient(), (byte) 0);
+ }
+ catch (final Exception e) {
+ if (e instanceof LoginException) {
+ final LogRecord log= new LogRecord(Level.INFO, "{0} performing login failed ({1}).");
+ log.setParameters(new Object[] { this.logPrefix, client });
+ log.setThrown(e);
+ LOGGER.log(log);
+ throw (LoginException) e;
+ }
+ if (e instanceof RjException) {
+ throw (RjException) e;
+ }
+ throw new RjException("An unexpected error occurred when validating the login credential.", e);
+ }
+ finally {
+ System.gc();
+ }
+ }
+
+ /**
+ * This method is called when the client sends the login data
+ *
+ * @param callbacks the callbacks handled by the client (note, the callbacks are not
+ * the same instances returned by {@link #createLogin()}, but clones)
+ *
+ * @return login id like username
+ *
+ * @throws LoginException if login failed (but can usually fixed by other login data)
+ * @throws RjException
+ */
+ protected abstract String doPerformLogin(Callback[] callbacks) throws LoginException, RjException;
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerRuntimePlugin.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerRuntimePlugin.java
new file mode 100644
index 0000000..adbb209
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/ServerRuntimePlugin.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext;
+
+
+public interface ServerRuntimePlugin {
+
+
+ public String getSymbolicName();
+
+ public void rjIdle() throws Exception;
+
+ public void rjStop(int state) throws Exception;
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/FxAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/FxAuthMethod.java
new file mode 100644
index 0000000..8796611
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/FxAuthMethod.java
@@ -0,0 +1,128 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.Arrays;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.FxCallback;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+/**
+ * Authentication method 'none'
+ * without any authentication mechanism.
+ */
+public class FxAuthMethod extends ServerAuthMethod {
+
+
+ private File file;
+ private FileInputStream fileInputStream;
+
+ private final byte[] pendingKey= new byte[1024];
+ private FileChannel fileChannel;
+
+
+ public FxAuthMethod() {
+ super("fx", false);
+ }
+
+
+ @Override
+ public void doInit(final String arg) throws RjException {
+ final String configType;
+ final String configValue;
+ { final String[] args= ServerUtils.getArgConfigValue(arg);
+ configType= args[0];
+ configValue= args[1];
+ }
+ if (configType.equals("file")) {
+ if (configValue == null || configValue.length() == 0) {
+ throw new RjException("Missing lock file name.", null);
+ }
+ this.file= new File(configValue);
+
+ try {
+ if (!this.file.exists()) {
+ this.file.createNewFile();
+ }
+ this.fileChannel= new RandomAccessFile(this.file, "rws").getChannel();
+ this.fileChannel.truncate(512);
+ }
+ catch (final IOException e) {
+ throw new RjException("Cannot read lock file.", e);
+ }
+ }
+ else {
+ throw new RjException("Unsupported configuration type '"+configType+"'.", null);
+ }
+ }
+
+ @Override
+ protected Callback[] doCreateLogin() throws RjException {
+ getRandom().nextBytes(this.pendingKey);
+ try {
+ this.fileChannel.position(this.fileChannel.size());
+ }
+ catch (final IOException e) {
+ throw new RjException("Cannot read lock file.", e);
+ }
+
+ return new Callback[] {
+ new NameCallback("Username"),
+ new FxCallback(this.file.getPath(), this.pendingKey),
+ };
+ }
+
+ @Override
+ protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+ final String userName= ((NameCallback) callbacks[0]).getName();
+ final byte[] clientKey= ((FxCallback) callbacks[1]).getContent();
+ if (clientKey.length < 1024) {
+ throw new RjException("Unsufficient client key");
+ }
+ try {
+ if (compare(this.pendingKey) && compare(clientKey)) {
+ return userName;
+ }
+ }
+ catch (final IOException e) {
+ throw new RjException("Cannot read lock file.", e);
+ }
+ throw new FailedLoginException();
+ }
+
+ private boolean compare(final byte[] key) throws IOException {
+ final byte[] check= new byte[key.length];
+ final int n= this.fileChannel.read(ByteBuffer.wrap(check));
+ if (n != key.length) {
+ return false;
+ }
+ return Arrays.equals(key, check);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/JaasAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/JaasAuthMethod.java
new file mode 100644
index 0000000..804dbb1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/JaasAuthMethod.java
@@ -0,0 +1,213 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+/**
+ * Draft for a JAAS auth method.
+ * Missing role/principal handling.
+ */
+public abstract class JaasAuthMethod extends ServerAuthMethod implements CallbackHandler, Runnable {
+
+
+ private static String JAAS_NAME= "org.eclipse.statet.rj.server";
+
+
+ private class JaasConfig extends Configuration {
+
+
+ private final AppConfigurationEntry entry;
+
+
+ JaasConfig(final String clazz) {
+ this.entry= new AppConfigurationEntry(clazz, AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, new HashMap());
+ }
+
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(final String name) {
+ return null;
+ }
+
+ @Override
+ public void refresh() {
+ }
+
+ }
+
+
+ private static final int STARTED= 1;
+ private static final int CALLBACK= 2;
+ private static final int PERFORM= 3;
+ private static final int LOGGED_IN= 4;
+
+ private static final int CANCEL= -1;
+ private static final int FAILED= -2;
+
+
+ private Configuration configuration;
+ private LoginContext context;
+
+ private Callback[] pendingLoginCallback;
+ private int pendingLogin;
+ private String pendingLoginMsg;
+
+ private final Thread loginThread;
+
+
+ protected JaasAuthMethod(final String id) {
+ super(id, true);
+ this.loginThread= new Thread(this);
+ }
+
+
+ @Override
+ public void doInit(final String arg) throws RjException {
+ this.configuration= Configuration.getConfiguration();
+ if (this.configuration.getAppConfigurationEntry(JAAS_NAME) == null) {
+ this.configuration= new JaasConfig(arg);
+ }
+ try {
+ this.context= new LoginContext(JAAS_NAME, new Subject(), this, this.configuration);
+ }
+ catch (final LoginException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected Callback[] doCreateLogin() throws RjException {
+ cancel();
+ this.loginThread.start();
+ synchronized (this) {
+ while (this.pendingLogin >= 0 && this.pendingLogin < CALLBACK) {
+ notifyAll();
+ try {
+ wait();
+ }
+ catch (final InterruptedException e) {}
+ }
+ }
+ if (this.pendingLogin == FAILED) {
+ throw new SecurityException("failed to init login", null);
+ }
+ return this.pendingLoginCallback;
+ }
+
+ @Override
+ protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+ this.pendingLoginCallback= callbacks;
+ this.pendingLogin= PERFORM;
+ synchronized (this) {
+ while (this.loginThread.isAlive()) {
+ notifyAll();
+ try {
+ wait();
+ }
+ catch (final InterruptedException e) {}
+ }
+ }
+ if (this.pendingLogin != LOGGED_IN) {
+ if (this.pendingLoginMsg != null) {
+ throw new LoginException(this.pendingLoginMsg);
+ }
+ else {
+ throw new SecurityException("", null);
+ }
+ }
+ return null;
+ }
+
+ private void cancel() {
+ this.pendingLoginCallback= null;
+ this.pendingLoginMsg= null;
+ this.pendingLogin= CANCEL;
+ synchronized (this) {
+ while (this.loginThread.isAlive()) {
+ notifyAll();
+ try {
+ wait();
+ }
+ catch (final InterruptedException e) {}
+ }
+ }
+ this.pendingLogin= 0;
+ }
+
+ @Override
+ public void run() {
+ this.pendingLogin= STARTED;
+ try {
+ this.context.login();
+ this.pendingLogin= LOGGED_IN;
+ this.context.logout();
+ }
+ catch (final LoginException e) {
+ this.pendingLogin= FAILED;
+ this.pendingLoginMsg= e.getLocalizedMessage();
+ }
+ catch (final Throwable e) {
+ this.pendingLogin= FAILED;
+ }
+ finally {
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+ }
+
+ @Override
+ public void handle(final Callback[] callbacks) throws IOException, UnsupportedCallbackException {
+ if (this.pendingLogin == STARTED) {
+ this.pendingLogin= CALLBACK;
+ this.pendingLoginCallback= callbacks;
+
+ synchronized (this) {
+ while (this.pendingLogin == CALLBACK) {
+ notifyAll();
+ try {
+ wait();
+ }
+ catch (final InterruptedException e) {}
+ }
+ }
+
+ if (this.pendingLogin != PERFORM) {
+ throw new IOException();
+ }
+ copyAnswer(this.pendingLoginCallback, callbacks);
+ }
+ else if (callbacks.length > 0){
+ this.pendingLogin= FAILED;
+ throw new UnsupportedCallbackException(callbacks[0]);
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/LocalShajAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/LocalShajAuthMethod.java
new file mode 100644
index 0000000..d23fc2b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/LocalShajAuthMethod.java
@@ -0,0 +1,82 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import com.cenqua.shaj.Shaj;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+/**
+ * Authentication method 'local-shaj'
+ * to authenticate against local user account.
+ */
+public class LocalShajAuthMethod extends ServerAuthMethod {
+
+
+ private String[] users;
+
+
+ public LocalShajAuthMethod() {
+ super("local-shaj", true);
+ }
+
+
+ @Override
+ public void doInit(final String arg) throws RjException {
+ if (!Shaj.init()) {
+ throw new RjException("Initializing authentication failed:\n" +
+ "Initializing 'shaj'-library failed");
+ }
+ this.users = new String[] { System.getProperty("user.name") };
+ }
+
+ @Override
+ protected Callback[] doCreateLogin() throws RjException {
+ return new Callback[] {
+ new NameCallback("Username"),
+ new PasswordCallback("Password", false),
+ };
+ }
+
+ @Override
+ protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+ final String loginName = ((NameCallback) callbacks[0]).getName();
+ if (isValidUser(loginName)) {
+ final char[] loginPassword = ((PasswordCallback) callbacks[1]).getPassword();
+ if (Shaj.checkPassword(null, loginName, new String(loginPassword))) {
+ return loginName;
+ }
+ }
+ throw new FailedLoginException("Invalid username or password");
+ }
+
+ private boolean isValidUser(final String user) {
+ for (final String s : this.users) {
+ if (s.equals(user)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/NoAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/NoAuthMethod.java
new file mode 100644
index 0000000..1eef829
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/NoAuthMethod.java
@@ -0,0 +1,59 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+
+
+/**
+ * Authentication method 'none'
+ * without any authentication mechanism.
+ */
+public class NoAuthMethod extends ServerAuthMethod {
+
+
+ public NoAuthMethod() {
+ super("none", false);
+ }
+
+ public NoAuthMethod(final String client) {
+ super("none", false);
+ setExpliciteClient(client);
+ try {
+ init("");
+ }
+ catch (final RjException e) {}
+ }
+
+
+ @Override
+ public void doInit(final String arg) throws RjException {
+ }
+
+ @Override
+ protected Callback[] doCreateLogin() throws RjException {
+ return null;
+ }
+
+ @Override
+ protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+ return "-";
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/SimpleNamePassAuthMethod.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/SimpleNamePassAuthMethod.java
new file mode 100644
index 0000000..e922c42
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/srvext/auth/SimpleNamePassAuthMethod.java
@@ -0,0 +1,139 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.srvext.auth;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Map.Entry;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+
+
+/**
+ * Authentication method 'name-pass'
+ * to authenticate against a given name password pair.
+ */
+public class SimpleNamePassAuthMethod extends ServerAuthMethod {
+
+
+ private Properties users;
+
+ private byte[] digestSash;
+ private MessageDigest digestService;
+ private Charset digestCharset;
+
+
+ public SimpleNamePassAuthMethod() {
+ super("name-pass", true);
+ }
+
+
+ @Override
+ public void doInit(final String arg) throws RjException {
+ final String configType;
+ final String configValue;
+ { final String[] args= ServerUtils.getArgConfigValue(arg);
+ configType= args[0];
+ configValue= args[1];
+ }
+ try {
+ this.digestSash= new byte[8];
+ final SecureRandom random= SecureRandom.getInstance("SHA1PRNG");
+ random.nextBytes(this.digestSash);
+ this.digestService= MessageDigest.getInstance("SHA-512");
+ this.digestCharset= Charset.forName("UTF-8");
+ }
+ catch (final Exception e) {
+ throw new RjException("", e);
+ }
+
+ if (configType.equals("file")) {
+ if (configValue == null || configValue.length() == 0) {
+ throw new RjException("Missing password file name.", null);
+ }
+ final File file= new File(configValue);
+ this.users= new Properties();
+ try {
+ this.users.load(new FileInputStream(file));
+ }
+ catch (final IOException e) {
+ throw new RjException("Reading password file failed.", null);
+ }
+ }
+ else {
+ throw new RjException("Unsupported configuration type '"+configType+"'.", null);
+ }
+ this.digestService.update(this.digestSash);
+ final Set<Entry<Object,Object>> entrySet= this.users.entrySet();
+ for (final Entry<Object, Object> entry : entrySet) {
+ final byte[] password= this.digestService.digest(this.digestCharset.encode(
+ (String) entry.getValue()).array());
+ entry.setValue(password);
+ }
+ System.gc();
+ }
+
+ @Override
+ protected Callback[] doCreateLogin() throws RjException {
+ return new Callback[] {
+ new NameCallback("Loginname"),
+ new PasswordCallback("Password", false),
+ };
+ }
+
+ @Override
+ protected String doPerformLogin(final Callback[] callbacks) throws LoginException, RjException {
+ final String loginName= ((NameCallback) callbacks[0]).getName();
+ final Object object= this.users.get(loginName);
+ if (object instanceof byte[]) {
+ final byte[] loginPassword= getPass((PasswordCallback) callbacks[1]);
+ if (Arrays.equals((byte[]) object, loginPassword)) {
+ return loginName;
+ }
+ }
+ throw new FailedLoginException("Invalid loginname or password");
+ }
+
+ private byte[] getPass(final PasswordCallback callback) {
+ final char[] loginPassword= callback.getPassword();
+ final byte[] loginBytes;
+ if (loginPassword == null) {
+ return new byte[0];
+ }
+ this.digestService.update(this.digestSash);
+ loginBytes= this.digestService.digest(this.digestCharset.encode(
+ CharBuffer.wrap(loginPassword)).array());
+ callback.clearPassword();
+ Arrays.fill(loginPassword, (char) 0);
+ return loginBytes;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/LocalREnv.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/LocalREnv.java
new file mode 100644
index 0000000..9329ad9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/LocalREnv.java
@@ -0,0 +1,286 @@
+/*=============================================================================#
+ # Copyright (c) 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.util;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Function;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+
+
+public class LocalREnv {
+
+
+ public static final int OS_WIN= 1;
+ public static final int OS_NIX= 2;
+ public static final int OS_MAC= 3;
+
+
+ private static final Logger LOGGER= Logger.getLogger("org.eclipse.statet.rj.server"); //$NON-NLS-1$
+
+ private static final int OS_TYPE;
+ static {
+ final String osname= System.getProperty("os.name").toLowerCase(); //$NON-NLS-1$
+ if (osname.contains("win")) { //$NON-NLS-1$
+ OS_TYPE= OS_WIN;
+ }
+ else if (osname.contains("mac")) { //$NON-NLS-1$
+ OS_TYPE= OS_MAC;
+ }
+ else {
+ OS_TYPE= OS_NIX;
+ }
+ }
+
+ private static final Pattern PATH_SPLITTER= Pattern.compile(Pattern.quote(File.pathSeparator));
+
+ private static final String DEFAULT_HOME_TEMPLATE= "${R_HOME}"; //$NON-NLS-1$
+
+ private static final List<String> DEFAULT_PATHS_TEMPLATES= Arrays.asList(
+ "${R_LIBS}", //$NON-NLS-1$
+ "${R_LIBS_USER}", //$NON-NLS-1$
+ "${R_LIBS_SITE}" , //$NON-NLS-1$
+ "${R_HOME}/library" ); //$NON-NLS-1$
+
+
+ private static void add(final List<Path> paths, final Path pathToAdd) {
+ if (pathToAdd != null && !paths.contains(pathToAdd)) {
+ paths.add(pathToAdd);
+ }
+ }
+
+ private static void addAll(final List<Path> paths, final List<Path> pathsToAdd) {
+ if (pathsToAdd != null) {
+ pathsToAdd.forEach((path) -> add(paths, path));
+ }
+ }
+
+
+ /**
+ * R home path.
+ */
+ private final Path rHomePath;
+
+ /**
+ * R library path (list with directories containing R packages).
+ */
+ private final List<Path> rLibPaths;
+
+
+ public LocalREnv(final String rHomeTemplate, final List<String> rLibPathsTemplates,
+ Function<String, String> varResolver)
+ throws RjInvalidConfigurationException {
+ if (rHomeTemplate == null) {
+ throw new NullPointerException("rHomeTemplate"); //$NON-NLS-1$
+ }
+ if (rLibPathsTemplates == null) {
+ throw new NullPointerException("rLibPathsTemplates"); //$NON-NLS-1$
+ }
+ if (varResolver == null) {
+ varResolver= System::getenv;
+ }
+ this.rHomePath= checkPath(resolveTemplate(rHomeTemplate, varResolver));
+ this.rLibPaths= resolveRLibPaths(rLibPathsTemplates, varResolver);
+
+ checkSpec();
+ }
+
+ public LocalREnv() throws RjInvalidConfigurationException {
+ this(DEFAULT_HOME_TEMPLATE, DEFAULT_PATHS_TEMPLATES, null);
+ }
+
+ public LocalREnv(final Function<String, String> varResolver)
+ throws RjInvalidConfigurationException {
+ this(DEFAULT_HOME_TEMPLATE, DEFAULT_PATHS_TEMPLATES, varResolver);
+ }
+
+
+ public LocalREnv(final String rHome, final List<String> rLibPaths)
+ throws RjInvalidConfigurationException {
+ if (rHome == null) {
+ throw new NullPointerException("rHome"); //$NON-NLS-1$
+ }
+ if (rLibPaths == null) {
+ throw new NullPointerException("rLibPaths"); //$NON-NLS-1$
+ }
+ this.rHomePath= checkPath(rHome);
+ this.rLibPaths= resolveRLibPaths(rLibPaths, null);
+
+ checkSpec();
+ }
+
+ public LocalREnv(final Path rHomePath, final List<Path> rLibPaths)
+ throws RjInvalidConfigurationException {
+ if (rHomePath == null) {
+ throw new NullPointerException("rHome"); //$NON-NLS-1$
+ }
+ if (rLibPaths == null) {
+ throw new NullPointerException("rLibPaths"); //$NON-NLS-1$
+ }
+ this.rHomePath= rHomePath;
+ this.rLibPaths= rLibPaths;
+
+ checkSpec();
+ }
+
+
+ protected List<Path> resolveRLibPaths(final List<String> rLibPathsTemplates,
+ final Function<String, String> varResolver) {
+ final List<Path> paths= new ArrayList<>();
+ for (final String template : rLibPathsTemplates) {
+ final String value= (varResolver != null) ?
+ resolveTemplate(template, varResolver) :
+ template;
+ try {
+ addAll(paths, checkPathList(value));
+ }
+ catch (final Exception e) {
+ LOGGER.log(Level.WARNING, "An error occurred when adding '" + template + "' to R library paths.", e);
+ }
+ }
+
+ return paths;
+ }
+
+ protected String resolveTemplate(final String s, final Function<String, String> varResolver) {
+ if (s != null && s.indexOf('$') >= 0) {
+ final StringBuilder sb= new StringBuilder();
+ int startIdx= 0;
+ int endIdx= 0;
+ while (true) {
+ startIdx= s.indexOf("${", endIdx);
+ if (startIdx >= 0) {
+ sb.append(s, endIdx, startIdx);
+ startIdx+= 2;
+ endIdx= s.indexOf('}', startIdx);
+ if (endIdx >= 0) {
+ final String value= varResolver.apply(s.substring(startIdx, endIdx));
+ if (value != null) {
+ sb.append(value);
+ endIdx++;
+ continue;
+ }
+ }
+ break;
+ }
+ else {
+ sb.append(s, endIdx, s.length());
+ return sb.toString();
+ }
+ }
+ }
+ return null;
+ }
+
+ protected void checkSpec() throws RjInvalidConfigurationException {
+ if (LOGGER.isLoggable(Level.CONFIG)) {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RJClassLoader - R home path= "); //$NON-NLS-1$
+ if (this.rHomePath != null) {
+ sb.append(this.rHomePath);
+ }
+ else {
+ sb.append("<missing>"); //$NON-NLS-1$
+ }
+ sb.append("RJClassLoader - R library paths= "); //$NON-NLS-1$
+ if (this.rLibPaths != null) {
+ if (this.rLibPaths.isEmpty()) {
+ sb.append("<empty>"); //$NON-NLS-1$
+ }
+ else {
+ ServerUtils.prettyPrint(this.rLibPaths, sb);
+ }
+ }
+ else {
+ sb.append("<missing>"); //$NON-NLS-1$
+ }
+ LOGGER.log(Level.CONFIG, sb.toString());
+ }
+
+ if (this.rHomePath == null) {
+ throw new RjInvalidConfigurationException("Spec of R home path is missing."); //$NON-NLS-1$
+ }
+ if (this.rLibPaths.isEmpty()) {
+ throw new RjInvalidConfigurationException("Spec of R library paths is empty"); //$NON-NLS-1$
+ }
+ }
+
+
+ public Path checkPath(String path) {
+ if (path != null) {
+ path= path.trim();
+ if (!path.isEmpty()) {
+ return Paths.get(path).normalize();
+ }
+ }
+ return null;
+ }
+
+ public List<Path> checkPathList(String pathList) {
+ if (pathList != null) {
+ pathList= pathList.trim();
+ if (!pathList.isEmpty()) {
+ final String[] split= PATH_SPLITTER.split(pathList);
+ final ArrayList<Path> list= new ArrayList<>(split.length);
+ for (int i= 0; i < split.length; i++) {
+ final Path path= checkPath(split[i]);
+ if (path != null) {
+ list.add(path);
+ }
+ }
+ return list;
+ }
+ }
+ return null;
+ }
+
+
+ public int getOSType() {
+ return OS_TYPE;
+ }
+
+ public Path getRHomePath() {
+ return this.rHomePath;
+ }
+
+ public List<Path> getRLibPaths() {
+ return Collections.unmodifiableList(this.rLibPaths);
+ }
+
+
+ public Path searchRPkg(final String name) {
+ for (final Path path : this.rLibPaths) {
+ try {
+ final Path packagePath= path.resolve(name);
+ if (Files.isRegularFile(packagePath.resolve("DESCRIPTION"))) {
+ return packagePath;
+ }
+ }
+ catch (final Exception e) {}
+ }
+ return null;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/RJContext.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/RJContext.java
new file mode 100644
index 0000000..132775b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/RJContext.java
@@ -0,0 +1,266 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.util;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_SERVER_ID;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.regex.Pattern;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+
+
+public class RJContext {
+
+
+ protected static abstract class PathEntry implements Comparable<PathEntry> {
+
+ final String name;
+
+ public PathEntry(final String child) {
+ this.name= child;
+ }
+
+ @Override
+ public int compareTo(final PathEntry o) {
+ return this.name.compareTo((o).name);
+ }
+
+ public abstract String getPath();
+
+ @Override
+ public abstract String toString();
+
+ }
+
+ protected static class FilePathEntry extends PathEntry {
+
+ final File dir;
+
+ public FilePathEntry(final File dir, final String name) {
+ super(name);
+ this.dir= dir;
+ }
+
+ @Override
+ public String getPath() {
+ final File file= new File(this.dir, this.name);
+ if (file.isDirectory()) {
+ final File binFile= new File(file, "bin");
+ if (binFile.exists() && binFile.isDirectory()) {
+ return binFile.getPath();
+ }
+ }
+ return file.getPath();
+ }
+
+ @Override
+ public String toString() {
+ return '\'' + this.name + "' in '" + this.dir + '\'';
+ }
+
+ }
+
+
+ private String libPath;
+
+
+ public RJContext(final String libPath) {
+ this.libPath= libPath;
+ }
+
+ protected RJContext() {
+ }
+
+
+ public List<String> searchRJLibs(final List<String> libIds)
+ throws RjInvalidConfigurationException {
+ final List<PathEntry> candidates= getRJLibCandidates();
+
+ final ArrayList<String> resolved= new ArrayList<>(libIds.size());
+ StringBuilder sb= null;
+
+ Collections.sort(candidates);
+ for (final String libId : libIds) {
+ final PathEntry entry= searchLib(candidates, libId);
+ if (entry == null) {
+ if (sb == null) {
+ sb= new StringBuilder("Missing RJ library ");
+ }
+ else {
+ sb.append(", ");
+ }
+ sb.append('\'');
+ sb.append(libId);
+ sb.append('\'');
+ }
+ else {
+ resolved.add(entry.getPath());
+ }
+ }
+ if (sb != null) {
+ sb.append('.');
+ throw new RjInvalidConfigurationException(sb.toString());
+ }
+ return resolved;
+ }
+
+ protected String[] getLibDirPaths() throws RjInvalidConfigurationException {
+ String path= System.getProperty("org.eclipse.statet.rj.path");
+ if (path == null) {
+ path= this.libPath;
+ }
+ if (path == null || path.isEmpty()) {
+ throw new RjInvalidConfigurationException("Missing or invalid RJ library location.");
+ }
+ return path.split(Pattern.quote(File.pathSeparator));
+ }
+
+ protected List<PathEntry> getRJLibCandidates() throws RjInvalidConfigurationException {
+ final String[] paths= getLibDirPaths();
+
+ final List<PathEntry> files= new ArrayList<>(paths.length*10);
+ for (int i= 0; i < paths.length; i++) {
+ if (paths[i].length() > 0) {
+ File dir= new File(paths[i]);
+ try {
+ dir= dir.getCanonicalFile();
+ }
+ catch (final IOException e) {}
+ final String[] list= dir.list();
+ if (list != null) {
+ for (final String child : list) {
+ files.add(new FilePathEntry(dir, child));
+ }
+ }
+ }
+ }
+
+ return files;
+ }
+
+ protected PathEntry searchLib(final List<PathEntry> files, final String libId) {
+ PathEntry found= null;
+ for (final PathEntry entry : files) {
+ if (entry.name.startsWith(libId)) {
+ // without version
+ if (entry.name.length() == libId.length() // equals
+ || (entry.name.length() == libId.length() + 4 && entry.name.endsWith(".jar")) ) {
+ return entry;
+ }
+ // with version suffix
+ if (entry.name.length() > libId.length()) {
+ if (entry.name.charAt(libId.length()) == '_') {
+ found= entry;
+ }
+ }
+ }
+ }
+ return found;
+ }
+
+
+ public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+ String serverLib= searchRJLibs(Collections.singletonList(RJ_SERVER_ID)).get(0);
+ final File libFile= new File(serverLib);
+ if (libFile.isDirectory()) {
+ File file= new File(libFile, "localhost.policy");
+ if (libFile.getName().equals("bin") && !file.exists()) {
+ file= new File(libFile.getParentFile(), "localhost.policy");
+ }
+ return file.toURI().toString();
+ }
+ // expect jar file
+ serverLib= libFile.toURI().toString();
+ return "jar:" + serverLib + "!/localhost.policy";
+ }
+
+
+ protected String getPropertiesDirPath() {
+ return System.getProperty("user.dir");
+ }
+
+ protected InputStream getInputStream(final String path) throws IOException {
+ final File file= new File(path);
+ if (!file.exists()) {
+ return null;
+ }
+ return new FileInputStream(file);
+ }
+
+ protected OutputStream getOutputStream(final String path) throws IOException {
+ final File file= new File(path);
+ return new FileOutputStream(file, false);
+ }
+
+ public Properties loadProperties(final String name) throws IOException {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ final String path= getPropertiesDirPath() + "/" + name + ".properties";
+ final InputStream in= getInputStream(path);
+ if (in == null) {
+ return null;
+ }
+
+ final Properties properties= new Properties();
+ try {
+ properties.load(in);
+ }
+ finally {
+ if (in != null) {
+ try {
+ in.close();
+ }
+ catch (final IOException e) {}
+ }
+ }
+
+ return properties;
+ }
+
+ public void saveProperties(final String name, final Properties properties) throws IOException {
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ if (properties == null) {
+ throw new NullPointerException("properties");
+ }
+ final String path= getPropertiesDirPath() + "/" + name + ".properties";
+ final OutputStream out= getOutputStream(path);
+
+ try {
+ properties.store(out, null);
+ }
+ finally {
+ if (out != null) {
+ try {
+ out.close();
+ }
+ catch (final IOException e) {}
+ }
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/ServerUtils.java b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/ServerUtils.java
new file mode 100644
index 0000000..4cf12b4
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/src/org/eclipse/statet/rj/server/util/ServerUtils.java
@@ -0,0 +1,231 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.util;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.eclipse.statet.rj.server.RjsStatus;
+
+
+/**
+ * Server utilities.
+ */
+public class ServerUtils {
+
+
+ public static final String RJ_DATA_ID= "org.eclipse.statet.rj.data";
+ public static final String RJ_SERVER_ID= "org.eclipse.statet.rj.server";
+
+ public static final int[] RJ_VERSION= new int[] { 2, 1, 0 };
+
+ public static final RjsStatus MISSING_ANSWER_STATUS= new RjsStatus(RjsStatus.ERROR, 121, "Server error (missing answer).");
+
+
+ /**
+ * Split at next ':'
+ * @param arg the argument to split
+ * @return String array of length 2
+ */
+ public static String[] getArgSubValue(final String arg) {
+ final String[] args= new String[2];
+ if (arg != null && arg.length() > 0) {
+ final int idx= arg.indexOf(':');
+ if (idx >= 0) {
+ args[0]= arg.substring(0, idx);
+ args[1]= arg.substring(idx+1);
+ }
+ else {
+ args[0]= arg;
+ }
+ }
+ else {
+ args[0]= "";
+ }
+ return args;
+ }
+
+ /**
+ * Split at next '='
+ * @param arg the argument to split
+ * @return String array of length 2
+ */
+ public static String[] getArgConfigValue(final String arg) {
+ final String[] args= new String[2];
+ if (arg != null && arg.length() > 0) {
+ final int idx= arg.indexOf('=');
+ if (idx >= 0) {
+ args[0]= arg.substring(0, idx);
+ args[1]= arg.substring(idx+1);
+ }
+ else {
+ args[0]= arg;
+ }
+ }
+ else {
+ args[0]= "";
+ }
+ return args;
+ }
+
+ /**
+ * Split at ','
+ * @param arg the argument to split
+ * @return List with String
+ */
+ public static List<String> getArgValueList(final String arg) {
+ if (arg != null && arg.length() > 0) {
+ return Arrays.asList(arg.split(","));
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+
+ public static void prettyPrint(final Map map, final StringBuilder sb) {
+ final String sep= System.getProperty("line.separator")+"\t";
+ final Set<Entry<?, ?>> entrySet= map.entrySet();
+ for (final Entry<?, ?> entry : entrySet) {
+ sb.append(sep);
+ sb.append(entry.getKey());
+ sb.append('=');
+ final Object value= entry.getValue();
+ if (value != null) {
+ sb.append(value);
+ }
+ }
+ }
+
+ public static void prettyPrint(final Collection<?> list, final StringBuilder sb) {
+ final String sep= System.getProperty("line.separator")+"\t";
+ for (final Object value : list) {
+ sb.append(sep);
+ if (value != null) {
+ sb.append(value);
+ }
+ }
+ }
+
+ public static void prettyPrintVersion(final int[] version, final StringBuilder sb) {
+ if (version == null || version.length == 0) {
+ sb.append("<missing>");
+ }
+ else {
+ sb.append(version[0]);
+ for (int i= 1; i < version.length; i++) {
+ sb.append('.');
+ sb.append(version[i]);
+ }
+ }
+ }
+
+
+ public static String concatPathVar(final Collection<String> entries) {
+ if (entries.isEmpty()) {
+ return "";
+ }
+ final StringBuilder sb= new StringBuilder();
+ for (final String entry : entries) {
+ sb.append(entry);
+ sb.append(File.pathSeparatorChar);
+ }
+ return sb.substring(0, sb.length()-1);
+ }
+
+ private static String encodeCodebaseEntry(String path) {
+ if (path == null || path.isEmpty()) {
+ return null;
+ }
+ URI uri= null;
+ try {
+ if (path.startsWith("file:")) {
+ path= path.substring(5);
+ uri= new URI("file", null, path, null);
+ }
+ else {
+ if (File.separatorChar == '\\') {
+ path= path.replace('\\', '/');
+ }
+ if (path.charAt(0) != '/') {
+ path= '/' + path;
+ }
+ uri= new URI("file", null, path, null);
+ }
+ return uri.toString();
+ }
+ catch (final URISyntaxException e) {
+ throw new IllegalArgumentException("Invalid entry for codebase", e);
+ }
+ }
+
+ /**
+ * Concats the specified entries to a valid codebase property value.
+ * The entries have to be path in the local file system. It is recommend to specify the entries
+ * as URL with the schema 'file'.
+ */
+ public static String concatCodebase(final Collection<String> entries) {
+ if (entries.isEmpty()) {
+ return "";
+ }
+ final StringBuilder sb= new StringBuilder();
+ for (final String entry : entries) {
+ final String path= encodeCodebaseEntry(entry);
+ if (path != null) {
+ sb.append(path);
+ sb.append(' ');
+ }
+ }
+ return sb.substring(0, sb.length()-1);
+ }
+
+ public static boolean delDir(final File dir) {
+ final String[] children= dir.list();
+ for (final String child : children) {
+ final File file= new File(dir, child);
+ if (file.isDirectory()) {
+ delDir(file);
+ }
+ else {
+ file.delete();
+ }
+ }
+ return dir.delete();
+ }
+
+ public static void cleanDir(final File dir, final String exclude) {
+ final String[] children= dir.list();
+ for (final String child : children) {
+ if (child.equals(exclude)) {
+ continue;
+ }
+ final File file= new File(dir, child);
+ if (file.isDirectory()) {
+ delDir(file);
+ }
+ else {
+ file.delete();
+ }
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/e/srvext/SWTPlugin.java b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/e/srvext/SWTPlugin.java
new file mode 100644
index 0000000..ab49038
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/e/srvext/SWTPlugin.java
@@ -0,0 +1,57 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.e.srvext;
+
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+
+
+/**
+ * Creates a display for native widgets ('native' depends on SWT in classpath).
+ */
+public class SWTPlugin implements ServerRuntimePlugin {
+
+
+ private Display display;
+
+
+ public SWTPlugin() {
+ }
+
+
+ @Override
+ public String getSymbolicName() {
+ return "swt";
+ }
+
+ @Override
+ public void rjIdle() throws Exception {
+ if (this.display == null) {
+ Display.setAppName("R");
+ this.display= new Display();
+ }
+ this.display.readAndDispatch();
+ }
+
+ @Override
+ public void rjStop(final int regular) throws Exception {
+ if (this.display != null) {
+ this.display.dispose();
+ this.display= null;
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/osgi/ERJContext.java b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/osgi/ERJContext.java
new file mode 100644
index 0000000..ad1cbe1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.server/srcEExtensions/org/eclipse/statet/rj/server/osgi/ERJContext.java
@@ -0,0 +1,150 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.server.osgi;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_SERVER_ID;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.osgi.framework.Bundle;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+
+
+/**
+ * Server utilities when using the Eclipse Platform.
+ */
+public class ERJContext extends RJContext {
+
+
+ private static void handle(final IStatus status) {
+ Platform.getLog(Platform.getBundle(RJ_SERVER_ID)).log(status);
+ }
+
+
+ public ERJContext() {
+ }
+
+
+ /**
+ * Searches the specified RJ libraries in the Eclipse Platform installations
+ * <p>
+ * Uses always the os/arch currently running.</p>
+ *
+ * @param libIds the bundle ids of the libraries
+ * @return the file paths of the found libraries
+ */
+ @Override
+ public List<String> searchRJLibs(final List<String> libIds) {
+ final Set<String> resolved= new LinkedHashSet<>();
+ for (final String libId : libIds) {
+ final Bundle pluginBundle= Platform.getBundle(libId);
+ if (pluginBundle != null) {
+ addPath(pluginBundle, resolved);
+ final Bundle[] fragments= Platform.getFragments(pluginBundle);
+ if (fragments != null) {
+ for (final Bundle fragmentBundle : fragments) {
+ addPath(fragmentBundle, resolved);
+ }
+ }
+ }
+ }
+ return ImCollections.toList(resolved);
+ }
+
+ private void addPath(final Bundle bundle, final Set<String> classpath) {
+// String location= bundle.getLocation();
+// if (location.startsWith("initial@")) {
+// location= location.substring(8);
+// }
+// if (location.startsWith("reference:file:")) { //$NON-NLS-1$
+// location= location.substring(15);
+// IPath path= new Path(location);
+// if (!path.isAbsolute()) {
+// path= new Path(Platform.getInstallLocation().getURL().getFile()).append(path);
+// }
+// String checked= path.lastSegment();
+// if (checked.contains("motif")) { //$NON-NLS-1$
+// checked= checked.replaceAll("motif", "gtk"); //$NON-NLS-1$ //$NON-NLS-2$
+// }
+// if (checked.contains("gtk")) { //$NON-NLS-1$
+// if (is64 && !checked.contains("64")) { //$NON-NLS-1$
+// checked= checked.replaceAll("x86", "x86_64"); //$NON-NLS-1$ //$NON-NLS-2$
+// }
+// if (!is64 && checked.contains("64")) { //$NON-NLS-1$
+// checked= checked.replaceAll("x86_64", "x86"); //$NON-NLS-1$ //$NON-NLS-2$
+// }
+// }
+// final String s= path.removeLastSegments(1).append(checked).makeAbsolute().toOSString();
+// if (location.endsWith("/")) { // //$NON-NLS-1$
+// if (Platform.inDevelopmentMode()) {
+// classpath.add(s+File.separatorChar+"bin"+File.separatorChar); //$NON-NLS-1$
+// }
+// classpath.add(s+File.separatorChar);
+// }
+// else {
+// classpath.add(s);
+// }
+// return;
+// }
+ try {
+ String s= FileLocator.resolve(bundle.getEntry("/")).toExternalForm();
+ if (s.startsWith("jar:") && s.endsWith("!/")) {
+ s= s.substring(4, s.length()-2);
+ }
+ if (s.startsWith("file:")) {
+ s= s.substring(5);
+ }
+ if (Platform.inDevelopmentMode() && s.endsWith("/")) {
+ classpath.add(s+"bin/");
+ }
+ classpath.add(s);
+ return;
+ }
+ catch (final Exception e) {}
+ handle(new Status(IStatus.WARNING, RJ_SERVER_ID,
+ "Unknown location for plug-in: '"+bundle.getBundleId()+"'. May cause fail to startup RJ (RMI/JRI)")); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+ try {
+ final Bundle bundle= Platform.getBundle(RJ_SERVER_ID);
+ if (bundle == null) {
+ throw new RjInvalidConfigurationException("RJ Server bundle ('"+RJ_SERVER_ID+"') is missing.");
+ }
+ final URL intern= bundle.getEntry("/localhost.policy");
+ final URL java= FileLocator.resolve(intern);
+ final String path= java.toExternalForm();
+ return path;
+ }
+ catch (final IOException e) {
+ throw new RjInvalidConfigurationException("Failed to resolve path to 'localhost.policy'.", e);
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/.classpath b/core/org.eclipse.statet.rj.services.core/.classpath
new file mode 100644
index 0000000..020ba8c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+ <attributes>
+ <attribute name="owner.project.facets" value="java"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="srcREnv"/>
+ <classpathentry kind="src" path="srcGraphic"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/core/org.eclipse.statet.rj.services.core/.gitignore b/core/org.eclipse.statet.rj.services.core/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/core/org.eclipse.statet.rj.services.core/.project b/core/org.eclipse.statet.rj.services.core/.project
new file mode 100644
index 0000000..394d5aa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.project
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.services.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.resources.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.runtime.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.core.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.ui.prefs b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.component b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..8428fc2
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="org.eclipse.statet.rj.services.core">
+ <wb-resource deploy-path="/" source-path="/src"/>
+ <wb-resource deploy-path="/" source-path="/srcGraphic"/>
+ </wb-module>
+</project-modules>
diff --git a/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.project.facet.core.xml b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..a1f5f3c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <fixed facet="java"/>
+ <fixed facet="jst.utility"/>
+ <installed facet="java" version="1.8"/>
+ <installed facet="jst.utility" version="1.0"/>
+</faceted-project>
diff --git a/core/org.eclipse.statet.rj.services.core/META-INF/MANIFEST.MF b/core/org.eclipse.statet.rj.services.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b71336a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/META-INF/MANIFEST.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.services.core;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - R Services API and Tools - Core
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)";visibility:=reexport
+Import-Package: org.osgi.framework;version="1.8.0",
+ org.eclipse.core.runtime
+Export-Package: org.eclipse.statet.rj.graphic.core;version="1.0.0",
+ org.eclipse.statet.rj.graphic.core.util;version="1.0.0",
+ org.eclipse.statet.rj.renv.core;version="2.1.0",
+ org.eclipse.statet.rj.services;version="1.0.0",
+ org.eclipse.statet.rj.services.util;version="2.1.0",
+ org.eclipse.statet.rj.services.util.dataaccess;version="2.1.0"
diff --git a/core/org.eclipse.statet.rj.services.core/about.html b/core/org.eclipse.statet.rj.services.core/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/core/org.eclipse.statet.rj.services.core/build.properties b/core/org.eclipse.statet.rj.services.core/build.properties
new file mode 100644
index 0000000..fe1609f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/build.properties
@@ -0,0 +1,10 @@
+source..= src/,\
+ srcREnv/,\
+ srcGraphic/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ .,\
+ about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FQRObjectRef.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FQRObjectRef.java
new file mode 100644
index 0000000..86a6235
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FQRObjectRef.java
@@ -0,0 +1,49 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import org.eclipse.statet.rj.data.RObject;
+
+
+/**
+ * Fully qualified reference to an R object.
+ *
+ * @since 2.1 (provisional)
+ */
+public interface FQRObjectRef {
+
+
+ /**
+ * Handle to the R instance.
+ *
+ * @return handle to R.
+ */
+ Object getRHandle();
+
+ /**
+ * The environment in R, specified by a call or reference.
+ *
+ * @return a reference to the environment
+ */
+ RObject getEnv();
+
+ /**
+ * Name, relative to the environment, specified by a symbol or call.
+ *
+ * @return the name
+ */
+ RObject getName();
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FunctionCall.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FunctionCall.java
new file mode 100644
index 0000000..6008e09
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/FunctionCall.java
@@ -0,0 +1,340 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RStore;
+
+
+/**
+ * A function call provides a comfortable way to build and execute
+ * R function call.
+ *
+ * <p>A function call builder for a given function can be created by
+ * {@link RService#createFunctionCall(String)}.</p>
+ *
+ * <p>The builder mainly provides methods to add arguments and to
+ * finally evaluate the resulting function call in R.</p>
+ *
+ * <p>Arguments are added by the <code>#add...()</code> methods. The
+ * order they are added is exactly the order they are send to R. There
+ * are add methods for a symbol referring to data existing in R,
+ * for given R data objects and for single data values which are
+ * transformed automatically from java primitives into R data objects.
+ * All methods are available in a variant with and without a parameter
+ * for the R argument name. An unnamed argument can be specified by
+ * using the variant without the argument name parameter or by specifying
+ * the name as <code>null</code>.</p>
+ *
+ * <p>The common guidelines in {@link RService} (like concurrency) are effective
+ * for all evaluation methods in this interface.</p>
+ */
+public interface FunctionCall {
+
+
+ /**
+ * Adds an argument with the given R expression as value.
+ *
+ * <p>The expression is parsed and lazily evaluated as known from function calls in R source
+ * code.</p>
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @param expression a single valid expression
+ * @return a reference to this object
+ *
+ * @see #addChar(String, String) to add a string/character value directly
+ */
+ FunctionCall add(String arg, String expression);
+
+ /**
+ * Adds a unnamed argument with the given R expression as value.
+ *
+ * <p>The expression is parsed and lazily evaluated as known from function calls in R source
+ * code.</p>
+ *
+ * @param expression a single valid expression
+ * @return a reference to this object
+ *
+ * @see #addChar(String) to add a string/character value directly
+ */
+ FunctionCall add(String expression);
+
+ /**
+ * Adds a argument with the given R data object as value.
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @param data an R data object
+ * @return a reference to this object
+ */
+ FunctionCall add(String arg, RObject data);
+
+ /**
+ * Adds an unnamed argument with the given R data object as value.
+ *
+ * @param arg the name of the argument
+ * @param data an R data object
+ * @return a reference to this object
+ */
+ FunctionCall add(RObject data);
+
+
+ /**
+ * Adds an argument with the given boolean/logical as value.
+ *
+ * <p>The Java boolean value is transformed into an R data object
+ * of type {@link RStore#LOGICAL logical}.</p>
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @param logical the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addLogi(String arg, boolean logical);
+
+ /**
+ * Adds an unnamed argument with the given boolean/logical as value.
+ *
+ * <p>The Java boolean value is transformed into an R data object
+ * of type {@link RStore#LOGICAL logical}.</p>
+ *
+ * @param logical the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addLogi(boolean logical);
+
+ /**
+ * Adds an argument with the given integer as value.
+ *
+ * <p>The Java integer value is transformed into an R data object
+ * of type {@link RStore#INTEGER integer}.</p>
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @param integer the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addInt(String arg, int integer);
+
+ /**
+ * Adds an unnamed argument with the given integer as value.
+ *
+ * <p>The Java integer value is transformed into an R data object
+ * of type {@link RStore#INTEGER integer}.</p>
+ *
+ * @param integer the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addInt(int integer);
+
+ /**
+ * Adds an argument with the given double/numeric as value.
+ *
+ * <p>The Java double value is transformed into an R data object
+ * of type {@link RStore#NUMERIC numeric}, also called real.</p>
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @param numeric the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addNum(String arg, double numeric);
+
+ /**
+ * Adds an unnamed argument with the given double/numeric as value.
+ *
+ * <p>The Java double value is transformed into an R data object
+ * of type {@link RStore#NUMERIC numeric}, also called real.</p>
+ *
+ * @param arg the name of the argument
+ * @param numeric the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addNum(double numeric);
+
+ /**
+ * Adds an argument with the given string/character as value.
+ *
+ * <p>The Java String value is transformed into an R data object
+ * of type {@link RStore#CHARACTER character}.</p>
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @param character the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addCplx(String arg, double real, double imaginary);
+
+ /**
+ * Adds an unnamed argument with the given string/character as value.
+ *
+ * <p>The Java String value is transformed into an R data object
+ * of type {@link RStore#CHARACTER character}.</p>
+ *
+ * @param character the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addCplx(double real, double imaginary);
+
+ /**
+ * Adds an argument with the given string/character as value.
+ *
+ * <p>The Java String value is transformed into an R data object
+ * of type {@link RStore#CHARACTER character}.</p>
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @param character the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addChar(String arg, String character);
+
+ /**
+ * Adds an unnamed argument with the given string/character as value.
+ *
+ * <p>The Java String value is transformed into an R data object
+ * of type {@link RStore#CHARACTER character}.</p>
+ *
+ * @param character the value of the argument
+ * @return a reference to this object
+ */
+ FunctionCall addChar(String character);
+
+ /**
+ * Adds an argument with the given NULL as value.
+ *
+ * <p>The Java String value is transformed into an R data
+ * {@link RObject#NULL NULL} object.</p>
+ *
+ * @param arg the name of the argument or <code>null</code> for unnamed
+ * @return a reference to this object
+ */
+ FunctionCall addNull(String arg);
+
+ /**
+ * Adds an unnamed argument with the given NULL as value.
+ *
+ * <p>The Java String value is transformed into an R data
+ * {@link RObject#NULL NULL} object.</p>
+ *
+ * @return a reference to this object
+ */
+ FunctionCall addNull();
+
+
+ /**
+ * Performs the evaluation of this function call in R without returning a value.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>The evaluation is performed in the global environment of R.</p>
+ *
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ void evalVoid(IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of this function call in R without returning a value.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>This method allows advanced configuration for the evaluation.</p>
+ *
+ * @param envir the environment where to perform the evaluation; specified by an reference
+ * or language object, or <code>null</code> for the global environment
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ *
+ * @since de.walware.rj.services 2.1
+ */
+ void evalVoid(RObject envir, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the this function call in R and returns its value as R data object.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>This is a short version of {@link #evalData(String, int, int, IProgressMonitor)}
+ * sufficient for most purpose. The returned R data objects are created by the default factory
+ * with no limit in the object tree depth.</p>
+ *
+ * <p>The evaluation is performed in the global environment of R.</p>
+ *
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the evaluated value as R data object
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ RObject evalData(IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the this function call in R and returns its value as R data object.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>This method allows advanced configuration for the returned R data object.</p>
+ *
+ * <p>The evaluation is performed in the global environment of R.</p>
+ *
+ * @param factoryId the id of the factory to use when creating the RObject in this VM.
+ * @param options 0
+ * @param depth object tree depth for the created return value
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the evaluated value as R data object
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ RObject evalData(String factoryId, int options, int depth,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the this function call in R and returns its value as R data object.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>This method allows advanced configuration for the evaluation and the returned R data
+ * object.</p>
+ *
+ * @param envir the environment where to perform the evaluation; specified by an reference
+ * or language object, or <code>null</code> for the global environment
+ * @param factoryId the id of the factory to use when creating the RObject in this VM.
+ * @param options 0
+ * @param depth object tree depth for the created return value
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the evaluated value as R data object
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ *
+ * @since de.walware.rj.services 2.1
+ */
+ RObject evalData(RObject envir, String factoryId, int options, int depth,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the this function call in R and assign its return value to
+ * the specified expression.
+ *
+ * <p>The target have to be a valid target expression for a R <code><-</code> assignment
+ * operation. A single symbol like <code>x</code> or <code>`x-y`</code>, a path in an object
+ * tree like <code>xlist$item1</code> or <code>xobj@slotName</code> is valid as well as
+ * special function calls which supports assignments like <code>dim(x)</code>.</p>
+ *
+ * <p>The evaluation and assignment is performed in the global environment of R.</p>
+ *
+ * @param target a single valid expression to assign the result to
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ *
+ * @since de.walware.rj.services 2.0
+ */
+ void evalAssign(String target, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RGraphicCreator.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RGraphicCreator.java
new file mode 100644
index 0000000..f7c3fdc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RGraphicCreator.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+
+
+/**
+ * Controls the creation of {@link RGraphic}.
+ *
+ * The creator can be access by {@link RService#createRGraphicCreator(int)}.
+ * A creator can be used multiple times for different graphics. Properties
+ * are reused and not reseted.
+ *
+ * @noimplement This interface is not intended to be implemented by clients.
+ * @since de.walware.rj.services 0.5
+ */
+public interface RGraphicCreator {
+
+ /**
+ * Sets the size in pixel of the graphic to create.
+ *
+ * @param width width in pixel
+ * @param height height in pixel
+ */
+ void setSize(double width, double height);
+
+ RGraphic create(String expression, IProgressMonitor monitor) throws CoreException;
+
+ RGraphic create(FunctionCall fcall, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RJServices.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RJServices.java
new file mode 100644
index 0000000..6987a75
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RJServices.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+
+public class RJServices {
+
+
+ public static final String BUNDLE_ID= "org.eclipse.statet.rj.services"; //$NON-NLS-1$
+
+
+ private RJServices() {
+ }
+
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RPlatform.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RPlatform.java
new file mode 100644
index 0000000..917ad20
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RPlatform.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+import org.osgi.framework.Version;
+
+
+/**
+ * Information about the platform R is running on
+ * and the running R version.
+ *
+ * The properties usually doesn't change for a single RService
+ * instance.
+ */
+public final class RPlatform implements Externalizable {
+
+ /**
+ * OS type constant for windows operation systems
+ */
+ public static final String OS_WINDOWS= "windows";
+
+ /**
+ * OS type constant for unix operation systems
+ */
+ public static final String OS_UNIX= "unix";
+
+
+ private String osType;
+
+ private String fileSep;
+ private String pathSep;
+
+ private String versionString;
+ private transient Version version;
+
+ private String osName;
+ private String osArch;
+ private String osVersion;
+
+
+ public RPlatform() {
+ }
+
+ public RPlatform(final String osType, final String fileSep, final String pathSep,
+ final String version,
+ final String osName, final String osArch, final String osVersion) {
+ this.osType= osType;
+ this.fileSep= fileSep;
+ this.pathSep= pathSep;
+ this.versionString= version;
+
+ this.osName= osName;
+ this.osArch= osArch;
+ this.osVersion= osVersion;
+ }
+
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ this.osType= in.readUTF();
+ this.fileSep= in.readUTF();
+ this.pathSep= in.readUTF();
+ this.versionString= in.readUTF();
+
+ this.osName= in.readUTF();
+ this.osArch= in.readUTF();
+ this.osVersion= in.readUTF();
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeUTF(this.osType);
+ out.writeUTF(this.fileSep);
+ out.writeUTF(this.pathSep);
+ out.writeUTF(this.versionString);
+
+ out.writeUTF(this.osName);
+ out.writeUTF(this.osArch);
+ out.writeUTF(this.osVersion);
+ }
+
+
+ /**
+ * The OS type as defined in R <code>.Platform$OS.type</code>
+ *
+ * @see #OS_WINDOWS
+ * @see #OS_UNIX
+ *
+ * @return the os type constant
+ */
+ public String getOsType() {
+ return this.osType;
+ }
+
+ public String getFileSep() {
+ return this.fileSep;
+ }
+
+ public String getPathSep() {
+ return this.pathSep;
+ }
+
+ public Version getRVersion() {
+ if (this.version == null) {
+ this.version= new Version(this.versionString);
+ }
+ return this.version;
+ }
+
+
+ /**
+ * The OS name as defined by the Java property <code>os.name</code>
+ *
+ * @return the OS name string
+ */
+ public String getOSName() {
+ return this.osName;
+ }
+
+ /**
+ * The OS architecture as defined by the Java property <code>os.arch</code>
+ *
+ * @return the OS architecture string
+ */
+ public String getOSArch() {
+ return this.osArch;
+ }
+
+ /**
+ * The OS version as defined by the Java property <code>os.version</code>
+ *
+ * @return the OS version string
+ */
+ public String getOSVersion() {
+ return this.osVersion;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RService.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RService.java
new file mode 100644
index 0000000..edc4e69
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RService.java
@@ -0,0 +1,350 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+
+
+/**
+ * A interface with methods to evaluate and exchange data with R.
+ * <p>
+ * It depends on the application how to get access to the RService.
+ * In StatET it is passed as adapter argument in
+ * {@link org.eclipse.statet.ecommons.ts.core.IToolRunnable#run(org.eclipse.statet.ecommons.ts.core.IToolService, IProgressMonitor) IToolRunnable#run(...)},
+ * if the R console supports the featureset {@link org.eclipse.statet.r.core.tool.RTool#R_DATA_FEATURESET_ID RTool#R_DATA_FEATURESET_ID}.
+ * In applications using R in the background by the RServi library,
+ * the {@link org.eclipse.statet.rj.servi.RServi RServi} object provides the RService methods.</p>
+ * <p>
+ * If the application has also an console, the operations of an RService
+ * usually doesn't appears in the console. Even not recommended, it is possible
+ * to call special R functions like print which output is written to the console.
+ * It should absolutely avoided to use functions like <code>readline</code> which requires
+ * interaction with the console.</p>
+ * <p>
+ * The methods of an RService should not be called concurrently by different
+ * threads. The RService consumer have to make sure that the function calls
+ * are synchronized, if multiple thread have access to the same instance.
+ * Implementations of RService interface can perform checks too, but the consumer
+ * must not rely on that.</p>
+ * <p>
+ * Especially for longer evaluations, it is recommended that the application implements
+ * this synchronization in a way that the GUI is not blocked.
+ * In StatET both is guaranteed by a queue and a single execution thread for runnables.</p>
+ * <p>
+ * All data exchange methods are copy operations. So changes on R data objects in Java
+ * are not reflected in R and the other way round.</p>
+ * <p>
+ * In general it is not necessary to surround R expressions with try-catch or similar construction
+ * except the error object is expected as return value.</p>
+ *
+ * @since de.walware.rj.services 0.4
+ */
+public interface RService {
+
+
+ /**
+ * Value for depth parameters indicating that the depth is not limited.
+ *
+ * @since de.walware.rj.services 0.5
+ */
+ int DEPTH_INFINITE= -1;
+
+ /**
+ * Value for depth parameters indicating to create only the specified object itself.
+ *
+ * @since de.walware.rj.services 0.5
+ */
+ int DEPTH_ONE= 1;
+
+ /**
+ * Value for depth parameters indicating to create only a reference to the specified object.
+ *
+ * @since de.walware.rj.services 1.1
+ */
+ int DEPTH_REFERENCE= 0;
+
+
+ /**
+ * Option flag indication to load environments directly instead of the reference only.
+ *
+ * @since de.walware.rj.services 2.1
+ **/
+ int LOAD_ENVIR= 1 << 4;
+
+ /**
+ * Option flag indicating to eval all promises directly.
+ *
+ * @since de.walware.rj.services 2.1
+ **/
+ int LOAD_PROMISE= 1 << 5;
+
+
+ RPlatform getPlatform();
+
+ /**
+ * Performs the evaluation of the given expression in R without returning a value.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>The evaluation is performed in the global environment of R.</p>
+ *
+ * @param expression a single valid R expression to evaluate
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ void evalVoid(String expression, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the given expression in R without returning a value.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>This method allows advanced configuration for the evaluation.</p>
+ *
+ * @param expression a single valid R expression to evaluate
+ * @param envir the environment where to perform the evaluation; specified by an reference
+ * or language object, or <code>null</code> for the global environment
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback.
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ *
+ * @since de.walware.rj.services 2.1
+ */
+ void evalVoid(String expression, RObject envir, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the given expression in R and returns its value as R data object.
+ * The method returns after the evaluation is finished.
+ *
+ * <p>This is a short version of {@link #evalData(String, String, int, int, IProgressMonitor)}
+ * sufficient for most purpose. The returned R data objects are created by the default factory
+ * with no limit in the object tree depth.</p>
+ *
+ * <p>The evaluation is performed in the global environment of R.</p>
+ *
+ * @param expression a single valid R expression to evaluate
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the evaluated value as R data object
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ RObject evalData(String expression, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the given expression in R and returns its value. The method returns
+ * after the evaluation is finished.
+ *
+ * <p>This method allows advanced configuration for the returned R data object.</p>
+ *
+ * <p>The evaluation is performed in the global environment of R.</p>
+ *
+ * @param expression a single valid R expression to evaluate
+ * @param factoryId the id of the factory to use when creating the RObject in this VM.
+ * @param options 0
+ * @param depth object tree depth for the created return value
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the evaluated value as R data object
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ *
+ * @see #DEPTH_INFINITE
+ * @see #DEPTH_ONE
+ */
+ RObject evalData(String expression, String factoryId, int options, int depth,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the evaluation of the given expression in R and returns its value. The method
+ * returns after the evaluation is finished.
+ *
+ * <p>This method allows advanced configuration for the evaluation and the returned R data
+ * object.</p>
+ *
+ * @param expression a single valid R expression to evaluate
+ * @param envir the environment where to perform the evaluation; specified by an reference
+ * or language object, or <code>null</code> for the global environment
+ * @param factoryId the id of the factory to use when creating the RObject in this VM.
+ * @param options 0
+ * @param depth object tree depth for the created return value
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the evaluated value as R data object
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ *
+ * @since de.walware.rj.services 2.1
+ *
+ * @see #DEPTH_INFINITE
+ * @see #DEPTH_ONE
+ */
+ RObject evalData(String expression, RObject envir, String factoryId, int options, int depth,
+ IProgressMonitor monitor) throws CoreException;
+
+ RObject evalData(RReference reference, IProgressMonitor monitor) throws CoreException;
+ RObject evalData(RReference reference, String factoryId, int options, int depth,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Performs the assignment of the given R data object to an expression in R. The method returns
+ * after the assignment is finished.
+ *
+ * <p>The target have to be a valid target expression for a R <code><-</code> assignment
+ * operation. A single symbol like <code>x</code> or <code>`x-y`</code>, a path in an object
+ * tree like <code>xlist$item1</code> or <code>xobj@slotName</code> is valid as well as
+ * special function calls which supports assignments like <code>dim(x)</code>.</p>
+ *
+ * <p>The assignment is performed in the global environment of R.</p>
+ *
+ * @param target a single valid expression to assign the data to
+ * @param data a valid R data object to assign to the expression
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the evaluated value as R data object
+ * @throws CoreException if the operation was canceled or was failed; the status
+ * of the exception contains detail about the cause
+ */
+ void assignData(String target, RObject data, IProgressMonitor monitor) throws CoreException;
+
+// void assignDataToAttribute(String expression, String attributeName, RObject data, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Uploads a file or an other input stream to a file on the R host system.
+ * <p>
+ * The file name can be relative or absolute. A relative file name is handled relative
+ * to the current R working directory. An absolute file name must be a valid absolute
+ * path on the R host system.</p>
+ * <p>
+ * The input stream is not closed by the service.</p>
+ * <p>
+ * Typical pattern to upload a local file is:</p>
+ * <pre>
+ * FileInputStream in= null;
+ * try {
+ * in= new FileInputStream(localfile);
+ * rservice.uploadFile(in, localfile.length(), "data.xml", 0, monitor);
+ * }
+ * finally {
+ * if (in != null) {
+ * in.close();
+ * }
+ * }
+ * </pre>
+ *
+ * @param in an input stream providing the content of the file
+ * @param length the length of the content
+ * @param fileName the name of the file on the R host system
+ * @param options 0
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ void uploadFile(InputStream in, long length, String fileName, int options,
+ IProgressMonitor monitor) throws CoreException;
+
+// void uploadFile(byte[], long length, String fileName, int options, IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Downloads a file on the R host system to a local file or another output stream.
+ * <p>
+ * The file name can be relative or absolute. A relative file name is handled relative
+ * to the current R working directory. An absolute file name must be a valid absolute
+ * path on the R host system.</p>
+ * <p>
+ * The output stream is not closed by the service.</p>
+ * <p>
+ * Typical pattern to download to a local file is:</p>
+ * <pre>
+ * FileOutputStream out= null;
+ * try {
+ * out= new FileOutputStream(localfile);
+ * rservice.downloadFile(out, "data.xml", 0, monitor);
+ * }
+ * finally {
+ * if (out != null) {
+ * out.close();
+ * }
+ * }
+ * </pre>
+ *
+ * @param out the output stream to write the content of the file to
+ * @param fileName the name of the file on the R host system
+ * @param options 0
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ void downloadFile(OutputStream out, String fileName, int options,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Downloads a file on the R host system into a byte array.
+ * <p>
+ * The file name can be relative or absolute. A relative file name is handled relative
+ * to the current R working directory. An absolute file name must be a valid absolute
+ * path on the R host system.</p>
+ * <p>
+ * The byte array represents the content of the complete file; the array has the length of
+ * the file.</p>
+ *
+ * @param fileName the name of the file on the R host system
+ * @param options 0
+ * @param monitor a progress monitor to catch cancellation and provide progress feedback
+ * @return the file content
+ * @throws CoreException if the operation was canceled or failed; the status
+ * of the exception contains detail about the cause
+ */
+ byte[] downloadFile(String fileName, int options,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Creates a new function call builder for the specified function.
+ *
+ * <p>The builder is valid as long as the RService owns the consumer. After the service is for
+ * example closed, it must not longer be used.</p>
+ *
+ * @param name the name of the function, optional with prefix namespace
+ *
+ * @return a new function creator
+ * @throws CoreException if the operation failed; the status
+ * of the exception contains detail about the cause
+ */
+ FunctionCall createFunctionCall(String name) throws CoreException;
+
+ /**
+ * Creates a new creator for {@link RGraphic}s.
+ *
+ * <p>The default options are:</p><ul>
+ * <li>MANAGED_OFF: the graphic is not managed by this RService.
+ * Important: the caller is responsible to dispose the graphic.</li>
+ * <li>R_CLOSE_OFF: the graphic is not closed if the device is closed in R.</li>
+ * </ul>
+ *
+ * @param options optional options, <code>0</code> for default
+ * @return a new graphic creator
+ * @throws CoreException if the operation failed; the status
+ * of the exception contains detail about the cause
+ *
+ * @since de.walware.rj.services 0.5
+ */
+ RGraphicCreator createRGraphicCreator(int options) throws CoreException;
+// void beginCatchRGraphics(int options);
+// Map<String, RGraphic> endCatchRGraphics();
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RServiceControlExtension.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RServiceControlExtension.java
new file mode 100644
index 0000000..bff3264
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/RServiceControlExtension.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.locks.Lock;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+
+/**
+ *
+ * @provisional
+ */
+public interface RServiceControlExtension {
+
+ /**
+ * Adds a cancel handler called when the tool is canceled to the stack of cancel handlers.
+ * <p>
+ * The cancel handler should return <code>true</code> if the cancel event was handled
+ * completely and the other handlers will not be called.</p>
+ *
+ * @param handler the handler
+ */
+ void addCancelHandler(Callable<Boolean> handler);
+
+ /**
+ * Removes a cancel handler from the stack of cancel handlers.
+ *
+ * @param handler the handler
+ */
+ void removeCancelHandler(Callable<Boolean> handler);
+
+ /**
+ * The lock for wait operations.
+ *
+ * @return the lock
+ */
+ Lock getWaitLock();
+
+ /**
+ * Waits in the current tool thread.
+ * <p>
+ * If short background operations are waiting for execution, they are executed (depends on
+ * implementation).</p>
+ * <p>
+ * The current thread must hold the lock {@link #getWaitLock()}. The method returns after a
+ * short waiting time, operations are executed <b>or</b> {@link #resume()} is called.</p>
+ *
+ * @param monitor the current monitor
+ */
+ void waitingForUser(IProgressMonitor monitor);
+
+ /**
+ * Resumes the tool thread which is waiting in {@link #waitingForUser(IProgressMonitor)}.
+ */
+ void resume();
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/Graphic.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/Graphic.java
new file mode 100644
index 0000000..c34776d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/Graphic.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import java.io.OutputStream;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+public abstract class Graphic {
+
+
+ public static final String UNIT_PX= "px";
+ public static final String UNIT_IN= "in";
+ public static final String UNIT_CM= "cm";
+ public static final String UNIT_MM= "mm";
+
+
+ String sizeUnit;
+ double sizeWidth;
+ double sizeHeight;
+
+ int resolution= -1;
+
+
+ protected Graphic() {
+ }
+
+
+ /**
+ * Sets the size of the graphic.
+ *
+ * The unit can be one of the constants with prefix UNIT_ .
+ * The default is pixel for raster graphic images (png) and inch for vector images (pdf).
+ *
+ * @param width the width in the given unit
+ * @param height the height in the given unit
+ * @param unit the unit of width and height arguments
+ */
+ public void setSize(final double width, final double height, final String unit) {
+ this.sizeWidth= width;
+ this.sizeHeight= height;
+ this.sizeUnit= unit;
+ }
+
+ /**
+ * Sets the nominal resolution in dpi of the graphic.
+ *
+ * @param resolution the resolution in dpi
+ */
+ public void setResolution(final int resolution) {
+ this.resolution= resolution;
+ }
+
+
+ public byte[] create(final FunctionCall plot, final RService service, final IProgressMonitor monitor) throws CoreException {
+ final String filename= "plot-"+System.nanoTime()+".plot";
+ prepare(filename, service, monitor);
+ plot.evalVoid(monitor);
+ service.evalVoid("dev.off()", monitor);
+ return service.downloadFile(filename, 0, monitor);
+ }
+
+ public void create(final FunctionCall plot, final OutputStream out, final RService service, final IProgressMonitor monitor) throws CoreException {
+ final String filename= "plot-"+System.nanoTime()+".plot";
+ prepare(filename, service, monitor);
+ plot.evalVoid(monitor);
+ service.evalVoid("dev.off()", monitor);
+ service.downloadFile(out, filename, 0, monitor);
+ }
+
+ public byte[] create(final String plotCommand, final RService service, final IProgressMonitor monitor) throws CoreException {
+ final String filename= "plot-"+System.nanoTime()+".plot";
+ prepare(filename, service, monitor);
+ service.evalVoid(plotCommand, monitor);
+ service.evalVoid("dev.off()", monitor);
+ return service.downloadFile(filename, 0, monitor);
+ }
+
+ public void create(final String plotCommand, final OutputStream out, final RService service, final IProgressMonitor monitor) throws CoreException {
+ final String filename= "plot-"+System.nanoTime()+".plot";
+ prepare(filename, service, monitor);
+ service.evalVoid(plotCommand, monitor);
+ service.evalVoid("dev.off()", monitor);
+ service.downloadFile(out, filename, 0, monitor);
+ }
+
+ protected abstract void prepare(String filename, RService service, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PdfGraphic.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PdfGraphic.java
new file mode 100644
index 0000000..3d736e8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PdfGraphic.java
@@ -0,0 +1,63 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class PdfGraphic extends Graphic {
+
+
+ public PdfGraphic() {
+ }
+
+
+ @Override
+ public void setSize(final double width, final double height, final String unit) {
+ if (UNIT_PX.equals(unit)) {
+ throw new IllegalArgumentException("Pixel not supported by PDF graphic.");
+ }
+ super.setSize(width, height, unit);
+ }
+
+ @Override
+ protected void prepare(final String filename, final RService service, final IProgressMonitor monitor) throws CoreException {
+ final FunctionCall png= service.createFunctionCall("pdf"); //$NON-NLS-1$
+ png.addChar("file", filename); //$NON-NLS-1$
+ if (this.resolution > 0) {
+ png.addInt("res", this.resolution); //$NON-NLS-1$
+ }
+ if (this.sizeUnit != null) {
+ if (this.sizeUnit.equals(UNIT_IN)) {
+ png.addNum("width", this.sizeWidth); //$NON-NLS-1$
+ png.addNum("height", this.sizeHeight); //$NON-NLS-1$
+ }
+ else if (this.sizeUnit.equals(UNIT_CM)) {
+ png.addNum("width", this.sizeWidth/2.54); //$NON-NLS-1$
+ png.addNum("height", this.sizeHeight/2.54); //$NON-NLS-1$
+ }
+ else if (this.sizeUnit.equals(UNIT_MM)) {
+ png.addNum("width", this.sizeWidth/25.4); //$NON-NLS-1$
+ png.addNum("height", this.sizeHeight/25.4); //$NON-NLS-1$
+ }
+ }
+ png.evalVoid(monitor);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PngGraphic.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PngGraphic.java
new file mode 100644
index 0000000..7a8c660
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/PngGraphic.java
@@ -0,0 +1,50 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class PngGraphic extends Graphic {
+
+
+ public PngGraphic() {
+ }
+
+
+ @Override
+ protected void prepare(final String filename, final RService service, final IProgressMonitor monitor) throws CoreException {
+ final FunctionCall png= service.createFunctionCall("png");
+ png.addChar("filename", filename);
+ if (this.resolution > 0) {
+ png.addInt("res", this.resolution);
+ }
+ if (this.sizeUnit != null) {
+ png.addNum("width", this.sizeWidth);
+ png.addNum("height", this.sizeHeight);
+ png.addChar("unit", this.sizeUnit);
+ }
+ if (service.getPlatform().getOsType().equals(RPlatform.OS_WINDOWS)) {
+ png.addLogi("restoreConsole", false);
+ }
+ png.evalVoid(monitor);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/RPkgInstallation.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/RPkgInstallation.java
new file mode 100644
index 0000000..6d4a19d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/RPkgInstallation.java
@@ -0,0 +1,180 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RIntegerStore;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.renv.core.RNumVersion;
+import org.eclipse.statet.rj.renv.core.RPkg;
+import org.eclipse.statet.rj.renv.core.RPkgType;
+import org.eclipse.statet.rj.renv.core.RPkgUtils;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RJServices;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Utility to install an R package from a local file.
+ * <p>
+ * Run {@link #install(RService, IProgressMonitor)} to install the package.</p>
+ * <p>
+ * The class can be reused.</p>
+ *
+ * @since de.walware.rj.services 2.0
+ */
+public class RPkgInstallation {
+
+
+ private final RPkg pkgInfo;
+
+ private final File file;
+
+
+ public RPkgInstallation(final File file) throws CoreException {
+ if (file == null) {
+ throw new NullPointerException();
+ }
+ this.pkgInfo= RPkgUtils.checkPkgFileName(file.getName());
+ this.file= file;
+ }
+
+
+ public RPkg getPkg() {
+ return this.pkgInfo;
+ }
+
+ protected String getPkgFileName() {
+ return this.file.getName();
+ }
+
+ protected void uploadPkgFile(final String target, final RService r,
+ final IProgressMonitor monitor) throws CoreException, IOException {
+ FileInputStream in= null;
+ try {
+ in= new FileInputStream(this.file);
+ r.uploadFile(in, this.file.length(), target, 0, monitor);
+ }
+ finally {
+ if (in != null) {
+ try {
+ in.close();
+ }
+ catch (final IOException e) {}
+ }
+ }
+ }
+
+ public void install(final RService r, final IProgressMonitor monitor) throws CoreException {
+ final String source= getPkgFileName();
+ final RPkgType pkgType= RPkgUtils.checkPkgType(source, r.getPlatform());
+
+ Exception error= null;
+ String serverFile= null;
+ String libLoc= null;
+ try {
+ { final RVector<RIntegerStore> data= RDataUtils.checkRIntVector(r.evalData(
+ "rj:::renv.isValidLibLoc(.libPaths()[1])", monitor )); //$NON-NLS-1$
+ final int state= RDataUtils.checkSingleIntValue(data);
+ libLoc= data.getNames().getChar(0);
+ if (state != 0) {
+ throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+ MessageFormat.format("The library location ''{0}'' is not writable.", libLoc) ));
+ }
+ }
+
+ { final FunctionCall call= r.createFunctionCall("dir.create"); //$NON-NLS-1$
+ call.addChar("rpkgs"); //$NON-NLS-1$
+ call.addLogi("showWarnings", false); //$NON-NLS-1$
+ call.evalVoid(monitor);
+
+ serverFile= "rpkgs/" + source; //$NON-NLS-1$
+ }
+
+ uploadPkgFile(serverFile, r, monitor);
+
+ { final FunctionCall call= r.createFunctionCall("install.packages"); //$NON-NLS-1$
+ call.addChar(serverFile);
+ call.addChar("lib", libLoc); //$NON-NLS-1$
+ call.addNull("repos"); //$NON-NLS-1$
+ call.addChar("type", RPkgUtils.getPkgTypeInstallKey(r.getPlatform(), pkgType)); //$NON-NLS-1$
+ call.evalVoid(monitor);
+ }
+
+ { final FunctionCall call= r.createFunctionCall("packageDescription"); //$NON-NLS-1$
+ call.addChar("pkg", this.pkgInfo.getName()); //$NON-NLS-1$
+ call.addChar("lib.loc", libLoc); //$NON-NLS-1$
+ call.addChar("fields", "Version"); //$NON-NLS-1$ //$NON-NLS-2$
+ final RVector<?> data= RDataUtils.checkRVector(call.evalData(monitor));
+ try {
+ final String s= RDataUtils.checkSingleCharValue(data);
+ final RNumVersion installedVersion= RNumVersion.create(s);
+ if (!installedVersion.equals(this.pkgInfo.getVersion())) {
+ throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+ MessageFormat.format("Validation of package installation failed: installed package has different version (found= {0}, expected= {1}).",
+ installedVersion.toString(), this.pkgInfo.getVersion().toString() )));
+ }
+ }
+ catch (final UnexpectedRDataException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+ "Validation of package installation failed: no installed package found." ));
+ }
+ }
+
+ clear(serverFile, r, monitor);
+ serverFile= null;
+ }
+ catch (final IOException e) {
+ error= e;
+ }
+ catch (final CoreException e) {
+ error= e;
+ }
+ catch (final UnexpectedRDataException e) {
+ error= e;
+ }
+ finally {
+ if (serverFile != null) {
+ try {
+ clear(serverFile, r, monitor);
+ }
+ catch (final Exception e) {}
+ }
+ }
+ if (error != null) {
+ throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+ MessageFormat.format("An error occurred when installing R package from {0}.",
+ source), error ));
+ }
+ }
+
+ private void clear(final String target, final RService r, final IProgressMonitor monitor) throws CoreException {
+ final FunctionCall call= r.createFunctionCall("file.remove"); //$NON-NLS-1$
+ call.addChar(target);
+ call.evalVoid(monitor);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/AbstractRDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/AbstractRDataAdapter.java
new file mode 100644
index 0000000..0ec2ef8
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/AbstractRDataAdapter.java
@@ -0,0 +1,170 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+import org.eclipse.statet.rj.services.FQRObjectRef;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Adapter interface to load R data in one- or two-dimensional fragments.
+ *
+ * @param <TRObject> type of R object
+ * @param <TFragmentObject> type of R object value fragments
+ * @since 2.0 (provisional)
+ */
+public abstract class AbstractRDataAdapter<TRObject extends RObject, TFragmentObject extends RObject> {
+
+
+ public static final int ROW_COUNT= 1 << 0;
+ public static final int STORE_TYPE= 1 << 2;
+
+ protected static final String API_R_PREFIX= "rj:::sda002"; //$NON-NLS-1$
+
+
+ protected static void addXRef(final FunctionCall fcall, final FQRObjectRef ref) {
+ fcall.add("x.env", ref.getEnv()); //$NON-NLS-1$
+ fcall.add("x.expr", DefaultRObjectFactory.INSTANCE.createExpression( //$NON-NLS-1$
+ "x.env$" + ((RLanguage) ref.getName()).getSource() )); //$NON-NLS-1$
+ }
+
+
+ public abstract TRObject validate(RObject rObject)
+ throws UnexpectedRDataException;
+ public abstract TRObject validate(RObject rObject, TRObject referenceObject, int flags)
+ throws UnexpectedRDataException;
+
+ public abstract long getRowCount(TRObject rObject);
+ public abstract long getColumnCount(TRObject rObject);
+
+
+ public void check(final FQRObjectRef ref, final TRObject referenceObject,
+ final RService r, final IProgressMonitor monitor) throws CoreException,
+ UnexpectedRDataException {
+ final RObject result;
+ { final FunctionCall fcall= r.createFunctionCall(API_R_PREFIX + ".checkDataStruct"); //$NON-NLS-1$
+ addXRef(fcall, ref);
+ fcall.addChar("xClass1", referenceObject.getRClassName()); //$NON-NLS-1$
+ fcall.add("xDim", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+ getRowCount(referenceObject),
+ getColumnCount(referenceObject),
+ }));
+ result= fcall.evalData(monitor);
+ }
+ if (RDataUtils.checkSingleLogiValue(result) == false) {
+ throw new UnexpectedRDataException("It seems something changed.");
+ }
+ }
+
+ public TFragmentObject loadData(final FQRObjectRef ref, final TRObject referenceObject,
+ final LazyRStore.Fragment<TFragmentObject> fragment, final String rowMapping,
+ final RService r,
+ final IProgressMonitor monitor) throws CoreException, UnexpectedRDataException {
+ final RObject fragmentObject;
+ { final FunctionCall fcall= r.createFunctionCall(getLoadDataFName());
+ addXRef(fcall, ref);
+ fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+ fragment.getRowBeginIdx() + 1,
+ fragment.getRowEndIdx(),
+ fragment.getColumnBeginIdx() + 1,
+ fragment.getColumnEndIdx(),
+ }));
+ if (rowMapping != null) {
+ fcall.addChar("rowMapping", rowMapping); //$NON-NLS-1$
+ }
+
+ fragmentObject= fcall.evalData(monitor);
+ }
+
+ return validateData(fragmentObject, referenceObject, fragment);
+ }
+
+ protected abstract String getLoadDataFName();
+
+ protected abstract TFragmentObject validateData(RObject rObject, TRObject referenceObject,
+ LazyRStore.Fragment<TFragmentObject> fragment)
+ throws UnexpectedRDataException;
+
+ public void setData(final FQRObjectRef ref, final TRObject referenceObject,
+ final RDataAssignment assignment, final String rowMapping,
+ final RService r,
+ final IProgressMonitor monitor) throws CoreException, UnexpectedRDataException {
+ { final FunctionCall fcall= r.createFunctionCall(getSetDataFName());
+ addXRef(fcall, ref);
+ fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+ assignment.getRowBeginIdx() + 1,
+ assignment.getRowEndIdx(),
+ assignment.getColumnBeginIdx() + 1,
+ assignment.getColumnEndIdx(),
+ }));
+ if (rowMapping != null) {
+ fcall.addChar("rowMapping", rowMapping); //$NON-NLS-1$
+ }
+ fcall.add("values", DefaultRObjectFactory.INSTANCE.createVector( //$NON-NLS-1$
+ assignment.getData() ));
+
+ fcall.evalVoid(monitor);
+ }
+ }
+
+ protected abstract String getSetDataFName();
+
+ public RVector<?> loadRowNames(final FQRObjectRef ref, final TRObject referenceObject,
+ final LazyRStore.Fragment<RVector<?>> fragment, final String rowMapping,
+ final RService r, final IProgressMonitor monitor) throws CoreException,
+ UnexpectedRDataException {
+ final RObject fragmentObject;
+ { final FunctionCall fcall= r.createFunctionCall(getLoadRowNamesFName());
+ addXRef(fcall, ref);
+ fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+ fragment.getRowBeginIdx() + 1,
+ fragment.getRowEndIdx(),
+ }));
+ if (rowMapping != null) {
+ fcall.addChar("rowMapping", rowMapping); //$NON-NLS-1$
+ }
+
+ fragmentObject= fcall.evalData(monitor);
+ }
+
+ return validateRowNames(fragmentObject, referenceObject, fragment);
+ }
+
+ protected abstract String getLoadRowNamesFName();
+
+ protected RVector<?> validateRowNames(final RObject rObject, final TRObject referenceObject,
+ final LazyRStore.Fragment<RVector<?>> fragment)
+ throws UnexpectedRDataException {
+ if (rObject.getRObjectType() == RObject.TYPE_NULL) {
+ return null;
+ }
+
+ final RVector<?> vector= RDataUtils.checkRVector(rObject);
+ RDataUtils.checkLengthEqual(vector.getData(), fragment.getRowCount());
+
+ return vector;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/LazyRStore.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/LazyRStore.java
new file mode 100644
index 0000000..6203829
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/LazyRStore.java
@@ -0,0 +1,448 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ *
+ *
+ * @param <V> type of R object fragments
+ * @since 2.0 (provisional)
+ */
+public class LazyRStore<V> {
+
+
+ public final static int DEFAULT_FRAGMENT_SIZE= 2500;
+
+ public final static class Fragment<W> extends RDataSubset {
+
+ private static final byte SCHEDULED= (byte) 1 << 0;
+ private static final byte SET= (byte) 1 << 1;
+
+ /** sequential number of fragments, first by fragment col, then by fragment row */
+ private final long number;
+
+ private W rObject;
+
+ private Fragment<W> newer;
+ private Fragment<W> older;
+
+ private byte state;
+
+
+ Fragment(final long number,
+ final long rowBeginIdx, final long rowCount,
+ final long columnBeginIdx, final long columnCount) {
+ super(rowBeginIdx, rowCount, columnBeginIdx, columnCount);
+ this.number= number;
+ }
+
+
+ /**
+ * Returns the R object for this fragment.
+ *
+ * @return the R object for this fragment or <code>null</code>, if not available.
+ */
+ public W getRObject() {
+ return this.rObject;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder("LazyRStore$Fragment "); //$NON-NLS-1$
+ sb.append(this.number);
+ sb.append("\n\trows= ").append(getRowBeginIdx()).append("...").append(getRowEndIdx()); //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append("\n\tcolumns= ").append(getColumnBeginIdx()).append("...").append(getColumnEndIdx()); //$NON-NLS-1$ //$NON-NLS-2$
+ return sb.toString();
+ }
+
+ }
+
+
+ public static final int FORCE_SYNC= 1 << 0;
+
+ public static interface Updater<T> {
+
+
+ void scheduleUpdate(LazyRStore<T> store,
+ RDataAssignment assignment, Fragment<T> fragment,
+ int flags, IProgressMonitor monitor);
+
+ }
+
+
+ private final long columnCount;
+ private long rowCount;
+
+ private final int maxFragmentCount;
+ private Fragment<V>[] fragments;
+ private int currentFragmentCount= 0;
+ private final Fragment<V> topFragment= new Fragment<>(-1, 0, 0, 0, 0);
+ private final Fragment<V> bottomFragment= new Fragment<>(-1, 0, 0, 0, 0);
+
+ private final int fragmentRowCount;
+ private final int fragmentColCount;
+ private final long fragmentCountInRow;
+
+ private final List<RDataAssignment> assignments= new ArrayList<>();
+
+ private int scheduledCount;
+ private Fragment<V> scheduleNext;
+ private Updater<V> updater;
+
+
+ public LazyRStore(final long rowCount, final long columnCount,
+ final int maxFragmentCount,
+ final Updater<V> updater) {
+ this(rowCount, columnCount, maxFragmentCount, DEFAULT_FRAGMENT_SIZE, updater);
+ }
+
+ public LazyRStore(final long rowCount, final long columnCount,
+ final int maxFragmentCount, final int fragmentSize,
+ final Updater<V> updater) {
+ this.columnCount= columnCount;
+
+ this.maxFragmentCount= maxFragmentCount;
+
+ this.fragmentColCount= (int) Math.min(columnCount, 25);
+ this.fragmentCountInRow= (columnCount - 1) / this.fragmentColCount + 1;
+ this.fragmentRowCount= fragmentSize / this.fragmentColCount;
+
+ this.updater= updater;
+
+ init(rowCount);
+ }
+
+ public LazyRStore(final long rowCount, final long columnCount,
+ final int maxFragmentCount,
+ final int fragmentRowCount, final int fragmentColCount,
+ final Updater<V> updater) {
+ this.columnCount= columnCount;
+
+ this.maxFragmentCount= maxFragmentCount;
+
+ this.fragmentColCount= fragmentColCount;
+ this.fragmentCountInRow= (columnCount - 1) / fragmentColCount + 1;
+ this.fragmentRowCount= fragmentRowCount;
+
+ this.updater= updater;
+
+ init(rowCount);
+ }
+
+ private void init(final long rowCount) {
+ this.fragments= new Fragment[Math.min(16, this.maxFragmentCount)];
+
+ clear(rowCount);
+ }
+
+ private long getNumber(final long rowIdx, final long columnIdx) {
+ return (rowIdx / this.fragmentRowCount) * this.fragmentCountInRow +
+ (columnIdx / this.fragmentColCount);
+ }
+
+
+ public LazyRStore.Fragment<V> getFragment(final long rowIdx, final long columnIdx,
+ final int flags, final IProgressMonitor monitor) {
+ if (rowIdx >= this.rowCount) {
+ return null;
+ }
+ final long number= getNumber(rowIdx, columnIdx);
+ final Fragment<V> fragment= getFragment(number, true);
+
+ if ((fragment.state & Fragment.SET) != 0) {
+ return fragment;
+ }
+
+ final boolean scheduleUpdate= (this.scheduledCount == 0);
+
+ this.scheduleNext= this.topFragment;
+
+ if ((fragment.state & Fragment.SCHEDULED) == 0) {
+ fragment.state= Fragment.SCHEDULED;
+ this.scheduledCount++;
+ }
+
+ if (scheduleUpdate || (flags & FORCE_SYNC) != 0) {
+ this.updater.scheduleUpdate(this, null, fragment, flags, monitor);
+
+ if ((fragment.state & Fragment.SET) != 0) {
+ return fragment;
+ }
+ }
+
+ return null;
+ }
+
+ public LazyRStore.Fragment<V> getLoadedFragment(final long rowIdx, final long columnIdx) {
+ if (rowIdx >= this.rowCount) {
+ return null;
+ }
+ final long number= getNumber(rowIdx, columnIdx);
+ final Fragment<V> fragment= getFragment(number, false);
+
+ if ((fragment.state & Fragment.SET) != 0) {
+ return fragment;
+ }
+ return null;
+ }
+
+ public LazyRStore.Fragment<V> getLoadedFragmentAny() {
+ Fragment<V> fragment= this.topFragment;
+ while (fragment != null) {
+ if ((fragment.state & Fragment.SET) != 0) {
+ return fragment;
+ }
+ fragment= fragment.older;
+ }
+ return null;
+ }
+
+ public void set(final RDataAssignment assignment,
+ final int flags, final IProgressMonitor monitor) {
+ final Fragment<V> fragment= clear(assignment);
+ this.assignments.add(assignment);
+
+ final boolean scheduleUpdate= (this.scheduledCount == 0);
+
+ this.scheduledCount++; // assignment
+
+ if (fragment != null) {
+ fragment.state= Fragment.SCHEDULED;
+ this.scheduledCount++;
+ }
+
+ if (scheduleUpdate) {
+ this.updater.scheduleUpdate(this, assignment, fragment, flags, monitor);
+ }
+ }
+
+ public Fragment<V> clear(final RDataSubset subset) {
+ Fragment<V> firstFragment= null;
+ long columnBeginIdx= (subset.getColumnBeginIdx() / this.fragmentColCount) * this.fragmentColCount;
+ while (columnBeginIdx < subset.getColumnEndIdx()) {
+ long rowBeginIdx= (subset.getRowBeginIdx() / this.fragmentRowCount) * this.fragmentRowCount;
+ while (rowBeginIdx < subset.getRowEndIdx()) {
+ final long number= getNumber(rowBeginIdx, columnBeginIdx);
+ final int idx= indexOf(number);
+ if (idx >= 0) {
+ final Fragment<V> fragment= clearFragment(idx);
+ if (firstFragment == null) {
+ firstFragment= fragment;
+ }
+ }
+ rowBeginIdx= Math.min(rowBeginIdx + this.fragmentRowCount, this.rowCount);
+ }
+ columnBeginIdx= Math.min(columnBeginIdx + this.fragmentColCount, this.columnCount);
+ }
+ return firstFragment;
+ }
+
+
+ private int indexOf(final long number) {
+ final Fragment<V>[] array= this.fragments;
+ int low= 0;
+ int high= this.currentFragmentCount;
+
+ while (low <= high) {
+ final int mid= (low + high) >> 1;
+ final Fragment<V> fragment= array[mid];
+
+ if (fragment.number < number) {
+ low= mid + 1;
+ }
+ else if (fragment.number > number) {
+ high= mid - 1;
+ }
+ else {
+ return mid;
+ }
+ }
+ return - (low + 1);
+ }
+
+ private Fragment<V> getFragment(final long number, final boolean create) {
+ if (this.topFragment.older.number == number) {
+ return this.topFragment.older;
+ }
+
+ final Fragment<V>[] array= this.fragments;
+ int low= 0;
+ { int high= this.currentFragmentCount - 1;
+ while (low <= high) {
+ final int mid= (low + high) >> 1;
+ final Fragment<V> fragment= array[mid];
+
+ if (fragment.number < number) {
+ low= mid + 1;
+ }
+ else if (fragment.number > number) {
+ high= mid - 1;
+ }
+ else {
+ fragment.newer.older= fragment.older;
+ fragment.older.newer= fragment.newer;
+ fragment.newer= this.topFragment;
+ fragment.older= this.topFragment.older;
+ this.topFragment.older.newer= fragment;
+ this.topFragment.older= fragment;
+ return fragment;
+ }
+ }
+ }
+ if (!create) {
+ return null;
+ }
+
+ final Fragment<V> fragment= createFragment(number);
+ { if (array.length == this.currentFragmentCount) {
+ this.fragments= new Fragment[Math.min(this.currentFragmentCount * 2, this.maxFragmentCount)];
+ System.arraycopy(array, 0, this.fragments, 0, low);
+ }
+ System.arraycopy(array, low, this.fragments, low + 1, this.currentFragmentCount - low);
+ this.fragments[low]= fragment;
+ this.currentFragmentCount++;
+ }
+
+ fragment.newer= this.topFragment;
+ fragment.older= this.topFragment.older;
+ this.topFragment.older.newer= fragment;
+ this.topFragment.older= fragment;
+
+ if (this.currentFragmentCount >= this.maxFragmentCount) {
+ removeOldestFragment();
+ }
+
+ return fragment;
+ }
+
+ private Fragment<V> createFragment(final long number) {
+ final long rowBeginIdx= (number / this.fragmentCountInRow) * this.fragmentRowCount;
+ final long rowEndIdx= Math.min(rowBeginIdx + this.fragmentRowCount, this.rowCount);
+ final long columnBeginIdx= (number % this.fragmentCountInRow) * this.fragmentColCount;
+ final long columnEndIdx= Math.min(columnBeginIdx + this.fragmentColCount, this.columnCount);
+ return new Fragment<>(number,
+ rowBeginIdx, (rowEndIdx - rowBeginIdx),
+ columnBeginIdx, (columnEndIdx - columnBeginIdx) );
+ }
+
+ private Fragment<V> clearFragment(final int idx) {
+ final Fragment<V> oldFragment= this.fragments[idx];
+ final Fragment<V> newFragment= new Fragment<>(oldFragment.number,
+ oldFragment.getRowBeginIdx(), oldFragment.getRowCount(),
+ oldFragment.getColumnBeginIdx(), oldFragment.getColumnCount() );
+ if (oldFragment.newer != null) {
+ newFragment.newer= oldFragment.newer;
+ newFragment.newer.older= newFragment;
+ }
+ if (oldFragment.older != null) {
+ newFragment.older= oldFragment.older;
+ newFragment.older.newer= newFragment;
+ }
+ return this.fragments[idx]= newFragment;
+ }
+
+ private void removeOldestFragment() {
+ final Fragment<V> fragment= this.bottomFragment.newer;
+ if ((fragment.state & Fragment.SCHEDULED) != 0) {
+ fragment.state &= ~Fragment.SCHEDULED;
+ this.scheduledCount--;
+ }
+ if (this.scheduleNext == fragment) {
+ this.scheduleNext= fragment.older;
+ }
+
+ final int idx= indexOf(fragment.number);
+ this.currentFragmentCount--;
+ System.arraycopy(this.fragments, idx + 1, this.fragments, idx, this.currentFragmentCount - idx);
+ this.fragments[this.currentFragmentCount]= null;
+
+ fragment.newer.older= this.bottomFragment;
+ this.bottomFragment.newer= fragment.newer;
+ fragment.newer= null;
+ fragment.older= null;
+ return;
+ }
+
+
+ public void clear(final long rowCount) {
+ final Fragment<V>[] array= this.fragments;
+ for (int i= 0; i < this.currentFragmentCount; i++) {
+ array[i].state &= ~Fragment.SCHEDULED;
+ array[i]= null;
+ }
+ this.currentFragmentCount= 0;
+ this.topFragment.older= this.bottomFragment;
+ this.bottomFragment.newer= this.topFragment;
+
+ this.scheduledCount= 0;
+ this.scheduleNext= this.topFragment;
+
+ if (rowCount >= 0) {
+ this.rowCount= rowCount;
+ }
+ }
+
+ public Fragment<V>[] getScheduledFragments() {
+ final Fragment<V>[] scheduledFragments= new Fragment[this.scheduledCount];
+ Fragment<V> fragment= this.topFragment.older;
+ int i= 0;
+ while (i < this.scheduledCount) {
+ if ((fragment.state & Fragment.SCHEDULED) != 0) {
+ scheduledFragments[i++]= fragment;
+ }
+ fragment= fragment.older;
+ }
+ return scheduledFragments;
+ }
+
+ public Fragment<V> getNextScheduledFragment() {
+ if (this.scheduledCount == 0) {
+ return null;
+ }
+ Fragment<V> fragment= this.scheduleNext.older;
+ while (true) {
+ if ((fragment.state & Fragment.SCHEDULED) != 0) {
+ this.scheduleNext= fragment;
+ return fragment;
+ }
+ fragment= fragment.older;
+ }
+ }
+
+ public void updateAssignment(final RDataAssignment assignment, final IStatus status) {
+ if (this.assignments.remove(assignment)) {
+ this.scheduledCount--;
+ }
+ }
+
+ public void updateFragment(final Fragment<V> fragment, final V rObject) {
+ if ((fragment.state & Fragment.SET) != 0) {
+ throw new IllegalStateException();
+ }
+ fragment.rObject= rObject;
+ if ((fragment.state & Fragment.SCHEDULED) != 0) {
+ this.scheduledCount--;
+ }
+ fragment.state= Fragment.SET;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RArrayAsVectorDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RArrayAsVectorDataAdapter.java
new file mode 100644
index 0000000..aa19602
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RArrayAsVectorDataAdapter.java
@@ -0,0 +1,133 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+import org.eclipse.statet.rj.services.FQRObjectRef;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RService;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for {@link RArray} objects of any dimension, loaded as one-dimensional vectors.
+ *
+ * @since 2.0 (provisional)
+ */
+public class RArrayAsVectorDataAdapter extends AbstractRDataAdapter<RArray<?>, RVector<?>> {
+
+
+ @Override
+ public RArray<?> validate(final RObject rObject) throws UnexpectedRDataException {
+ return RDataUtils.checkRArray(rObject);
+ }
+
+ @Override
+ public RArray<?> validate(final RObject rObject, final RArray<?> referenceObject,
+ final int flags) throws UnexpectedRDataException {
+ final RArray<?> array= RDataUtils.checkRArray(rObject, referenceObject.getDim().getLength());
+ // check dim ?
+ if ((flags & ROW_COUNT) != 0) {
+ RDataUtils.checkLengthEqual(array, referenceObject.getLength());
+ }
+ if ((flags & STORE_TYPE) != 0) {
+ RDataUtils.checkData(array.getData(), referenceObject.getData().getStoreType());
+ }
+ return array;
+ }
+
+ @Override
+ public long getRowCount(final RArray<?> rObject) {
+ return rObject.getLength();
+ }
+
+ @Override
+ public long getColumnCount(final RArray<?> rObject) {
+ return 1;
+ }
+
+
+ @Override
+ protected String getLoadDataFName() {
+ return API_R_PREFIX + ".getDataVectorValues"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected String getSetDataFName() {
+ return API_R_PREFIX + ".setDataVectorValues"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected RVector<?> validateData(final RObject rObject, final RArray<?> referenceObject,
+ final Fragment<RVector<?>> fragment) throws UnexpectedRDataException {
+ final RVector<?> vector= RDataUtils.checkRVector(rObject);
+ RDataUtils.checkLengthEqual(vector, fragment.getRowCount());
+
+ RDataUtils.checkData(rObject.getData(), referenceObject.getData().getStoreType());
+
+ return vector;
+ }
+
+ @Override
+ protected String getLoadRowNamesFName() {
+ throw new UnsupportedOperationException();
+ }
+
+ public RVector<?> loadDimNames(final FQRObjectRef ref, final RArray<?> referenceObject,
+ final LazyRStore.Fragment<RVector<?>> fragment,
+ final RService r, final IProgressMonitor monitor) throws CoreException,
+ UnexpectedRDataException {
+ final RObject fragmentObject;
+ { final FunctionCall fcall= r.createFunctionCall(API_R_PREFIX + ".getDataArrayDimNames"); //$NON-NLS-1$
+ addXRef(fcall, ref);
+ fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+ fragment.getRowBeginIdx() + 1,
+ fragment.getRowEndIdx(),
+ }));
+
+ fragmentObject= fcall.evalData(monitor);
+ }
+
+ return validateRowNames(fragmentObject, referenceObject, fragment);
+ }
+
+ public RVector<?> loadDimItemNames(final FQRObjectRef ref, final RArray<?> referenceObject,
+ final int dim, final LazyRStore.Fragment<RVector<?>> fragment,
+ final RService r, final IProgressMonitor monitor) throws CoreException,
+ UnexpectedRDataException {
+ final RObject fragmentObject;
+ { final FunctionCall fcall= r.createFunctionCall(API_R_PREFIX + ".getDataArrayDimItemNames"); //$NON-NLS-1$
+ addXRef(fcall, ref);
+ fcall.addInt("dimIdx", dim + 1); //$NON-NLS-1$
+ fcall.add("idxs", DefaultRObjectFactory.INSTANCE.createNumVector(new double[] { //$NON-NLS-1$
+ fragment.getRowBeginIdx() + 1,
+ fragment.getRowEndIdx(),
+ }));
+
+ fragmentObject= fcall.evalData(monitor);
+ }
+
+ return validateRowNames(fragmentObject, referenceObject, fragment);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataAssignment.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataAssignment.java
new file mode 100644
index 0000000..c6d01fd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataAssignment.java
@@ -0,0 +1,44 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RStore;
+
+
+public class RDataAssignment extends RDataSubset {
+
+
+ private final RStore<?> data;
+
+
+ public RDataAssignment(final long rowIdx, final long columnIdx, final RStore<?> data) {
+ super(rowIdx, 1, columnIdx, 1);
+
+ if (data == null) {
+ throw new NullPointerException("data"); //$NON-NLS-1$
+ }
+ if (data.getLength() > getLength()) {
+ throw new IllegalArgumentException("data.length"); //$NON-NLS-1$
+ }
+ this.data= data;
+ }
+
+
+ public RStore<?> getData() {
+ return this.data;
+ }
+
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataFrameDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataFrameDataAdapter.java
new file mode 100644
index 0000000..c71951d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataFrameDataAdapter.java
@@ -0,0 +1,92 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RDataFrame;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for {@link RDataFrame} objects.
+ *
+ * @since 2.0 (provisional)
+ */
+public class RDataFrameDataAdapter extends AbstractRDataAdapter<RDataFrame, RDataFrame> {
+
+
+ @Override
+ public RDataFrame validate(final RObject rObject) throws UnexpectedRDataException {
+ return RDataUtils.checkRDataFrame(rObject);
+ }
+
+ @Override
+ public RDataFrame validate(final RObject rObject, final RDataFrame referenceObject,
+ final int flags) throws UnexpectedRDataException {
+ final RDataFrame dataframe= RDataUtils.checkRDataFrame(rObject, referenceObject.getColumnCount());
+ if ((flags & ROW_COUNT) != 0) {
+ RDataUtils.checkRowCountEqual(dataframe, referenceObject.getRowCount());
+ }
+ if ((flags & STORE_TYPE) != 0) {
+ for (int i= 0; i < dataframe.getColumnCount(); i++) {
+ RDataUtils.checkData(dataframe.getColumn(i), referenceObject.getColumn(i).getStoreType());
+ }
+ }
+ return dataframe;
+ }
+
+ @Override
+ public long getRowCount(final RDataFrame rObject) {
+ return rObject.getRowCount();
+ }
+
+ @Override
+ public long getColumnCount(final RDataFrame rObject) {
+ return rObject.getColumnCount();
+ }
+
+
+ @Override
+ protected String getLoadDataFName() {
+ return API_R_PREFIX + ".getDataFrameValues"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected String getSetDataFName() {
+ return "rj:::.setDataFrameValues"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected RDataFrame validateData(final RObject rObject, final RDataFrame referenceObject,
+ final Fragment<RDataFrame> fragment) throws UnexpectedRDataException {
+ final RDataFrame dataframe= RDataUtils.checkRDataFrame(rObject, fragment.getColumnCount());
+ RDataUtils.checkRowCountEqual(dataframe, fragment.getRowCount());
+
+ for (int i= 0; i < fragment.getColumnCount(); i++) {
+ RDataUtils.checkData(dataframe.getColumn(i),
+ referenceObject.getColumn(fragment.getColumnBeginIdx() + i).getStoreType() );
+ }
+
+ return dataframe;
+ }
+
+ @Override
+ protected String getLoadRowNamesFName() {
+ return API_R_PREFIX + ".getDataFrameRowNames"; //$NON-NLS-1$
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataSubset.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataSubset.java
new file mode 100644
index 0000000..168587d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RDataSubset.java
@@ -0,0 +1,114 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+
+public class RDataSubset {
+
+
+ private final long rowBeginIdx;
+ private final long rowCount;
+ private final long columnBeginIdx;
+ private final long columnCount;
+
+
+ public RDataSubset(final long rowBeginIdx, final long rowCount,
+ final long columnBeginIdx, final long columnCount) {
+ this.rowBeginIdx= rowBeginIdx;
+ this.rowCount= rowCount;
+ this.columnBeginIdx= columnBeginIdx;
+ this.columnCount= columnCount;
+ }
+
+
+ /**
+ * Returns the row begin index of the subset.
+ *
+ * @return the begin index (zero-based)
+ */
+ public final long getRowBeginIdx() {
+ return this.rowBeginIdx;
+ }
+
+ /**
+ * Returns the row end index (exclusive) of the subset.
+ *
+ * @return the end index (zero-based)
+ */
+ public final long getRowEndIdx() {
+ return this.rowBeginIdx + this.rowCount;
+ }
+
+ /**
+ * Returns the row count of the subset.
+ *
+ * @return the count
+ */
+ public final long getRowCount() {
+ return this.rowCount;
+ }
+
+ public long toLocalRowIdx(final long rowIdx) {
+ final long idx;
+ if (rowIdx < this.rowBeginIdx
+ || (idx= rowIdx - this.rowBeginIdx) >= this.rowCount) {
+ throw new IndexOutOfBoundsException(Long.toString(rowIdx));
+ }
+ return idx;
+ }
+
+ /**
+ * Returns the column begin index of the subset.
+ *
+ * @return the index (zero-based)
+ */
+ public final long getColumnBeginIdx() {
+ return this.columnBeginIdx;
+ }
+
+ /**
+ * Returns the column end index (exclusive) of the subset.
+ *
+ * @return the index
+ */
+ public final long getColumnEndIdx() {
+ return this.columnBeginIdx + this.columnCount;
+ }
+
+ /**
+ * Returns the column count of the subset.
+ *
+ * @return the count
+ */
+ public final long getColumnCount() {
+ return this.columnCount;
+ }
+
+ public long toLocalColumnIdx(final long columnIdx) {
+ final long idx;
+ if (columnIdx < this.columnBeginIdx
+ || (idx= columnIdx - this.columnBeginIdx) >= this.columnCount) {
+ throw new IndexOutOfBoundsException(Long.toString(columnIdx));
+ }
+ return idx;
+ }
+
+
+ public long getLength() {
+ return (this.rowCount * this.columnCount);
+ }
+
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RMatrixDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RMatrixDataAdapter.java
new file mode 100644
index 0000000..4a232de
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RMatrixDataAdapter.java
@@ -0,0 +1,90 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RArray;
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for two-dimensional {@link RArray} objects.
+ *
+ * @since 2.0 (provisional)
+ */
+public class RMatrixDataAdapter extends AbstractRDataAdapter<RArray<?>, RArray<?>> {
+
+
+ @Override
+ public RArray<?> validate(final RObject rObject) throws UnexpectedRDataException {
+ return RDataUtils.checkRArray(rObject, 2);
+ }
+
+ @Override
+ public RArray<?> validate(final RObject rObject, final RArray<?> referenceObject,
+ final int flags) throws UnexpectedRDataException {
+ final RArray<?> array= RDataUtils.checkRArray(rObject, 2);
+ RDataUtils.checkColumnCountEqual(array, RDataUtils.getColumnCount(referenceObject));
+ if ((flags & ROW_COUNT) != 0) {
+ RDataUtils.checkLengthEqual(array, referenceObject.getLength());
+ }
+ if ((flags & STORE_TYPE) != 0) {
+ RDataUtils.checkData(array.getData(), referenceObject.getData().getStoreType());
+ }
+ return array;
+ }
+
+ @Override
+ public long getRowCount(final RArray<?> rObject) {
+ return rObject.getDim().getInt(0);
+ }
+
+ @Override
+ public long getColumnCount(final RArray<?> rObject) {
+ return rObject.getDim().getInt(1);
+ }
+
+
+ @Override
+ protected String getLoadDataFName() {
+ return API_R_PREFIX + ".getDataMatrixValues"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected String getSetDataFName() {
+ return "rj:::.setDataMatrixValues";
+ }
+
+ @Override
+ protected RArray<?> validateData(final RObject rObject, final RArray<?> referenceObject,
+ final Fragment<RArray<?>> fragment)
+ throws UnexpectedRDataException {
+ final RArray<?> array= RDataUtils.checkRArray(rObject, 2);
+ RDataUtils.checkColumnCountEqual(array, RDataUtils.checkIntLength(fragment.getColumnCount()));
+ RDataUtils.checkRowCountEqual(array, RDataUtils.checkIntLength(fragment.getRowCount()));
+
+ RDataUtils.checkData(rObject.getData(), referenceObject.getData().getStoreType());
+
+ return array;
+ }
+
+ @Override
+ protected String getLoadRowNamesFName() {
+ return API_R_PREFIX + ".getDataMatrixRowNames"; //$NON-NLS-1$
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RVectorDataAdapter.java b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RVectorDataAdapter.java
new file mode 100644
index 0000000..9dd1a2b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/src/org/eclipse/statet/rj/services/util/dataaccess/RVectorDataAdapter.java
@@ -0,0 +1,87 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.services.util.dataaccess;
+
+import org.eclipse.statet.rj.data.RDataUtils;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RVector;
+import org.eclipse.statet.rj.data.UnexpectedRDataException;
+import org.eclipse.statet.rj.services.util.dataaccess.LazyRStore.Fragment;
+
+
+/**
+ * Data adapter for {@link RVector} objects.
+ *
+ * @since 2.0 (provisional)
+ */
+public class RVectorDataAdapter extends AbstractRDataAdapter<RVector<?>, RVector<?>> {
+
+
+ @Override
+ public RVector<?> validate(final RObject rObject) throws UnexpectedRDataException {
+ return RDataUtils.checkRVector(rObject);
+ }
+
+ @Override
+ public RVector<?> validate(final RObject rObject, final RVector<?> referenceObject,
+ final int flags) throws UnexpectedRDataException {
+ final RVector<?> vector= RDataUtils.checkRVector(rObject);
+ if ((flags & ROW_COUNT) != 0) {
+ RDataUtils.checkLengthEqual(vector, referenceObject.getLength());
+ }
+ if ((flags & STORE_TYPE) != 0) {
+ RDataUtils.checkData(vector.getData(), referenceObject.getData().getStoreType());
+ }
+ return vector;
+ }
+
+ @Override
+ public long getRowCount(final RVector<?> rObject) {
+ return rObject.getLength();
+ }
+
+ @Override
+ public long getColumnCount(final RVector<?> rObject) {
+ return 1;
+ }
+
+
+ @Override
+ protected String getLoadDataFName() {
+ return API_R_PREFIX + ".getDataVectorValues"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected String getSetDataFName() {
+ return API_R_PREFIX + ".setDataVectorValues"; //$NON-NLS-1$
+ }
+
+ @Override
+ protected RVector<?> validateData(final RObject rObject, final RVector<?> referenceObject,
+ final Fragment<RVector<?>> fragment) throws UnexpectedRDataException {
+ final RVector<?> vector= RDataUtils.checkRVector(rObject);
+ RDataUtils.checkLengthEqual(vector, fragment.getRowCount());
+
+ RDataUtils.checkData(rObject.getData(), referenceObject.getData().getStoreType());
+
+ return vector;
+ }
+
+ @Override
+ protected String getLoadRowNamesFName() {
+ return API_R_PREFIX + ".getDataVectorRowNames"; //$NON-NLS-1$
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RCircle.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RCircle.java
new file mode 100644
index 0000000..8cac65f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RCircle.java
@@ -0,0 +1,65 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Circle with center <code>(x, y)</code> and radius <code>r</code>.
+ */
+public class RCircle extends RGraphicElement {
+
+
+ public final double x;
+ public final double y;
+ public final double r;
+
+
+ /**
+ * Creates a new circle.
+ *
+ * @param x x coordinate of the center
+ * @param y y coordinate of the center
+ * @param r radius
+ */
+ public RCircle(final double x, final double y, final double r) {
+ this.x= x;
+ this.y= y;
+ this.r= r;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return DRAW_CIRCLE;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(40);
+ sb.append("Circle[(");
+ sb.append(this.x);
+ sb.append(",");
+ sb.append(this.y);
+ sb.append("), ");
+ sb.append(this.r);
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RClipSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RClipSetting.java
new file mode 100644
index 0000000..a154b84
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RClipSetting.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Rectangular clipping area with the vertexes <code>(x0, y0)</code>, <code>(x0, y1)</code>,
+ * <code>(x1, y1)</code>, <code>(x1, y1)</code>.
+ */
+public class RClipSetting extends RPaintSetting {
+
+
+ public final double x0;
+ public final double y0;
+ public final double x1;
+ public final double y1;
+
+
+ /**
+ * Creates a new rectangular clipping area.
+ *
+ * @param x0 lower x coordinate
+ * @param y0 lower y coordinate
+ * @param x1 higher x coordinate
+ * @param y1 higher x coordinate
+ */
+ public RClipSetting(final double x0, final double y0, final double x1, final double y1) {
+ this.x0= x0;
+ this.y0= y0;
+ this.x1= x1;
+ this.y1= y1;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return SET_CLIP;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(50);
+ sb.append("RClipSetting[(");
+ sb.append(this.x0);
+ sb.append(",");
+ sb.append(this.y0);
+ sb.append("), (");
+ sb.append(this.x1);
+ sb.append(",");
+ sb.append(this.y1);
+ sb.append(")]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RColorSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RColorSetting.java
new file mode 100644
index 0000000..f01c41c
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RColorSetting.java
@@ -0,0 +1,66 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures paint color.
+ */
+public class RColorSetting extends RPaintSetting {
+
+
+ public final int color;
+
+
+ /**
+ * Creates a new color setting.
+ *
+ * @param color color
+ */
+ public RColorSetting(final int color) {
+ this.color= color;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return SET_COLOR;
+ }
+
+
+ public final int getAlpha() {
+ return ((this.color >> 24) & 255);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RPaintColor[(");
+ sb.append(this.color & 255);
+ sb.append(", ");
+ sb.append((this.color >> 8) & 255);
+ sb.append(", ");
+ sb.append((this.color >> 16) & 255);
+ sb.append("), ");
+ sb.append((this.color >> 24) & 255);
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFillSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFillSetting.java
new file mode 100644
index 0000000..4eedb13
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFillSetting.java
@@ -0,0 +1,66 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures filling paint color.
+ */
+public class RFillSetting extends RPaintSetting {
+
+
+ public final int color;
+
+
+ /**
+ * Creates a new fill setting.
+ *
+ * @param color color
+ */
+ public RFillSetting(final int color) {
+ this.color= color;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return SET_FILL;
+ }
+
+
+ public final int getAlpha() {
+ return ((this.color >> 24) & 255);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("RPaintFill[(");
+ sb.append(this.color & 255);
+ sb.append(", ");
+ sb.append((this.color >> 8) & 255);
+ sb.append(", ");
+ sb.append((this.color >> 16) & 255);
+ sb.append("), ");
+ sb.append((this.color >> 24) & 255);
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFontSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFontSetting.java
new file mode 100644
index 0000000..4e17b9e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RFontSetting.java
@@ -0,0 +1,92 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures the text font.
+ */
+public class RFontSetting extends RPaintSetting {
+
+ /**
+ * Font family name, ~R: <code>par(familiy)</code>.
+ **/
+ public final String family;
+
+ /**
+ * Font face constant, ~R: <code>par(font)</code>.
+ * <p>
+ * Values:
+ * 1= default,
+ * 2= bold,
+ * 3= italic,
+ * 4= bold and italic,
+ * 5= symbol.</p>
+ **/
+ public final int face;
+
+ /**
+ * Font size in points, ~R: ps * cex.
+ */
+ public final float pointSize;
+
+ /**
+ * The line height factor, ~R: <code>par(lheight)</code>
+ */
+ public final double lineHeight;
+
+
+ /**
+ * Creates a new font setting.
+ *
+ * @param family font family name
+ * @param type face font face constant
+ * @param pointSize font size in points
+ * @param lineHeight line height factor
+ */
+ public RFontSetting(final String family, final int face, final float pointSize,
+ final double lineHeight) {
+ this.family= family;
+ this.face= face;
+ this.pointSize= pointSize;
+ this.lineHeight= lineHeight;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return SET_FONT;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(40 + this.family.length());
+ sb.append("RFontParameter[");
+ sb.append(this.family);
+ sb.append(", ");
+ sb.append(this.face);
+ sb.append(", ");
+ sb.append(this.pointSize);
+ sb.append(", ");
+ sb.append(this.lineHeight);
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphic.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphic.java
new file mode 100644
index 0000000..fcdc0d0
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphic.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+import java.util.List;
+
+
+/**
+ * An RGraphic represents the client side of a graphic (device)
+ * in R.
+ * <p>
+ * The attributes devId ({@link #getDevId()}) and active ({@link #isActive()},
+ * {@link Listener#activated()}, {@link Listener#deactivated()}) are equivalent
+ * to the device id and active device in R.</p>
+ * <p>
+ * A graphic has a sequence of graphic instructions describing how to paint the
+ * graphic ({@link #getInstructions()}). If not empty, the first instruction is
+ * of the type {@link RGraphicInstruction#INIT INIT}, followed by setting and
+ * drawing instructions. Settings are valid for all following drawing instructions
+ * until it is changed by a new setting instruction of the same type.</p>
+ */
+public interface RGraphic {
+
+
+ interface Listener {
+
+ void activated();
+ void deactivated();
+ void drawingStarted();
+ void drawingStopped();
+
+ }
+
+ /**
+ * Returns the device id of the graphic in R. Note that the device number presented in public
+ * R functions is this device id + 1.
+ *
+ * @return the device id
+ */
+ int getDevId();
+
+ /**
+ * Returns if graphic device of this graphic is the active device in R.
+ *
+ * @return <code>true</code> if it is active, otherwise <code>false</code>
+ */
+ boolean isActive();
+
+ List<? extends RGraphicInstruction> getInstructions();
+
+ void addListener(Listener listener);
+
+ void removeListener(Listener listener);
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicElement.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicElement.java
new file mode 100644
index 0000000..c4adfe9
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicElement.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Parent of all instructions painting graphic elements (in contrast to {@link RPaintSetting}).
+ */
+public abstract class RGraphicElement implements RGraphicInstruction {
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInitialization.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInitialization.java
new file mode 100644
index 0000000..ec1414d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInitialization.java
@@ -0,0 +1,52 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * First instruction of an R graphic.
+ */
+public class RGraphicInitialization implements RGraphicInstruction {
+
+
+ /**
+ * The width the graphic is created for in R
+ */
+ public final double width;
+
+ /**
+ * The height the graphic is created for in R
+ */
+ public final double height;
+
+ /**
+ * The color of the device background
+ */
+ public final int canvasColor;
+
+
+ public RGraphicInitialization(final double width, final double height, final int canvasColor) {
+ this.width= width;
+ this.height= height;
+ this.canvasColor= canvasColor;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return INIT;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInstruction.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInstruction.java
new file mode 100644
index 0000000..a0f234d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RGraphicInstruction.java
@@ -0,0 +1,54 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Instruction to paint a R graphic.
+ *
+ * An instruction has one of the instruction type defined in this interface.
+ *
+ * @see RGraphic
+ */
+public interface RGraphicInstruction {
+
+
+ byte INIT= 0;
+
+ byte SET_CLIP= 1;
+ byte SET_COLOR= 2;
+ byte SET_FILL= 3;
+ byte SET_LINE= 4;
+ byte SET_FONT= 5;
+
+ byte DRAW_LINE= 6;
+ byte DRAW_RECTANGLE= 7;
+ byte DRAW_POLYLINE= 8;
+ byte DRAW_POLYGON= 9;
+ byte DRAW_CIRCLE= 10;
+ byte DRAW_TEXT= 11;
+ byte DRAW_RASTER= 12;
+ byte DRAW_PATH= 13;
+
+
+ /**
+ * Gets the type of this instruction.
+ *
+ * @return the instruction type
+ * @see RGraphicInstruction
+ */
+ byte getInstructionType();
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLine.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLine.java
new file mode 100644
index 0000000..7b30a5e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLine.java
@@ -0,0 +1,70 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Line with end points <code>(x0, y0)</code> and <code>(x1, y1)</code>.
+ */
+public class RLine extends RGraphicElement {
+
+
+ public final double x0;
+ public final double y0;
+ public final double x1;
+ public final double y1;
+
+
+ /**
+ * Creates a new line
+ *
+ * @param x0 x coordinate of point 1
+ * @param y0 y coordinate of point 1
+ * @param x1 x coordinate of point 2
+ * @param y1 y coordinate of point 2
+ */
+ public RLine(final double x0, final double y0, final double x1, final double y1) {
+ this.x0= x0;
+ this.y0= y0;
+ this.x1= x1;
+ this.y1= y1;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return DRAW_LINE;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(50);
+ sb.append("RLine[(");
+ sb.append(this.x0);
+ sb.append(",");
+ sb.append(this.y0);
+ sb.append("), (");
+ sb.append(this.x1);
+ sb.append(",");
+ sb.append(this.y1);
+ sb.append(")]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLineSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLineSetting.java
new file mode 100644
index 0000000..d2361dc
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RLineSetting.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Configures line width and type.
+ */
+public class RLineSetting extends RPaintSetting {
+
+
+ public static final int TYPE_BLANK= -1;
+ public static final int TYPE_SOLID= 0;
+
+ public static final byte CAP_ROUND= 1;
+ public static final byte CAP_BUTT= 2;
+ public static final byte CAP_SQUARE= 3;
+
+ public static final byte JOIN_ROUND= 1;
+ public static final byte JOIN_MITER= 2;
+ public static final byte JOIN_BEVEL= 3;
+
+
+ /**
+ * Line type, ~R: <code>par(lty)</code>
+ * <p>
+ * Values (not the predefined R constants, see line style encoding):
+ * -1= blank,
+ * 0= solid (default),
+ * encoded style
+ */
+ public final int type;
+
+ public final float width;
+
+ public final byte cap;
+
+ public final byte join;
+ public final float joinMiterLimit;
+
+
+ /**
+ * Creates a new line setting.
+ *
+ * @param type line type
+ * @param width line width
+ */
+ public RLineSetting(final int type, final float width,
+ final byte cap, final byte join, final float joinMiterLimit) {
+ this.type= type;
+ this.width= width;
+ this.cap= cap;
+ this.join= join;
+ this.joinMiterLimit= joinMiterLimit;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return SET_LINE;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(30);
+ sb.append("RLineSetting[");
+ sb.append(this.type);
+ sb.append(", ");
+ sb.append(this.width);
+ sb.append(", ");
+ sb.append(this.cap);
+ sb.append(", ");
+ sb.append(this.join);
+ sb.append(", ");
+ sb.append(this.joinMiterLimit);
+ sb.append("]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPaintSetting.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPaintSetting.java
new file mode 100644
index 0000000..5156593
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPaintSetting.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Parent of all instructions setting paint parameters (in contrast to {@link RGraphicElement}).
+ */
+public abstract class RPaintSetting implements RGraphicInstruction {
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPath.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPath.java
new file mode 100644
index 0000000..786108b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPath.java
@@ -0,0 +1,83 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Path with vertices <code>(x[1], y[1])</code>, ..., <code>(x[n-1], y[n-1])</code>.
+ */
+public class RPath extends RGraphicElement {
+
+
+ /**
+ * Number of vertices per segment
+ */
+ public final int[] n;
+
+ /**
+ * Coordinates of the vertices
+ */
+ public final double[] x, y;
+
+ public final int mode;
+
+
+ /**
+ * Creates a new path
+ *
+ * @param n {@link #n}
+ * @param x {@link #x}
+ * @param y {@link #y}
+ * @winding {@link #mode}
+ */
+ public RPath(final int[] n, final double[] x, final double[] y, final int mode) {
+ this.n= n;
+ this.x= x;
+ this.y= y;
+ this.mode= mode;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return DRAW_PATH;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final int n= this.x.length;
+ if (n == 0) {
+ return "RPath[]";
+ }
+ final StringBuilder sb= new StringBuilder(14 + this.x.length*20);
+ sb.append("RPath[(");
+ sb.append(this.x[0]);
+ sb.append(",");
+ sb.append(this.y[0]);
+ for (int i= 1; i < n; i++) {
+ sb.append("), (");
+ sb.append(this.x[i]);
+ sb.append(",");
+ sb.append(this.y[i]);
+ }
+ sb.append(")]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolygon.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolygon.java
new file mode 100644
index 0000000..34be464
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolygon.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Polygon with vertices <code>(x[1], y[1])</code>, ..., <code>(x[n-1], y[n-1])</code>.
+ */
+public class RPolygon extends RGraphicElement {
+
+
+ /**
+ * Coordinates of the vertices.
+ */
+ public final double[] x, y;
+
+
+ /**
+ * Creates a new polygon
+ *
+ * @param x {@link #x}
+ * @param y {@link #y}
+ */
+ public RPolygon(final double[] x, final double[] y) {
+ this.x= x;
+ this.y= y;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return DRAW_POLYGON;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final int n= this.x.length;
+ if (n == 0) {
+ return "RPolygon[]";
+ }
+ final StringBuilder sb= new StringBuilder(14 + this.x.length*20);
+ sb.append("RPolygon[(");
+ sb.append(this.x[0]);
+ sb.append(",");
+ sb.append(this.y[0]);
+ for (int i= 1; i < n; i++) {
+ sb.append("), (");
+ sb.append(this.x[i]);
+ sb.append(",");
+ sb.append(this.y[i]);
+ }
+ sb.append(")]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolyline.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolyline.java
new file mode 100644
index 0000000..a371222
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RPolyline.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Polyline through <code>(x[0], y[0])</code>, ..., <code>(x[n-1], y[n-1])</code>.
+ */
+public class RPolyline extends RGraphicElement {
+
+
+ /**
+ * Coordinates of the vertices.
+ */
+ public final double[] x, y;
+
+
+ /**
+ * Creates a new polyline.
+ *
+ * @param x {@link #x}
+ * @param y {@link #y}
+ */
+ public RPolyline(final double[] x, final double[] y) {
+ this.x= x;
+ this.y= y;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return DRAW_POLYLINE;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final int n= this.x.length;
+ if (n == 0) {
+ return "RPolyline[]";
+ }
+ final StringBuilder sb= new StringBuilder(14 + this.x.length*20);
+ sb.append("RPolyline[(");
+ sb.append(this.x[0]);
+ sb.append(",");
+ sb.append(this.y[0]);
+ for (int i= 1; i < n; i++) {
+ sb.append("), (");
+ sb.append(this.x[i]);
+ sb.append(",");
+ sb.append(this.y[i]);
+ }
+ sb.append(")]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRaster.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRaster.java
new file mode 100644
index 0000000..8bc17b1
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRaster.java
@@ -0,0 +1,101 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Raster image.
+ */
+public class RRaster extends RGraphicElement {
+
+ /**
+ * The image data to draw (RGBA).
+ */
+ public final byte[] imgData;
+ /**
+ * The dimension of the {@link #imgData image}.
+ */
+ public final int imgWidth, imgHeight;
+ /**
+ * The position for the bottom-left corner where to draw the image.
+ */
+ public final double x, y;
+ /**
+ * The dimension where to draw the image.
+ */
+ public final double width, height;
+ /**
+ * The degree to rotate anti-clockwise the image.
+ */
+ public final double rotateDegree;
+
+ public final boolean interpolate;
+
+
+ /**
+ * Creates a new raster image element.
+ *
+ * @param imgData {@link #imgData}
+ * @param imgWidth {@link #imgWidth}
+ * @param imgHeight {@link #imgHeight}
+ * @param x {@link #x}
+ * @param y {@link #y}
+ * @param w {@link #width}
+ * @param h {@link #height}
+ * @param rDeg {@link #rotateDegree}
+ * @param interpolate {@link #interpolate}
+ */
+ public RRaster(final byte[] imgData, final int imgWidth, final int imgHeight,
+ final double x, final double y, final double w, final double h,
+ final double rDeg, final boolean interpolate) {
+ this.imgData= imgData;
+ this.imgWidth= imgWidth;
+ this.imgHeight= imgHeight;
+ this.x= x;
+ this.y= y;
+ this.width= w;
+ this.height= h;
+ this.rotateDegree= rDeg;
+ this.interpolate= interpolate;
+ }
+
+
+ @Override
+ public byte getInstructionType() {
+ return DRAW_RASTER;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(50);
+ sb.append("RRaster[(");
+ sb.append(this.x);
+ sb.append(",");
+ sb.append(this.y);
+ sb.append("), (");
+ sb.append(this.width);
+ sb.append(" x ");
+ sb.append(this.height);
+ sb.append(", ");
+ sb.append(this.rotateDegree);
+ sb.append(", \"");
+ sb.append(this.interpolate);
+ sb.append("\"]");
+ return sb.toString();
+ }
+
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRect.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRect.java
new file mode 100644
index 0000000..c048e6a
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RRect.java
@@ -0,0 +1,71 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Rectangle with the vertexes <code>(x0, y0)</code>, <code>(x0, y1)</code>,
+ * <code>(x1, y1)</code>, <code>(x1, y1)</code>.
+ */
+public class RRect extends RGraphicElement {
+
+
+ public final double x0;
+ public final double y0;
+ public final double x1;
+ public final double y1;
+
+
+ /**
+ * Creates a new rectangle.
+ *
+ * @param x0 lower x coordinate
+ * @param y0 lower y coordinate
+ * @param x1 higher x coordinate
+ * @param y1 higher x coordinate
+ */
+ public RRect(final double x0, final double y0, final double x1, final double y1) {
+ this.x0= x0;
+ this.y0= y0;
+ this.x1= x1;
+ this.y1= y1;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return DRAW_RECTANGLE;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(50);
+ sb.append("RRect[(");
+ sb.append(this.x0);
+ sb.append(",");
+ sb.append(this.y0);
+ sb.append("), (");
+ sb.append(this.x1);
+ sb.append(",");
+ sb.append(this.y1);
+ sb.append(")]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RText.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RText.java
new file mode 100644
index 0000000..488103f
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/RText.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core;
+
+
+/**
+ * Text at position <code>(x, y)</code>, horizontal adjusted by <code>hAdj</code>
+ * [0, 1] and rotated by <code>rDeg</code>.
+ */
+public class RText extends RGraphicElement {
+
+ /**
+ * The text to draw.
+ */
+ public final String text;
+ /**
+ * The position where to draw the text.
+ */
+ public final double x, y;
+ /**
+ * The factor for the horizontal adjustment of the text.
+ */
+ public final double horizontalAdjust;
+ /**
+ * The degrees for rotation of the text.
+ */
+ public final double rotateDegree;
+
+
+ /**
+ * Creates a new text element.
+ *
+ * @param x {@link #x}
+ * @param y {@link #y}
+ * @param hAdj {@link #horizontalAdjust}
+ * @param rDeg {@link #rotateDegree}
+ * @param text {@link #text}
+ */
+ public RText(final String text,
+ final double x, final double y, final double rDeg, final double hAdj) {
+ this.text= text;
+ this.x= x;
+ this.y= y;
+ this.horizontalAdjust= hAdj;
+ this.rotateDegree= rDeg;
+ }
+
+
+ @Override
+ public final byte getInstructionType() {
+ return DRAW_TEXT;
+ }
+
+
+ @Override
+ public String toString() {
+ final StringBuilder sb= new StringBuilder(50 + this.text.length());
+ sb.append("RText[(");
+ sb.append(this.x);
+ sb.append(",");
+ sb.append(this.y);
+ sb.append("), ");
+ sb.append(this.horizontalAdjust);
+ sb.append(", ");
+ sb.append(this.rotateDegree);
+ sb.append(", \"");
+ sb.append(this.text);
+ sb.append("\"]");
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/.gitignore b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/.gitignore
new file mode 100644
index 0000000..86eb01d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/.gitignore
@@ -0,0 +1 @@
+/AdbSymbol.txt
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CachedMapping.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CachedMapping.java
new file mode 100644
index 0000000..7d58fad
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CachedMapping.java
@@ -0,0 +1,45 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+
+public final class CachedMapping implements CharMapping {
+
+
+ private final CharMapping mapping;
+
+ private String lastString;
+ private String lastEncoded;
+
+
+ public CachedMapping(final CharMapping mapping) {
+ this.mapping= mapping;
+ }
+
+
+ @Override
+ public int encode(final int codepoint) {
+ return this.mapping.encode(codepoint);
+ }
+
+ @Override
+ public String encode(final String s) {
+ if (s.equals(this.lastString)) {
+ return this.lastEncoded;
+ }
+ return (this.lastEncoded= this.mapping.encode(s));
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CharMapping.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CharMapping.java
new file mode 100644
index 0000000..d7395a5
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CharMapping.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+
+public interface CharMapping {
+
+
+ int encode(int codepoint);
+
+ String encode(String s);
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CodeGenAdbSymbol.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CodeGenAdbSymbol.java
new file mode 100644
index 0000000..d9298dd
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/CodeGenAdbSymbol.java
@@ -0,0 +1,60 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+
+/**
+ * Code generation for AdbSymbol
+ *
+ * http://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt
+ */
+class CodeGenAdbSymbol {
+
+
+ public static void main(final String[] args) throws Exception {
+ final File file= new File("bin/" + CodeGenAdbSymbol.class.getPackage().getName().replace('.', '/') + "/AdbSymbol.txt");
+ final BufferedReader reader= new BufferedReader(new FileReader(file));
+ String line;
+ while ((line= reader.readLine()) != null) {
+ if (line.length() == 0 || line.startsWith("#")) {
+ continue;
+ }
+ final String[] columns= line.split("\t");
+ if (columns.length != 4) {
+ throw new IOException(line);
+ }
+
+ System.out.print("MAPPING[0x");
+ System.out.print(columns[0]);
+ System.out.print("]= 0x");
+ System.out.print(columns[1]);
+ System.out.print("; // ");
+ System.out.print(columns[2].substring(2));
+
+ final int codepoint= Integer.parseInt(columns[0], 16);
+ if (new String(new int[] { codepoint }, 0, 1).length() != 1) {
+ throw new IOException("Warning: multichar codepoint");
+ }
+
+ System.out.println();
+ }
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/Unicode2AdbSymbolMapping.java b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/Unicode2AdbSymbolMapping.java
new file mode 100644
index 0000000..7f14f34
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcGraphic/org/eclipse/statet/rj/graphic/core/util/Unicode2AdbSymbolMapping.java
@@ -0,0 +1,240 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.graphic.core.util;
+
+
+public final class Unicode2AdbSymbolMapping implements CharMapping {
+
+
+ private final static char[] ADBSYMBOL_U2C= new char[0xffff];
+
+ static {
+ for (int i= 0; i < ADBSYMBOL_U2C.length; i++) {
+ ADBSYMBOL_U2C[i]= (char) i;
+ }
+ // Generated by CodeGenAdbSymbol
+ ADBSYMBOL_U2C[0x0020]= 0x20; // SPACE
+ ADBSYMBOL_U2C[0x00A0]= 0x20; // NO-BREAK SPACE
+ ADBSYMBOL_U2C[0x0021]= 0x21; // EXCLAMATION MARK
+ ADBSYMBOL_U2C[0x2200]= 0x22; // FOR ALL
+ ADBSYMBOL_U2C[0x0023]= 0x23; // NUMBER SIGN
+ ADBSYMBOL_U2C[0x2203]= 0x24; // THERE EXISTS
+ ADBSYMBOL_U2C[0x0025]= 0x25; // PERCENT SIGN
+ ADBSYMBOL_U2C[0x0026]= 0x26; // AMPERSAND
+ ADBSYMBOL_U2C[0x220B]= 0x27; // CONTAINS AS MEMBER
+ ADBSYMBOL_U2C[0x0028]= 0x28; // LEFT PARENTHESIS
+ ADBSYMBOL_U2C[0x0029]= 0x29; // RIGHT PARENTHESIS
+ ADBSYMBOL_U2C[0x2217]= 0x2A; // ASTERISK OPERATOR
+ ADBSYMBOL_U2C[0x002B]= 0x2B; // PLUS SIGN
+ ADBSYMBOL_U2C[0x002C]= 0x2C; // COMMA
+ ADBSYMBOL_U2C[0x2212]= 0x2D; // MINUS SIGN
+ ADBSYMBOL_U2C[0x002E]= 0x2E; // FULL STOP
+ ADBSYMBOL_U2C[0x002F]= 0x2F; // SOLIDUS
+ ADBSYMBOL_U2C[0x0030]= 0x30; // DIGIT ZERO
+ ADBSYMBOL_U2C[0x0031]= 0x31; // DIGIT ONE
+ ADBSYMBOL_U2C[0x0032]= 0x32; // DIGIT TWO
+ ADBSYMBOL_U2C[0x0033]= 0x33; // DIGIT THREE
+ ADBSYMBOL_U2C[0x0034]= 0x34; // DIGIT FOUR
+ ADBSYMBOL_U2C[0x0035]= 0x35; // DIGIT FIVE
+ ADBSYMBOL_U2C[0x0036]= 0x36; // DIGIT SIX
+ ADBSYMBOL_U2C[0x0037]= 0x37; // DIGIT SEVEN
+ ADBSYMBOL_U2C[0x0038]= 0x38; // DIGIT EIGHT
+ ADBSYMBOL_U2C[0x0039]= 0x39; // DIGIT NINE
+ ADBSYMBOL_U2C[0x003A]= 0x3A; // COLON
+ ADBSYMBOL_U2C[0x003B]= 0x3B; // SEMICOLON
+ ADBSYMBOL_U2C[0x003C]= 0x3C; // LESS-THAN SIGN
+ ADBSYMBOL_U2C[0x003D]= 0x3D; // EQUALS SIGN
+ ADBSYMBOL_U2C[0x003E]= 0x3E; // GREATER-THAN SIGN
+ ADBSYMBOL_U2C[0x003F]= 0x3F; // QUESTION MARK
+ ADBSYMBOL_U2C[0x2245]= 0x40; // APPROXIMATELY EQUAL TO
+ ADBSYMBOL_U2C[0x0391]= 0x41; // GREEK CAPITAL LETTER ALPHA
+ ADBSYMBOL_U2C[0x0392]= 0x42; // GREEK CAPITAL LETTER BETA
+ ADBSYMBOL_U2C[0x03A7]= 0x43; // GREEK CAPITAL LETTER CHI
+ ADBSYMBOL_U2C[0x0394]= 0x44; // GREEK CAPITAL LETTER DELTA
+ ADBSYMBOL_U2C[0x2206]= 0x44; // INCREMENT
+ ADBSYMBOL_U2C[0x0395]= 0x45; // GREEK CAPITAL LETTER EPSILON
+ ADBSYMBOL_U2C[0x03A6]= 0x46; // GREEK CAPITAL LETTER PHI
+ ADBSYMBOL_U2C[0x0393]= 0x47; // GREEK CAPITAL LETTER GAMMA
+ ADBSYMBOL_U2C[0x0397]= 0x48; // GREEK CAPITAL LETTER ETA
+ ADBSYMBOL_U2C[0x0399]= 0x49; // GREEK CAPITAL LETTER IOTA
+ ADBSYMBOL_U2C[0x03D1]= 0x4A; // GREEK THETA SYMBOL
+ ADBSYMBOL_U2C[0x039A]= 0x4B; // GREEK CAPITAL LETTER KAPPA
+ ADBSYMBOL_U2C[0x039B]= 0x4C; // GREEK CAPITAL LETTER LAMDA
+ ADBSYMBOL_U2C[0x039C]= 0x4D; // GREEK CAPITAL LETTER MU
+ ADBSYMBOL_U2C[0x039D]= 0x4E; // GREEK CAPITAL LETTER NU
+ ADBSYMBOL_U2C[0x039F]= 0x4F; // GREEK CAPITAL LETTER OMICRON
+ ADBSYMBOL_U2C[0x03A0]= 0x50; // GREEK CAPITAL LETTER PI
+ ADBSYMBOL_U2C[0x0398]= 0x51; // GREEK CAPITAL LETTER THETA
+ ADBSYMBOL_U2C[0x03A1]= 0x52; // GREEK CAPITAL LETTER RHO
+ ADBSYMBOL_U2C[0x03A3]= 0x53; // GREEK CAPITAL LETTER SIGMA
+ ADBSYMBOL_U2C[0x03A4]= 0x54; // GREEK CAPITAL LETTER TAU
+ ADBSYMBOL_U2C[0x03A5]= 0x55; // GREEK CAPITAL LETTER UPSILON
+ ADBSYMBOL_U2C[0x03C2]= 0x56; // GREEK SMALL LETTER FINAL SIGMA
+ ADBSYMBOL_U2C[0x03A9]= 0x57; // GREEK CAPITAL LETTER OMEGA
+ ADBSYMBOL_U2C[0x2126]= 0x57; // OHM SIGN
+ ADBSYMBOL_U2C[0x039E]= 0x58; // GREEK CAPITAL LETTER XI
+ ADBSYMBOL_U2C[0x03A8]= 0x59; // GREEK CAPITAL LETTER PSI
+ ADBSYMBOL_U2C[0x0396]= 0x5A; // GREEK CAPITAL LETTER ZETA
+ ADBSYMBOL_U2C[0x005B]= 0x5B; // LEFT SQUARE BRACKET
+ ADBSYMBOL_U2C[0x2234]= 0x5C; // THEREFORE
+ ADBSYMBOL_U2C[0x005D]= 0x5D; // RIGHT SQUARE BRACKET
+ ADBSYMBOL_U2C[0x22A5]= 0x5E; // UP TACK
+ ADBSYMBOL_U2C[0x005F]= 0x5F; // LOW LINE
+ ADBSYMBOL_U2C[0xF8E5]= 0x60; // RADICAL EXTENDER
+ ADBSYMBOL_U2C[0x03B1]= 0x61; // GREEK SMALL LETTER ALPHA
+ ADBSYMBOL_U2C[0x03B2]= 0x62; // GREEK SMALL LETTER BETA
+ ADBSYMBOL_U2C[0x03C7]= 0x63; // GREEK SMALL LETTER CHI
+ ADBSYMBOL_U2C[0x03B4]= 0x64; // GREEK SMALL LETTER DELTA
+ ADBSYMBOL_U2C[0x03B5]= 0x65; // GREEK SMALL LETTER EPSILON
+ ADBSYMBOL_U2C[0x03C6]= 0x66; // GREEK SMALL LETTER PHI
+ ADBSYMBOL_U2C[0x03B3]= 0x67; // GREEK SMALL LETTER GAMMA
+ ADBSYMBOL_U2C[0x03B7]= 0x68; // GREEK SMALL LETTER ETA
+ ADBSYMBOL_U2C[0x03B9]= 0x69; // GREEK SMALL LETTER IOTA
+ ADBSYMBOL_U2C[0x03D5]= 0x6A; // GREEK PHI SYMBOL
+ ADBSYMBOL_U2C[0x03BA]= 0x6B; // GREEK SMALL LETTER KAPPA
+ ADBSYMBOL_U2C[0x03BB]= 0x6C; // GREEK SMALL LETTER LAMDA
+ ADBSYMBOL_U2C[0x00B5]= 0x6D; // MICRO SIGN
+ ADBSYMBOL_U2C[0x03BC]= 0x6D; // GREEK SMALL LETTER MU
+ ADBSYMBOL_U2C[0x03BD]= 0x6E; // GREEK SMALL LETTER NU
+ ADBSYMBOL_U2C[0x03BF]= 0x6F; // GREEK SMALL LETTER OMICRON
+ ADBSYMBOL_U2C[0x03C0]= 0x70; // GREEK SMALL LETTER PI
+ ADBSYMBOL_U2C[0x03B8]= 0x71; // GREEK SMALL LETTER THETA
+ ADBSYMBOL_U2C[0x03C1]= 0x72; // GREEK SMALL LETTER RHO
+ ADBSYMBOL_U2C[0x03C3]= 0x73; // GREEK SMALL LETTER SIGMA
+ ADBSYMBOL_U2C[0x03C4]= 0x74; // GREEK SMALL LETTER TAU
+ ADBSYMBOL_U2C[0x03C5]= 0x75; // GREEK SMALL LETTER UPSILON
+ ADBSYMBOL_U2C[0x03D6]= 0x76; // GREEK PI SYMBOL
+ ADBSYMBOL_U2C[0x03C9]= 0x77; // GREEK SMALL LETTER OMEGA
+ ADBSYMBOL_U2C[0x03BE]= 0x78; // GREEK SMALL LETTER XI
+ ADBSYMBOL_U2C[0x03C8]= 0x79; // GREEK SMALL LETTER PSI
+ ADBSYMBOL_U2C[0x03B6]= 0x7A; // GREEK SMALL LETTER ZETA
+ ADBSYMBOL_U2C[0x007B]= 0x7B; // LEFT CURLY BRACKET
+ ADBSYMBOL_U2C[0x007C]= 0x7C; // VERTICAL LINE
+ ADBSYMBOL_U2C[0x007D]= 0x7D; // RIGHT CURLY BRACKET
+ ADBSYMBOL_U2C[0x223C]= 0x7E; // TILDE OPERATOR
+ ADBSYMBOL_U2C[0x20AC]= 0xA0; // EURO SIGN
+ ADBSYMBOL_U2C[0x03D2]= 0xA1; // GREEK UPSILON WITH HOOK SYMBOL
+ ADBSYMBOL_U2C[0x2032]= 0xA2; // PRIME
+ ADBSYMBOL_U2C[0x2264]= 0xA3; // LESS-THAN OR EQUAL TO
+ ADBSYMBOL_U2C[0x2044]= 0xA4; // FRACTION SLASH
+ ADBSYMBOL_U2C[0x2215]= 0xA4; // DIVISION SLASH
+ ADBSYMBOL_U2C[0x221E]= 0xA5; // INFINITY
+ ADBSYMBOL_U2C[0x0192]= 0xA6; // LATIN SMALL LETTER F WITH HOOK
+ ADBSYMBOL_U2C[0x2663]= 0xA7; // BLACK CLUB SUIT
+ ADBSYMBOL_U2C[0x2666]= 0xA8; // BLACK DIAMOND SUIT
+ ADBSYMBOL_U2C[0x2665]= 0xA9; // BLACK HEART SUIT
+ ADBSYMBOL_U2C[0x2660]= 0xAA; // BLACK SPADE SUIT
+ ADBSYMBOL_U2C[0x2194]= 0xAB; // LEFT RIGHT ARROW
+ ADBSYMBOL_U2C[0x2190]= 0xAC; // LEFTWARDS ARROW
+ ADBSYMBOL_U2C[0x2191]= 0xAD; // UPWARDS ARROW
+ ADBSYMBOL_U2C[0x2192]= 0xAE; // RIGHTWARDS ARROW
+ ADBSYMBOL_U2C[0x2193]= 0xAF; // DOWNWARDS ARROW
+ ADBSYMBOL_U2C[0x00B0]= 0xB0; // DEGREE SIGN
+ ADBSYMBOL_U2C[0x00B1]= 0xB1; // PLUS-MINUS SIGN
+ ADBSYMBOL_U2C[0x2033]= 0xB2; // DOUBLE PRIME
+ ADBSYMBOL_U2C[0x2265]= 0xB3; // GREATER-THAN OR EQUAL TO
+ ADBSYMBOL_U2C[0x00D7]= 0xB4; // MULTIPLICATION SIGN
+ ADBSYMBOL_U2C[0x221D]= 0xB5; // PROPORTIONAL TO
+ ADBSYMBOL_U2C[0x2202]= 0xB6; // PARTIAL DIFFERENTIAL
+ ADBSYMBOL_U2C[0x2022]= 0xB7; // BULLET
+ ADBSYMBOL_U2C[0x00F7]= 0xB8; // DIVISION SIGN
+ ADBSYMBOL_U2C[0x2260]= 0xB9; // NOT EQUAL TO
+ ADBSYMBOL_U2C[0x2261]= 0xBA; // IDENTICAL TO
+ ADBSYMBOL_U2C[0x2248]= 0xBB; // ALMOST EQUAL TO
+ ADBSYMBOL_U2C[0x2026]= 0xBC; // HORIZONTAL ELLIPSIS
+ ADBSYMBOL_U2C[0xF8E6]= 0xBD; // VERTICAL ARROW EXTENDER
+ ADBSYMBOL_U2C[0xF8E7]= 0xBE; // HORIZONTAL ARROW EXTENDER
+ ADBSYMBOL_U2C[0x21B5]= 0xBF; // DOWNWARDS ARROW WITH CORNER LEFTWARDS
+ ADBSYMBOL_U2C[0x2135]= 0xC0; // ALEF SYMBOL
+ ADBSYMBOL_U2C[0x2111]= 0xC1; // BLACK-LETTER CAPITAL I
+ ADBSYMBOL_U2C[0x211C]= 0xC2; // BLACK-LETTER CAPITAL R
+ ADBSYMBOL_U2C[0x2118]= 0xC3; // SCRIPT CAPITAL P
+ ADBSYMBOL_U2C[0x2297]= 0xC4; // CIRCLED TIMES
+ ADBSYMBOL_U2C[0x2295]= 0xC5; // CIRCLED PLUS
+ ADBSYMBOL_U2C[0x2205]= 0xC6; // EMPTY SET
+ ADBSYMBOL_U2C[0x2229]= 0xC7; // INTERSECTION
+ ADBSYMBOL_U2C[0x222A]= 0xC8; // UNION
+ ADBSYMBOL_U2C[0x2283]= 0xC9; // SUPERSET OF
+ ADBSYMBOL_U2C[0x2287]= 0xCA; // SUPERSET OF OR EQUAL TO
+ ADBSYMBOL_U2C[0x2284]= 0xCB; // NOT A SUBSET OF
+ ADBSYMBOL_U2C[0x2282]= 0xCC; // SUBSET OF
+ ADBSYMBOL_U2C[0x2286]= 0xCD; // SUBSET OF OR EQUAL TO
+ ADBSYMBOL_U2C[0x2208]= 0xCE; // ELEMENT OF
+ ADBSYMBOL_U2C[0x2209]= 0xCF; // NOT AN ELEMENT OF
+ ADBSYMBOL_U2C[0x2220]= 0xD0; // ANGLE
+ ADBSYMBOL_U2C[0x2207]= 0xD1; // NABLA
+ ADBSYMBOL_U2C[0xF6DA]= 0xD2; // REGISTERED SIGN SERIF
+ ADBSYMBOL_U2C[0xF6D9]= 0xD3; // COPYRIGHT SIGN SERIF
+ ADBSYMBOL_U2C[0xF6DB]= 0xD4; // TRADE MARK SIGN SERIF
+ ADBSYMBOL_U2C[0x220F]= 0xD5; // N-ARY PRODUCT
+ ADBSYMBOL_U2C[0x221A]= 0xD6; // SQUARE ROOT
+ ADBSYMBOL_U2C[0x22C5]= 0xD7; // DOT OPERATOR
+ ADBSYMBOL_U2C[0x00AC]= 0xD8; // NOT SIGN
+ ADBSYMBOL_U2C[0x2227]= 0xD9; // LOGICAL AND
+ ADBSYMBOL_U2C[0x2228]= 0xDA; // LOGICAL OR
+ ADBSYMBOL_U2C[0x21D4]= 0xDB; // LEFT RIGHT DOUBLE ARROW
+ ADBSYMBOL_U2C[0x21D0]= 0xDC; // LEFTWARDS DOUBLE ARROW
+ ADBSYMBOL_U2C[0x21D1]= 0xDD; // UPWARDS DOUBLE ARROW
+ ADBSYMBOL_U2C[0x21D2]= 0xDE; // RIGHTWARDS DOUBLE ARROW
+ ADBSYMBOL_U2C[0x21D3]= 0xDF; // DOWNWARDS DOUBLE ARROW
+ ADBSYMBOL_U2C[0x25CA]= 0xE0; // LOZENGE
+ ADBSYMBOL_U2C[0x2329]= 0xE1; // LEFT-POINTING ANGLE BRACKET
+ ADBSYMBOL_U2C[0xF8E8]= 0xE2; // REGISTERED SIGN SANS SERIF
+ ADBSYMBOL_U2C[0xF8E9]= 0xE3; // COPYRIGHT SIGN SANS SERIF
+ ADBSYMBOL_U2C[0xF8EA]= 0xE4; // TRADE MARK SIGN SANS SERIF
+ ADBSYMBOL_U2C[0x2211]= 0xE5; // N-ARY SUMMATION
+ ADBSYMBOL_U2C[0xF8EB]= 0xE6; // LEFT PAREN TOP
+ ADBSYMBOL_U2C[0xF8EC]= 0xE7; // LEFT PAREN EXTENDER
+ ADBSYMBOL_U2C[0xF8ED]= 0xE8; // LEFT PAREN BOTTOM
+ ADBSYMBOL_U2C[0xF8EE]= 0xE9; // LEFT SQUARE BRACKET TOP
+ ADBSYMBOL_U2C[0xF8EF]= 0xEA; // LEFT SQUARE BRACKET EXTENDER
+ ADBSYMBOL_U2C[0xF8F0]= 0xEB; // LEFT SQUARE BRACKET BOTTOM
+ ADBSYMBOL_U2C[0xF8F1]= 0xEC; // LEFT CURLY BRACKET TOP
+ ADBSYMBOL_U2C[0xF8F2]= 0xED; // LEFT CURLY BRACKET MID
+ ADBSYMBOL_U2C[0xF8F3]= 0xEE; // LEFT CURLY BRACKET BOTTOM
+ ADBSYMBOL_U2C[0xF8F4]= 0xEF; // CURLY BRACKET EXTENDER
+ ADBSYMBOL_U2C[0x232A]= 0xF1; // RIGHT-POINTING ANGLE BRACKET
+ ADBSYMBOL_U2C[0x222B]= 0xF2; // INTEGRAL
+ ADBSYMBOL_U2C[0x2320]= 0xF3; // TOP HALF INTEGRAL
+ ADBSYMBOL_U2C[0xF8F5]= 0xF4; // INTEGRAL EXTENDER
+ ADBSYMBOL_U2C[0x2321]= 0xF5; // BOTTOM HALF INTEGRAL
+ ADBSYMBOL_U2C[0xF8F6]= 0xF6; // RIGHT PAREN TOP
+ ADBSYMBOL_U2C[0xF8F7]= 0xF7; // RIGHT PAREN EXTENDER
+ ADBSYMBOL_U2C[0xF8F8]= 0xF8; // RIGHT PAREN BOTTOM
+ ADBSYMBOL_U2C[0xF8F9]= 0xF9; // RIGHT SQUARE BRACKET TOP
+ ADBSYMBOL_U2C[0xF8FA]= 0xFA; // RIGHT SQUARE BRACKET EXTENDER
+ ADBSYMBOL_U2C[0xF8FB]= 0xFB; // RIGHT SQUARE BRACKET BOTTOM
+ ADBSYMBOL_U2C[0xF8FC]= 0xFC; // RIGHT CURLY BRACKET TOP
+ ADBSYMBOL_U2C[0xF8FD]= 0xFD; // RIGHT CURLY BRACKET MID
+ ADBSYMBOL_U2C[0xF8FE]= 0xFE; // RIGHT CURLY BRACKET BOTTOM
+ }
+
+
+ @Override
+ public int encode(final int codepoint) {
+ return (codepoint >= 0 && codepoint < 0xffff) ? ADBSYMBOL_U2C[codepoint] : codepoint;
+ }
+
+ @Override
+ public String encode(final String s) {
+ final char[] encodedChars= new char[s.length()];
+ for (int i= 0; i < s.length(); i++) {
+ final char c= s.charAt(i);
+ encodedChars[i]= (c >= 0 && c < 0xffff) ? ADBSYMBOL_U2C[c] : c;
+ }
+ return new String(encodedChars);
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkg.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkg.java
new file mode 100644
index 0000000..9eb392b
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkg.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * Basic immutable R package, implementation of {@link RPkg}.
+ *
+ * @since de.walware.rj.renv.core 2.0
+ */
+public class BasicRPkg implements RPkg {
+
+
+ private final String name;
+
+ private final RNumVersion version;
+
+
+ public BasicRPkg(final String name, final RNumVersion version) {
+ if (name == null) {
+ throw new NullPointerException("name"); //$NON-NLS-1$
+ }
+ if (version == null) {
+ throw new NullPointerException("version"); //$NON-NLS-1$
+ }
+ this.name= name;
+ this.version= version;
+ }
+
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ @Override
+ public RNumVersion getVersion() {
+ return this.version;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return this.name.hashCode() + this.version.hashCode() * 7;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof RPkg)) {
+ return false;
+ }
+ final RPkg other= (RPkg) obj;
+ return (this.name.equals(other.getName()) && this.version.equals(other.getVersion()));
+ }
+
+
+ @Override
+ public String toString() {
+ if (this.version == RNumVersion.NONE) {
+ return this.name;
+ }
+ final StringBuilder sb= new StringBuilder(this.name.length() + this.version.toString().length() + 12);
+ sb.append(this.name);
+ sb.append(" (" + "version= ").append(this.version.toString());
+ sb.append(')');
+ return sb.toString();
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkgDescription.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkgDescription.java
new file mode 100644
index 0000000..f11352e
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/BasicRPkgDescription.java
@@ -0,0 +1,86 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * Basic immutable R package description, implementation {@link RPkgDescription}.
+ *
+ * @since de.walware.rj.renv.core 2.0
+ */
+public class BasicRPkgDescription extends BasicRPkg implements RPkgDescription {
+
+
+ private final String title;
+ private final String description;
+
+ private final String author;
+ private final String maintainer;
+ private final String url;
+
+ private final String built;
+
+
+ public BasicRPkgDescription(final String name, final RNumVersion version,
+ final String title, final String desription,
+ final String author, final String maintainer, final String url,
+ final String built) {
+ super(name, version);
+ this.title= title;
+ this.description= desription;
+ this.author= author;
+ this.maintainer= maintainer;
+ this.url= url;
+ this.built= built;
+ }
+
+
+ @Override
+ public String getTitle() {
+ return this.title;
+ }
+
+ @Override
+ public String getDescription() {
+ return this.description;
+ }
+
+ @Override
+ public String getAuthor() {
+ return this.author;
+ }
+
+ @Override
+ public String getMaintainer() {
+ return this.maintainer;
+ }
+
+ @Override
+ public String getUrl() {
+ return this.url;
+ }
+
+ @Override
+ public String getBuilt() {
+ return this.built;
+ }
+
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (obj instanceof RPkgDescription && super.equals(obj));
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RNumVersion.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RNumVersion.java
new file mode 100644
index 0000000..701a267
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RNumVersion.java
@@ -0,0 +1,204 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+
+/**
+ * @since de.walware.rj.renv.core 2.0
+ */
+public final class RNumVersion {
+
+ // First int in numeric version is the operator
+
+
+ public static final RNumVersion NONE= new RNumVersion(""); //$NON-NLS-1$
+
+
+ public static RNumVersion create(final String s) {
+ if (s == null || s.isEmpty()) {
+ return NONE;
+ }
+ return new RNumVersion(s);
+ }
+
+
+ private static final int OP_UNSUPPORTED= -2;
+ private static final int OP_NONE= -1;
+
+ private static final int OP_GE= 2;
+
+ static {
+ NONE.numeric= new int[] { OP_NONE };
+ }
+
+
+ private static final int[] parseVersion(final String s) {
+ final int[] v= new int[(3 + s.length())/2];
+ int idx= 1;
+ int i= 0;
+ if (s.startsWith(">=")) { //$NON-NLS-1$
+ v[0]= OP_GE;
+ i= 2;
+ }
+ int start= -3;
+ for (; i < s.length(); i++) {
+ final char c= s.charAt(i);
+ if (start == -3 && c == ' ') {
+ continue;
+ }
+ if (c >= '0' && c <= '9') {
+ if (start < 0) {
+ start= i;
+ }
+ continue;
+ }
+ if (start >= 0) {
+ v[idx++]= Integer.parseInt(s.substring(start, i));
+ start= -1;
+ if (c == '.' || c == '-') {
+ continue;
+ }
+ }
+ break;
+ }
+ if (start >= 0) {
+ v[idx++]= Integer.parseInt(s.substring(start, s.length()));
+ }
+ if (idx <= 2) {
+ v[0]= OP_UNSUPPORTED;
+ idx= 1;
+ }
+ return (v.length == idx) ? v : Arrays.copyOf(v, idx);
+ }
+
+
+ private final String string;
+
+ /** use {@link #getNumericVersion()} */
+ private volatile int[] numeric;
+
+
+ private RNumVersion(final String s) {
+ this.string= s;
+ }
+
+
+ public boolean isGreaterEqualThan(final RNumVersion pkgVersion2) {
+ return isGreaterEqualThan(getNumericVersion(), pkgVersion2.getNumericVersion());
+ }
+
+ private boolean isGreaterEqualThan(final int[] v1, final int[] v2) {
+ final int l= Math.max(v1.length, v2.length);
+ for (int i= 1; i < l; i++) {
+ final int diff= ((i < v1.length) ? v1[i] : 0) - ((i < v2.length) ? v2[i] : 0);
+ if (diff > 0) {
+ return true;
+ }
+ else if (diff < 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean isGreaterThan(final RNumVersion pkgVersion2) {
+ return isGreaterThan(getNumericVersion(), pkgVersion2.getNumericVersion());
+ }
+
+ private boolean isGreaterThan(final int[] v1, final int[] v2) {
+ final int l= Math.max(v1.length, v2.length);
+ for (int i= 1; i < l; i++) {
+ final int diff= ((i < v1.length) ? v1[i] : 0) - ((i < v2.length) ? v2[i] : 0);
+ if (diff > 0) {
+ return true;
+ }
+ else if (diff < 0) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ public boolean isSmallerThan(final RNumVersion pkgVersion2) {
+ return isSmallerThan(getNumericVersion(), pkgVersion2.getNumericVersion());
+ }
+
+ private boolean isSmallerThan(final int[] v1, final int[] v2) {
+ final int l= Math.max(v1.length, v2.length);
+ for (int i= 1; i < l; i++) {
+ final int diff= ((i < v1.length) ? v1[i] : 0) - ((i < v2.length) ? v2[i] : 0);
+ if (diff < 0) {
+ return true;
+ }
+ else if (diff > 0) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ public boolean isSatisfiedBy(final RNumVersion pkgVersion2) {
+ final int[] v1= getNumericVersion();
+ switch (v1[0]) {
+ case OP_GE:
+ return isGreaterEqualThan(pkgVersion2.getNumericVersion(), v1);
+ default:
+ return true;
+ }
+ }
+
+ public boolean isSatisfiedByAny(final Iterator<RNumVersion> pkgVersion2) {
+ final int[] v1= getNumericVersion();
+ switch (v1[0]) {
+ case OP_GE:
+ while (pkgVersion2.hasNext()) {
+ if (isGreaterEqualThan(pkgVersion2.next().getNumericVersion(), v1)) {
+ return true;
+ }
+ }
+ return false;
+ default:
+ return pkgVersion2.hasNext();
+ }
+ }
+
+ private int[] getNumericVersion() {
+ if (this.numeric == null) {
+ this.numeric= parseVersion(this.string);
+ }
+ return this.numeric;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return this.string.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (this == obj || (obj instanceof RNumVersion
+ && this.string.equals(((RNumVersion) obj).string) ));
+ }
+
+ @Override
+ public String toString() {
+ return this.string;
+ }
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkg.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkg.java
new file mode 100644
index 0000000..59f9aaa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkg.java
@@ -0,0 +1,42 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * R package.
+ *
+ * Basic interface for representation of an R package.
+ *
+ * @since de.walware.rj.renv.core 2.0
+ */
+public interface RPkg {
+
+
+ /**
+ * The name of the package.
+ *
+ * @return the name
+ */
+ String getName();
+
+ /**
+ * The version of the package.
+ *
+ * @return the version
+ */
+ RNumVersion getVersion();
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgDescription.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgDescription.java
new file mode 100644
index 0000000..dfafa6d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgDescription.java
@@ -0,0 +1,38 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * R package description.
+ *
+ * @since de.walware.rj.renv.core 2.0
+ */
+public interface RPkgDescription extends RPkg {
+
+
+ String getTitle();
+
+ String getDescription();
+
+ String getAuthor();
+
+ String getMaintainer();
+
+ String getUrl();
+
+ String getBuilt();
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgType.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgType.java
new file mode 100644
index 0000000..a7eba1d
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgType.java
@@ -0,0 +1,46 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+
+/**
+ * Type ({@link #SOURCE source} or {@link #BINARY binary}) of R packages.
+ *
+ * @since de.walware.rj.renv.core 2.0
+ */
+public enum RPkgType {
+
+
+ SOURCE("Source"),
+ BINARY("Binary");
+
+
+ private final String label;
+
+
+ private RPkgType(final String label) {
+ if (label == null) {
+ throw new NullPointerException("label"); //$NON-NLS-1$
+ }
+ this.label= label;
+ }
+
+
+ public String getLabel() {
+ return this.label;
+ }
+
+
+}
diff --git a/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgUtils.java b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgUtils.java
new file mode 100644
index 0000000..83dcffa
--- /dev/null
+++ b/core/org.eclipse.statet.rj.services.core/srcREnv/org/eclipse/statet/rj/renv/core/RPkgUtils.java
@@ -0,0 +1,115 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.renv.core;
+
+import java.text.MessageFormat;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.rj.services.RJServices;
+import org.eclipse.statet.rj.services.RPlatform;
+
+
+/**
+ * @since de.walware.rj.renv.core 2.0
+ */
+public class RPkgUtils {
+
+
+ private static boolean isWin(final RPlatform rPlatform) {
+ return rPlatform.getOsType().equals(RPlatform.OS_WINDOWS);
+ }
+
+ private static boolean isMac(final RPlatform rPlatform) {
+ return rPlatform.getOSName().regionMatches(true, 0, "Mac OS", 0, 6); //$NON-NLS-1$
+ }
+
+ public static RPkgType getPkgType(final String fileName, final RPlatform rPlatform) {
+ if (fileName.endsWith(".tar.gz")) { //$NON-NLS-1$
+ return RPkgType.SOURCE;
+ }
+ if (isWin(rPlatform)) {
+ if (fileName.toLowerCase().endsWith(".zip")) { //$NON-NLS-1$
+ return RPkgType.BINARY;
+ }
+ }
+ else if (isMac(rPlatform)) {
+ if (fileName.endsWith(".tgz")) { //$NON-NLS-1$
+ return RPkgType.BINARY;
+ }
+ }
+ return null;
+ }
+
+ public static RPkgType checkPkgType(final String fileName, final RPlatform rPlatform) throws CoreException {
+ final RPkgType pkgType= getPkgType(fileName, rPlatform);
+ if (pkgType == null) {
+ throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+ MessageFormat.format("Invalid file name ''{0}'' (unsupported extension) for R package on {1}.",
+ fileName, rPlatform.getOSName() )));
+ }
+ return pkgType;
+ }
+
+ /**
+ * Checks if the given file name has the standard format <code>name_version.extension</code>.
+ *
+ * @param fileName the file name to check
+ * @return a R package object with the detected name and version.
+ * @throws CoreException if the file name has not the standard format.
+ */
+ public static RPkg checkPkgFileName(final String fileName) throws CoreException {
+ final int extIdx;
+ if (fileName.endsWith(".tar.gz")) { //$NON-NLS-1$
+ extIdx= fileName.length() - 7;
+ }
+ else if (fileName.endsWith(".zip") || fileName.endsWith(".tgz")) { //$NON-NLS-1$ //$NON-NLS-2$
+ extIdx= fileName.length() - 4;
+ }
+ else {
+ throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+ MessageFormat.format("Invalid file name ''{0}'' (unsupported extension) for R package.",
+ fileName )));
+ }
+
+ final int versionIdx= fileName.indexOf('_');
+ if (versionIdx < 0) {
+ throw new CoreException(new Status(IStatus.ERROR, RJServices.BUNDLE_ID,
+ MessageFormat.format("Invalid file name ''{0}'' (missing version) for R package.",
+ fileName )));
+ }
+ return new BasicRPkg(fileName.substring(0, versionIdx),
+ RNumVersion.create(fileName.substring(versionIdx + 1, extIdx)) );
+ }
+
+ public static String getPkgTypeInstallKey(final RPlatform rPlatform, final RPkgType pkgType) {
+ if (pkgType == RPkgType.SOURCE) {
+ return "source"; //$NON-NLS-1$
+ }
+ if (pkgType == RPkgType.BINARY) {
+ if (isWin(rPlatform)) {
+ return "win.binary"; //$NON-NLS-1$
+ }
+ else if (isMac(rPlatform)) {
+ return "mac.binary.leopard"; //$NON-NLS-1$
+ }
+ }
+ return null;
+ }
+
+
+}
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/.project b/eclient/_build/org.eclipse.statet.rj.eclient-feature/.project
new file mode 100644
index 0000000..3c68cf6
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.eclient.core-feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/build.properties b/eclient/_build/org.eclipse.statet.rj.eclient-feature/build.properties
new file mode 100644
index 0000000..4fc35c8
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes= feature.xml,\
+ feature.properties
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.properties b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.properties
diff --git a/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.xml b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.xml
new file mode 100644
index 0000000..3ab7cbf
--- /dev/null
+++ b/eclient/_build/org.eclipse.statet.rj.eclient-feature/feature.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.statet.rj.eclient"
+ version="2.1.0.qualifier"
+ label="StatET RJ - Eclipse Client"
+ provider-name="Eclipse.org"
+ license-feature="org.eclipse.license"
+ license-feature-version="1.0.1">
+
+ <description url="https://www.eclipse.org/statet">
+ Client of high-level Java-R library RJ for projects based on the Eclipse Workbench
+ </description>
+
+ <copyright>
+ Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.
+ </copyright>
+
+ <license url="%license_url">
+ %license_text
+ </license>
+
+ <requires>
+ <import feature="org.eclipse.statet.rj.core" version="2.1.0" match="equivalent"/>
+ <import feature="org.eclipse.statet.ecommons.e" version="1.2.0" match="compatible"/>
+ </requires>
+
+ <plugin
+ id="org.eclipse.statet.rj.services.core"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.statet.rj.client"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.statet.rj.eclient"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
+ id="org.eclipse.statet.rj.eclient.graphics"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.classpath b/eclient/org.eclipse.statet.rj.eclient.core/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.gitignore b/eclient/org.eclipse.statet.rj.eclient.core/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.project b/eclient/org.eclipse.statet.rj.eclient.core/.project
new file mode 100644
index 0000000..889e8b2
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.eclient.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.resources.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..95ae74d
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
+encoding/about.ini=ISO-8859-1
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.runtime.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.core.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.ui.prefs b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/META-INF/MANIFEST.MF b/eclient/org.eclipse.statet.rj.eclient.core/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..0a9d294
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/META-INF/MANIFEST.MF
@@ -0,0 +1,12 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.eclient.core;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Eclipse Client - Core
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="1.1.0";visibility:=reexport,
+ org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)";visibility:=reexport,
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)";visibility:=reexport
+Export-Package: org.eclipse.statet.rj.eclient.core;version="1.2.0"
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/about.html b/eclient/org.eclipse.statet.rj.eclient.core/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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 <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+</p>
+
+<p>
+ 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 <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/about.ini b/eclient/org.eclipse.statet.rj.eclient.core/about.ini
new file mode 100644
index 0000000..bfba74e
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/about.ini
@@ -0,0 +1,7 @@
+featureImage= rj32.png
+aboutText= \
+StatET RJ - Eclipse Client\n\
+\n\
+Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.\n\
+Visit https://www.eclipse.org/statet\n\
+\n\
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/build.properties b/eclient/org.eclipse.statet.rj.eclient.core/build.properties
new file mode 100644
index 0000000..3240dd3
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/build.properties
@@ -0,0 +1,11 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ plugin.xml,\
+ .,\
+ about.html,\
+ about.ini,\
+ rj32.png
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/plugin.xml b/eclient/org.eclipse.statet.rj.eclient.core/plugin.xml
new file mode 100644
index 0000000..8d0cd29
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/plugin.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+
+</plugin>
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/rj32.png b/eclient/org.eclipse.statet.rj.eclient.core/rj32.png
new file mode 100644
index 0000000..d9450d1
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/rj32.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolCommandHandler.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolCommandHandler.java
new file mode 100644
index 0000000..ae24e3d
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolCommandHandler.java
@@ -0,0 +1,42 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.statet.ecommons.ts.core.ToolCommandHandler;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+
+/**
+ * @since 1.2
+ */
+public abstract class AbstractRToolCommandHandler implements ToolCommandHandler {
+
+
+ @Override
+ public IStatus execute(final String id, final ToolService service, final Map<String, Object> data,
+ final IProgressMonitor monitor) throws CoreException {
+ return execute(id, (RToolService) service, data, monitor);
+ }
+
+ protected abstract IStatus execute(String id, RToolService r, Map<String, Object> data,
+ IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolRunnable.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolRunnable.java
new file mode 100644
index 0000000..b208740
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/AbstractRToolRunnable.java
@@ -0,0 +1,75 @@
+/*=============================================================================#
+ # Copyright (c) 2010, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+
+/**
+ * Abstract runnable for R tool.
+ *
+ * Sub class should implement at least the method {@link #run(RToolService, IProgressMonitor)},
+ * which is called by the R tool and gives access to the {@link RToolService} API.
+ *
+ * @since 1.2
+ */
+public abstract class AbstractRToolRunnable implements ToolRunnable {
+
+
+ private final String fTypeId;
+ private final String fLabel;
+
+
+ public AbstractRToolRunnable(final String typeId, final String label) {
+ this.fTypeId= typeId;
+ this.fLabel= label;
+ }
+
+
+ @Override
+ public String getTypeId() {
+ return this.fTypeId;
+ }
+
+ @Override
+ public String getLabel() {
+ return this.fLabel;
+ }
+
+ @Override
+ public boolean canRunIn(final Tool tool) {
+ return tool.isProvidingFeatureSet("org.eclipse.statet.rj.services.RService"); //$NON-NLS-1$
+ }
+
+ @Override
+ public boolean changed(final int event, final Tool tool) {
+ return true;
+ }
+
+ @Override
+ public void run(final ToolService service,
+ final IProgressMonitor monitor) throws CoreException {
+ run((RToolService) service, monitor);
+ }
+
+ protected abstract void run(RToolService r,
+ IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/RToolService.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/RToolService.java
new file mode 100644
index 0000000..90a7455
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/RToolService.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2012, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * @since 1.2
+ */
+public interface RToolService extends ToolService, RService {
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/ToolFQRObjectRef.java b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/ToolFQRObjectRef.java
new file mode 100644
index 0000000..5ee87e4
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.core/src/org/eclipse/statet/rj/eclient/core/ToolFQRObjectRef.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.core;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.data.RLanguage;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.services.FQRObjectRef;
+
+
+public class ToolFQRObjectRef implements FQRObjectRef {
+
+
+ private static boolean isValidEnvObject(final RObject env) {
+ switch (env.getRObjectType()) {
+ case RObject.TYPE_REFERENCE:
+ return (((RReference) env).getReferencedRObjectType() == RObject.TYPE_ENVIRONMENT);
+ case RObject.TYPE_LANGUAGE:
+ return (((RLanguage) env).getLanguageType() == RLanguage.CALL);
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isValidNameObject(final RObject env) {
+ switch (env.getRObjectType()) {
+ case RObject.TYPE_LANGUAGE:
+ switch (((RLanguage) env).getLanguageType()) {
+ case RLanguage.NAME:
+ case RLanguage.CALL:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+
+
+ private final Tool tool;
+
+ private final RObject env;
+
+ private final RObject name;
+
+
+ public ToolFQRObjectRef(final Tool tool, final RObject env, final RObject name) {
+ if (tool == null) {
+ throw new NullPointerException("tool"); //$NON-NLS-1$
+ }
+ if (env == null) {
+ throw new NullPointerException("env"); //$NON-NLS-1$
+ }
+ if (!isValidEnvObject(env)) {
+ throw new IllegalArgumentException("env"); //$NON-NLS-1$
+ }
+ if (name == null) {
+ throw new NullPointerException("name"); //$NON-NLS-1$
+ }
+ if (!isValidNameObject(name)) {
+ throw new IllegalArgumentException("name"); //$NON-NLS-1$
+ }
+
+ this.tool= tool;
+ this.env= env;
+ this.name= name;
+ }
+
+
+ @Override
+ public Tool getRHandle() {
+ return this.tool;
+ }
+
+ @Override
+ public RObject getEnv() {
+ return this.env;
+ }
+
+ @Override
+ public RObject getName() {
+ return this.name;
+ }
+
+
+ @Override
+ public String toString() {
+ return this.env + "\n" + this.name.toString();
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.classpath b/eclient/org.eclipse.statet.rj.eclient.graphics/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.gitignore b/eclient/org.eclipse.statet.rj.eclient.graphics/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.project b/eclient/org.eclipse.statet.rj.eclient.graphics/.project
new file mode 100644
index 0000000..9fe0f82
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.eclient.graphics</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.resources.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.runtime.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.core.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.ui.prefs b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/META-INF/MANIFEST.MF b/eclient/org.eclipse.statet.rj.eclient.graphics/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..b8a3c0e
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/META-INF/MANIFEST.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.eclient.graphics;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - Eclipse Client - R Graphics
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.statet.internal.rj.eclient.graphics.RGraphicsPlugin
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.10.0",
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.client;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.eclient.core;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.ui;bundle-version="3.6.0",
+ org.eclipse.statet.ecommons.uimisc;bundle-version="[1.6.0,1.7.0)"
+Import-Package: org.eclipse.statet.ecommons.collections;version="1.6.0",
+ org.eclipse.statet.ecommons.databinding,
+ org.eclipse.statet.jcommons.collections;version="1.0.0",
+ org.eclipse.statet.jcommons.lang;version="1.0.0"
+Export-Package: org.eclipse.statet.rj.eclient.graphics,
+ org.eclipse.statet.rj.eclient.graphics.comclient,
+ org.eclipse.statet.rj.eclient.graphics.util
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/about.html b/eclient/org.eclipse.statet.rj.eclient.graphics/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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 <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+</p>
+
+<p>
+ 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 <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/build.properties b/eclient/org.eclipse.statet.rj.eclient.graphics/build.properties
new file mode 100644
index 0000000..d7ffd88
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/build.properties
@@ -0,0 +1,10 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ plugin.xml,\
+ .,\
+ icons/,\
+ about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-cancel.png b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-cancel.png
new file mode 100644
index 0000000..fd4d1c0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-cancel.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-done.png b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-done.png
new file mode 100644
index 0000000..185b13c
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/locator-done.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/resize-fit-r.png b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/resize-fit-r.png
new file mode 100644
index 0000000..ed4095f
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/icons/loctool_16/resize-fit-r.png
Binary files differ
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/plugin.xml b/eclient/org.eclipse.statet.rj.eclient.graphics/plugin.xml
new file mode 100644
index 0000000..43a93dc
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/plugin.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+
+ <extension
+ point="org.eclipse.equinox.preferences.preferences">
+ <initializer
+ class="org.eclipse.statet.internal.rj.eclient.graphics.PreferenceInitializer">
+ </initializer>
+ </extension>
+
+</plugin>
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/CircleElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/CircleElement.java
new file mode 100644
index 0000000..c4d4ef8
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/CircleElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RCircle;
+
+
+public class CircleElement extends RCircle implements ERGraphicInstruction {
+
+
+ public CircleElement(final double x, final double y, final double r) {
+ super(x, y, r);
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ClipSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ClipSetting.java
new file mode 100644
index 0000000..09c3dbb
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ClipSetting.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RClipSetting;
+
+
+public class ClipSetting extends RClipSetting implements ERGraphicInstruction {
+
+
+ public ClipSetting(final double x0, final double y0, final double x1, final double y1) {
+ super(x0, y0, x1, y1);
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorManager.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorManager.java
new file mode 100644
index 0000000..2da8f4d
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorManager.java
@@ -0,0 +1,55 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.statet.ecommons.collections.IntHashMap;
+import org.eclipse.statet.ecommons.collections.IntMap.IntEntry;
+
+
+public class ColorManager {
+
+
+ private final Display display;
+
+ private final IntHashMap<Color> colors= new IntHashMap<>(0x7f);
+
+
+ public ColorManager(final Display display) {
+ this.display= display;
+ }
+
+
+ public synchronized Color getColor(final int rgb) {
+ Color color= this.colors.get(rgb);
+ if (color == null) {
+ color= new Color(this.display,
+ (rgb & 0xff), ((rgb >>> 8) & 0xff), ((rgb >>> 16) & 0xff) );
+ this.colors.put(rgb, color);
+ }
+ return color;
+ }
+
+
+ public void dispose() {
+ for (final IntEntry<Color> entry : this.colors.entryIntSet()) {
+ entry.getValue().dispose();
+ }
+ this.colors.clear();
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorSetting.java
new file mode 100644
index 0000000..3ff0e97
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/ColorSetting.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RColorSetting;
+
+
+public class ColorSetting extends RColorSetting implements ERGraphicInstruction {
+
+
+ public final Color swtColor;
+
+
+ public ColorSetting(final int color, final Color swtColor) {
+ super(color);
+ this.swtColor= swtColor;
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphic.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphic.java
new file mode 100644
index 0000000..6b47463
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphic.java
@@ -0,0 +1,1312 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.graphics.PaletteData;
+import org.eclipse.swt.graphics.Path;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+
+import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.FontManager.FontFamily;
+import org.eclipse.statet.rj.eclient.graphics.DefaultGCRenderer;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.eclient.graphics.LocatorCallback;
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ToolRClientGraphicActions;
+import org.eclipse.statet.rj.eclient.graphics.util.CopyToDevRunnable;
+import org.eclipse.statet.rj.graphic.core.RGraphicInitialization;
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.util.CachedMapping;
+import org.eclipse.statet.rj.graphic.core.util.CharMapping;
+import org.eclipse.statet.rj.graphic.core.util.Unicode2AdbSymbolMapping;
+import org.eclipse.statet.rj.server.client.RClientGraphic;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.services.RService;
+import org.eclipse.statet.rj.services.RServiceControlExtension;
+
+
+/**
+ * R graphic implementation of this plug-in. Implements R side API ({@link RClientGraphic})
+ * as well as client side API ({@link ERGraphic}, {@link org.eclipse.statet.rj.graphic.core.RGraphic}).
+ */
+public class EclipseRGraphic implements RClientGraphic, ERGraphic {
+
+
+ private static final CharMapping ADBSYMBOL_MAPPING= new CachedMapping(
+ new Unicode2AdbSymbolMapping() );
+
+ private static final long MILLI_NANOS= 1000000L;
+
+ private static final int DIRECT_RED_MASK= 0x0000FF00;
+ private static final int DIRECT_GREEN_MASK= 0x00FF0000;
+ private static final int DIRECT_BLUE_MASK= 0xFF000000;
+ private static final PaletteData DIRECT_PALETTE= new PaletteData(
+ DIRECT_RED_MASK, DIRECT_GREEN_MASK, DIRECT_BLUE_MASK );
+
+ private static final LocatorCallback R_LOCATOR_CALLBACK= new LocatorCallback() {
+
+ @Override
+ public String getMessage() {
+ return "→ Locate a point by mouse click (request from R)";
+ }
+
+ @Override
+ public int located(final double x, final double y) {
+ return NEXT;
+ }
+
+ @Override
+ public void stopped(final String type) {
+ }
+
+ };
+
+
+ private static void disposeElements(final ERGraphicInstruction[] instructions,
+ final int beginIdx, final int endIdx) {
+ try {
+ for (int i= beginIdx; i < endIdx; i++) {
+ switch (instructions[i].getInstructionType()) {
+ case RGraphicInstruction.DRAW_RASTER: {
+ final Image image= ((RasterElement) instructions[i]).swtImage;
+ if (image != null && !image.isDisposed()) {
+ image.dispose();
+ }
+ continue; }
+ case RGraphicInstruction.DRAW_PATH: {
+ final Path path= ((PathElement) instructions[i]).swtPath;
+ if (path != null && !path.isDisposed()) {
+ path.dispose();
+ }
+ continue; }
+ default:
+ continue;
+ }
+ }
+ }
+ catch (final SWTException e) {
+ if (e.code != SWT.ERROR_DEVICE_DISPOSED) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID,
+ "An error occurred when disposing SWT resources.", e ));
+ }
+ }
+ }
+
+ private static class DisposeRunnable implements Runnable {
+
+ private final ERGraphicInstruction[] instructions;
+ private final int size;
+
+ private boolean delay;
+
+ public DisposeRunnable(final ERGraphicInstruction[] instructions, final int size) {
+ this.instructions= instructions;
+ this.size= size;
+ }
+
+ @Override
+ public void run() {
+ if (this.delay) {
+ this.delay= false;
+ Display.getCurrent().timerExec(5000, this);
+ }
+
+ disposeElements(this.instructions, 0, this.size);
+ }
+
+ }
+
+
+ private final int devId;
+
+ private int canvasColor;
+
+ private int drawingStopDelay= 33; // ms after stop
+ private int drawingForceDelay= 333; // ms after last update
+
+ private final EclipseRGraphicFactory manager;
+ private boolean isRClosed;
+ private boolean isLocalClosed;
+
+ private final Object stateLock= new Object();
+ private boolean isActive;
+ private boolean isActiveNotified;
+ private int mode= 1;
+ private int modeNotified;
+ private long drawingStoppedStamp;
+ private long instructionsNotifiedStamp;
+ private boolean stateNotificationDirectScheduled;
+ private boolean stateNotificationDelayedScheduled;
+ private final Runnable stateNotificationRunnable= new Runnable() {
+ @Override
+ public void run() {
+ int type= 0;
+ Runnable runnable= null;
+ try {
+ while (true) {
+ boolean reset= false;
+ List<ERGraphicInstruction> update= null;
+ synchronized (EclipseRGraphic.this.stateLock) {
+ if (type == 0
+ && !EclipseRGraphic.this.stateNotificationDirectScheduled
+ && EclipseRGraphic.this.stateNotificationDelayedScheduled) {
+ EclipseRGraphic.this.stateNotificationDirectScheduled= true;
+ EclipseRGraphic.this.stateNotificationDelayedScheduled= false;
+ }
+ if (EclipseRGraphic.this.isActive != EclipseRGraphic.this.isActiveNotified) {
+ EclipseRGraphic.this.isActiveNotified= EclipseRGraphic.this.isActive;
+ type= (EclipseRGraphic.this.isActive) ? 1 : 2;
+ }
+ else if ((EclipseRGraphic.this.mode == 1 || EclipseRGraphic.this.instructionsUpdateSize > 0)
+ && EclipseRGraphic.this.modeNotified != 1 ) {
+ // start
+ EclipseRGraphic.this.modeNotified= 1;
+ type= 3;
+ }
+ else if (EclipseRGraphic.this.instructionsUpdateSize > 0) {
+ // update
+ final long stamp= System.nanoTime();
+ int t= EclipseRGraphic.this.drawingForceDelay - (int) ((stamp - EclipseRGraphic.this.instructionsNotifiedStamp) / MILLI_NANOS);
+ if (t > 10 && EclipseRGraphic.this.mode != 1) {
+ t= Math.min(t, EclipseRGraphic.this.drawingStopDelay - (int) ((stamp - EclipseRGraphic.this.drawingStoppedStamp) / MILLI_NANOS));
+ }
+ if (t <= 10) {
+ reset= (EclipseRGraphic.this.instructionsUpdateStart == 0);
+
+ synchronized (EclipseRGraphic.this.instructionsLock) {
+ if (reset && EclipseRGraphic.this.instructionsSize > 0) {
+ runnable= new DisposeRunnable(EclipseRGraphic.this.instructions, EclipseRGraphic.this.instructionsSize);
+ }
+ EclipseRGraphic.this.instructions= EclipseRGraphic.this.instructionsUpdate;
+ EclipseRGraphic.this.instructionsSize= EclipseRGraphic.this.instructionsUpdateStart + EclipseRGraphic.this.instructionsUpdateSize;
+ }
+ update= ImCollections.newList(EclipseRGraphic.this.instructionsUpdate)
+ .subList(EclipseRGraphic.this.instructionsUpdateStart, EclipseRGraphic.this.instructionsUpdateStart + EclipseRGraphic.this.instructionsUpdateSize);
+// System.out.println("InstrUpdate: \treset= " + reset + " \tcount= " + update.size() + " \ttdiff= " + ((stamp - this.instructionsNotifiedStamp) / MILLI_NANOS));
+ EclipseRGraphic.this.instructionsUpdateStart= EclipseRGraphic.this.instructionsSize;
+ EclipseRGraphic.this.instructionsUpdateSize= 0;
+ EclipseRGraphic.this.instructionsNotifiedStamp= stamp;
+ type= 5;
+ }
+ else {
+ if (!EclipseRGraphic.this.stateNotificationDelayedScheduled) {
+ EclipseRGraphic.this.stateNotificationDelayedScheduled= true;
+ EclipseRGraphic.this.display.timerExec(10 + Math.min(t, EclipseRGraphic.this.drawingStopDelay), this);
+ }
+ EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+ type= 0;
+ return;
+ }
+ }
+ else if (EclipseRGraphic.this.mode != 1 && EclipseRGraphic.this.modeNotified == 1 ) {
+ // stop
+ final long stamp= System.nanoTime();
+ final int t= EclipseRGraphic.this.drawingStopDelay - (int) ((stamp - EclipseRGraphic.this.drawingStoppedStamp) / MILLI_NANOS);
+ if (t <= 10) {
+ EclipseRGraphic.this.modeNotified= 0;
+ type= 4;
+ }
+ else {
+ if (!EclipseRGraphic.this.stateNotificationDelayedScheduled) {
+ EclipseRGraphic.this.stateNotificationDelayedScheduled= true;
+ EclipseRGraphic.this.display.timerExec(10 + t, this);
+ }
+ EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+ type= 0;
+ return;
+ }
+ }
+ else {
+ // done
+ EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+ type= 0;
+ return;
+ }
+ }
+
+
+ switch (type) {
+ case 1:
+ for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+ listener.activated();
+ }
+ break;
+ case 2:
+ for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+ listener.deactivated();
+ }
+ break;
+ case 3:
+ for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+ listener.drawingStarted();
+ }
+ break;
+ case 4:
+ for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+ listener.drawingStopped();
+ }
+ break;
+ case 5:
+ for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+ if (listener instanceof ListenerInstructionsExtension) {
+ ((ListenerInstructionsExtension) listener).instructionsChanged(reset, update);
+ }
+ }
+// System.out.println("InstrNotif: ns= " + (System.nanoTime() - this.instructionsNotifiedStamp));
+ break;
+ }
+ }
+ }
+ finally {
+ if (type != 0) {
+ synchronized (EclipseRGraphic.this.stateLock) {
+ EclipseRGraphic.this.stateNotificationDirectScheduled= false;
+ }
+ }
+ if (runnable != null) {
+ execInDisplay(runnable);
+ }
+ }
+ }
+ };
+
+
+ private final int options;
+ private final ToolRClientGraphicActions actions;
+ private volatile double[] nextSize;
+ private double[] size;
+
+ private FontFamily currentFontFamily;
+ private int currentFontSize;
+ private int currentFontStyle;
+ private int currentFontRFace;
+ private CharMapping currentFontMapping;
+
+ private String lastStringEnc;
+ private double[] lastStringWidth;
+
+ private final Display display;
+ private boolean isDisposed;
+ private final FontManager swtFontManager;
+ private final ColorManager swtColorManager;
+
+ private String serifFontName;
+ private String sansFontName;
+ private String monoFontName;
+ private String symbolFontName;
+ private CharMapping symbolFontMapping;
+
+ /** List of newly added instructions */
+ private ERGraphicInstruction[] instructionsNew= new ERGraphicInstruction[1]; // initial init
+ /** Count of newly added instructions in {@link #instructionsNew} */
+ private int instructionsNewSize;
+ /** Current list of instructions, notified + not yet notified */
+ private ERGraphicInstruction[] instructionsUpdate;
+ /** Index of first not yet notified instruction in {@link #instructionsUpdate} */
+ private int instructionsUpdateStart;
+ /** Count of not yet notified instructions in {@link #instructionsUpdate} */
+ private int instructionsUpdateSize;
+ /** Lock for {@link #instructions} and {@link #instructionsSize} */
+ private final Object instructionsLock= new Object();
+ /** List of notified instructions */
+ private ERGraphicInstruction[] instructions;
+ /** Count of notified instructions in {@link #instructions} */
+ private int instructionsSize;
+
+ private final Object userExchangeLock= new Object();
+ private String userExchangeRType;
+ private RServiceControlExtension userExchangeRCallback;
+
+ private volatile LocatorCallback locatorCallback; // != null => started
+ private LocatorCallback locatorNotified;
+ private IStatus locatorMessage;
+ private Collection<String> locatorStopTypes= Collections.emptySet();
+ private double[] locatorLocationValue; // only used for R
+ private final Object locatorAnswerLock= new Object(); // pipe for answers
+
+ private final CopyOnWriteIdentityListSet<ERGraphic.Listener> graphicListeners= new CopyOnWriteIdentityListSet<>();
+
+ private IStatus message= Status.OK_STATUS;
+ private final CopyOnWriteIdentityListSet<StatusChangeListener> messageListeners= new CopyOnWriteIdentityListSet<>();
+
+ private boolean locatorNotificationDirectScheduled;
+ private boolean locatorNotificationDeferredScheduled;
+ private long locatorDeferredStamp;
+ private final Runnable locatorNotificationRunnable= new Runnable() {
+ @Override
+ public void run() {
+ int type= 0;
+ try {
+ while (true) {
+ synchronized (EclipseRGraphic.this.userExchangeLock) {
+ if (type == 0
+ && !EclipseRGraphic.this.locatorNotificationDirectScheduled
+ && EclipseRGraphic.this.locatorNotificationDeferredScheduled) {
+ EclipseRGraphic.this.locatorNotificationDirectScheduled= true;
+ EclipseRGraphic.this.locatorNotificationDeferredScheduled= false;
+ }
+ if (EclipseRGraphic.this.locatorCallback != null && EclipseRGraphic.this.locatorNotified == null
+ && EclipseRGraphic.this.locatorDeferredStamp == Long.MIN_VALUE) {
+ EclipseRGraphic.this.locatorNotified= EclipseRGraphic.this.locatorCallback;
+ type= 1;
+ }
+ else if (EclipseRGraphic.this.locatorNotified != null
+ && (EclipseRGraphic.this.locatorCallback != EclipseRGraphic.this.locatorNotified || EclipseRGraphic.this.locatorCallback == null) ){
+ EclipseRGraphic.this.locatorNotified= null;
+ type= 2;
+ }
+ else if (EclipseRGraphic.this.locatorDeferredStamp != Long.MIN_VALUE
+ && EclipseRGraphic.this.locatorCallback != null) {
+ final int t= (int) ((EclipseRGraphic.this.locatorDeferredStamp - System.nanoTime()) / 1000000);
+ if (t <= 10) {
+ internalStopLocator(false);
+ type= 3;
+ continue;
+ }
+ else {
+ if (!EclipseRGraphic.this.locatorNotificationDeferredScheduled) {
+ EclipseRGraphic.this.locatorNotificationDeferredScheduled= true;
+ EclipseRGraphic.this.display.timerExec(t + 10, this);
+ }
+ EclipseRGraphic.this.locatorNotificationDirectScheduled= false;
+ type= 0;
+ return;
+ }
+ }
+ else {
+ EclipseRGraphic.this.locatorNotificationDirectScheduled= false;
+ type= 0;
+ return;
+ }
+ }
+
+ switch (type) {
+ case 1:
+ for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+ if (listener instanceof ListenerLocatorExtension) {
+ ((ListenerLocatorExtension) listener).locatorStarted();
+ }
+ }
+ break;
+ case 2:
+ for (final Listener listener : EclipseRGraphic.this.graphicListeners.toList()) {
+ if (listener instanceof ListenerLocatorExtension) {
+ ((ListenerLocatorExtension) listener).locatorStopped();
+ }
+ }
+ break;
+ }
+ updateMessage();
+ }
+ }
+ finally {
+ if (type != 0) {
+ synchronized (EclipseRGraphic.this.userExchangeLock) {
+ EclipseRGraphic.this.locatorNotificationDirectScheduled= false;
+ }
+ }
+ }
+ }
+ };
+
+
+ public EclipseRGraphic(final int devId, final double w, final double h, final InitConfig config,
+ final boolean active, final ToolRClientGraphicActions actions, final int options,
+ final EclipseRGraphicFactory manager) {
+ this.devId= devId;
+ this.isActive= active;
+ this.actions= actions;
+ this.manager= manager;
+ this.options= options;
+
+ this.display= UIAccess.getDisplay();
+ this.swtFontManager= manager.getFontManager(this.display);
+// this.swtFontManager= new FontManager(this.display); // -> dispose!
+ this.swtColorManager= manager.getColorManager(this.display);
+
+ this.size= this.nextSize= new double[] { w, h };
+ initPanel(w, h, config);
+ }
+
+
+ @Override
+ public String getLabel() {
+ final StringBuilder sb= new StringBuilder();
+ sb.append("Device ");
+ sb.append(this.devId + 1);
+ if (this.actions != null) {
+ final String rLabel= this.actions.getRLabel();
+ if (rLabel != null && rLabel.length() > 0) {
+ sb.append(" │ ");
+ sb.append(rLabel);
+ }
+ }
+ final boolean locator= isLocatorStarted();
+ if (this.isActive || locator) {
+ sb.append(" \t<"); //$NON-NLS-1$
+ if (this.isActive) {
+ sb.append("active+"); //$NON-NLS-1$
+ }
+ if (locator) {
+ sb.append("locator+"); //$NON-NLS-1$
+ }
+ sb.replace(sb.length()-1, sb.length(), ">"); //$NON-NLS-1$
+ }
+ return sb.toString();
+ }
+
+ private void add(final ERGraphicInstruction instr) {
+ // adding is always in R thread
+ if (this.instructionsNew == null) {
+ this.instructionsNew= new ERGraphicInstruction[512];
+ }
+ else if (this.instructionsNewSize >= this.instructionsNew.length) {
+ final ERGraphicInstruction[] newArray= new ERGraphicInstruction[this.instructionsNewSize + 512];
+// System.out.println("NewArray " + this.instructionsNewSize + " -> " + newArray.length);
+ System.arraycopy(this.instructionsNew, 0, newArray, 0, this.instructionsNewSize);
+ this.instructionsNew= newArray;
+ }
+ this.instructionsNew[this.instructionsNewSize]= instr;
+ this.instructionsNewSize++;
+ }
+
+ protected void initPanel(final double w, final double h, final InitConfig config) {
+ this.drawingStopDelay= 33;
+ this.drawingForceDelay= 333;
+
+ this.currentFontFamily= null;
+ this.currentFontMapping= null;
+
+ final IPreferencesService preferences= Platform.getPreferencesService();
+ this.serifFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY, "", null);
+ this.sansFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SANS_FONTNAME_KEY, "", null);
+ this.monoFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_MONO_FONTNAME_KEY, "", null);
+ if (preferences.getBoolean(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SYMBOL_USE_KEY, true, null)) {
+ this.symbolFontName= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SYMBOL_FONTNAME_KEY, "Symbol", null); //$NON-NLS-1$
+ final String encoding= preferences.getString(RGraphics.FONTS_PREF_QUALIFIER, RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY, "AdobeSymbol", null); //$NON-NLS-1$
+ if ("AdobeSymbol".equals(encoding)) { //$NON-NLS-1$
+ this.symbolFontMapping= ADBSYMBOL_MAPPING;
+ }
+ else {
+ this.symbolFontMapping= null;
+ }
+ }
+ else {
+ this.symbolFontName= null;
+ this.symbolFontMapping= null;
+ }
+ this.canvasColor= (config.canvasColor & 0xffffff);
+
+ add(new GraphicInitialization(w, h, this.canvasColor, this.swtColorManager.getColor(this.canvasColor)));
+ }
+
+ @Override
+ public void reset(final double w, final double h, final InitConfig config) {
+ synchronized (this.stateLock) {
+ internalReset();
+ }
+
+ initPanel(w, h, config);
+ }
+
+ private void internalReset() {
+ if (this.instructionsNew != null) {
+ if (this.instructionsNewSize > 0) {
+ disposeElements(this.instructionsNew, 0, this.instructionsNewSize);
+ }
+ this.instructionsNew= null;
+ this.instructionsNewSize= 0;
+ }
+ if (this.instructionsUpdate != null) {
+ if (this.instructionsUpdateSize > 0) {
+ disposeElements(this.instructionsUpdate, this.instructionsUpdateStart, this.instructionsUpdateStart+this.instructionsUpdateSize);
+ }
+ this.instructionsUpdate= null;
+ this.instructionsUpdateStart= 0;
+ this.instructionsUpdateSize= 0;
+ }
+ this.drawingStoppedStamp= System.nanoTime();
+ this.instructionsNotifiedStamp= this.drawingStoppedStamp - 1000 * MILLI_NANOS;
+ }
+
+ private void execInDisplay(final Runnable runnable) {
+ try {
+ this.display.asyncExec(runnable);
+ }
+ catch (final SWTException e) {
+ if (e.code != SWT.ERROR_DEVICE_DISPOSED) {
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public int getDevId() {
+ return this.devId;
+ }
+
+ @Override
+ public void setActive(final boolean active) {
+ if (this.isActive == active) {
+ return;
+ }
+ synchronized (this.stateLock) {
+ this.isActive= active;
+ if (this.isDisposed) {
+ return;
+ }
+ if (!this.stateNotificationDirectScheduled) {
+ this.stateNotificationDirectScheduled= true;
+ execInDisplay(this.stateNotificationRunnable);
+ }
+ }
+ }
+
+ @Override
+ public boolean isActive() {
+ return this.isActive;
+ }
+
+ @Override
+ public void setMode(final int mode) {
+ synchronized (this.stateLock) {
+ if (this.mode == mode) {
+ return;
+ }
+ if (mode != 1) {
+ this.drawingStoppedStamp= System.nanoTime();
+ flushNewInstructions();
+ }
+ this.mode= mode;
+ if (this.isDisposed) {
+ return;
+ }
+ if (mode == 1 && this.modeNotified != 1 // need start
+ && !this.stateNotificationDirectScheduled ) {
+ this.stateNotificationDirectScheduled= true;
+ execInDisplay(this.stateNotificationRunnable);
+ }
+ else if (mode != 1 // stop
+ && !(this.stateNotificationDirectScheduled || this.stateNotificationDelayedScheduled) ) {
+ this.stateNotificationDirectScheduled= true;
+ execInDisplay(this.stateNotificationRunnable);
+ }
+ }
+ }
+
+ private void flushNewInstructions() {
+ if (this.instructionsNewSize > 0) {
+ if (this.instructionsUpdate == null) {
+ this.instructionsUpdate= this.instructionsNew;
+ this.instructionsUpdateStart= 0;
+ this.instructionsUpdateSize= this.instructionsNewSize;
+ this.instructionsNew= null;
+ this.instructionsNewSize= 0;
+ }
+ else {
+ final int newSize= this.instructionsUpdateStart + this.instructionsUpdateSize + this.instructionsNewSize;
+ if (newSize > this.instructionsUpdate.length) {
+ final ERGraphicInstruction[] newArray= new ERGraphicInstruction[newSize + 512];
+ System.arraycopy(this.instructionsUpdate, 0, newArray, 0, this.instructionsUpdateStart + this.instructionsUpdateSize);
+ this.instructionsUpdate= newArray;
+ }
+ System.arraycopy(this.instructionsNew, 0, this.instructionsUpdate, this.instructionsUpdateStart + this.instructionsUpdateSize, this.instructionsNewSize);
+ this.instructionsUpdateSize+= this.instructionsNewSize;
+ this.instructionsNewSize= 0;
+ }
+ }
+ }
+
+ private List<ERGraphicInstruction> getCurrentInstructions() {
+ synchronized (this.stateLock) {
+ flushNewInstructions();
+ return ImCollections.newList(this.instructionsUpdate).subList(0,
+ this.instructionsSize + this.instructionsUpdateSize );
+ }
+ }
+
+ @Override
+ public double[] computeSize() {
+ return this.size;
+ }
+
+
+ protected void printFont() {
+ System.out.println(this.currentFontFamily.name + " " + this.currentFontStyle + " " + this.currentFontSize);
+ }
+
+ @Override
+ public double[] computeFontMetric(final int ch) {
+// System.out.println("==\nTextMetrics: \"" + ((char) ch) + "\" (" + ch + ")"); printFont();
+ return this.currentFontFamily.getCharMetrics(this.currentFontStyle, this.currentFontSize,
+ (this.currentFontMapping != null) ? this.currentFontMapping.encode(ch) : ch );
+ }
+
+ @Override
+ public double[] computeStringWidth(final String txt) {
+// System.out.println("==\nTextWidth: \"" + txt + "\""); printFont();
+ return computeStringWidthEnc((this.currentFontMapping != null) ? this.currentFontMapping.encode(txt) : txt);
+ }
+
+ protected final double[] computeStringWidthEnc(final String text) {
+ if (text.equals(this.lastStringEnc)) {
+ return this.lastStringWidth;
+ }
+
+ final double[] answer= this.currentFontFamily.getStringWidth(this.currentFontStyle, this.currentFontSize, text);
+
+ this.lastStringEnc= text;
+ return (this.lastStringWidth= answer);
+ }
+
+
+ @Override
+ public void addSetClip(final double x0, final double y0, final double x1, final double y1) {
+ final ClipSetting instr= new ClipSetting(x0, y0, x1, y1);
+ add(instr);
+ }
+
+ @Override
+ public void addSetColor(final int color) {
+ final ColorSetting instr= new ColorSetting(color,
+ this.swtColorManager.getColor((color & 0xffffff)) );
+ add(instr);
+ }
+
+ @Override
+ public void addSetFill(final int color) {
+ final FillSetting instr= new FillSetting(color,
+ this.swtColorManager.getColor((color & 0xffffff)) );
+ add(instr);
+ }
+
+ @Override
+ public void addSetFont(String family, final int face, final float pointSize,
+ final float lineHeight) {
+// System.out.println("==\nSetFont: \"" + family + "\" " + face + " " + pointSize);
+ switch (face) {
+ case 2:
+ case 3:
+ case 4:
+ family= getFontName(family);
+ this.currentFontStyle= face - 1;
+ this.currentFontMapping= null;
+ break;
+ case 5:
+ if (this.symbolFontName != null) {
+ family= this.symbolFontName;
+ this.currentFontStyle= 0;
+ this.currentFontMapping= this.symbolFontMapping;
+ break;
+ }
+ //$FALL-THROUGH$
+ default:
+ family= getFontName(family);
+ this.currentFontStyle= 0;
+ this.currentFontMapping= null;
+ break;
+ }
+ this.currentFontFamily= this.swtFontManager.getFamily(family);
+ this.currentFontRFace= face;
+ this.currentFontSize= (int) (pointSize + 0.5);
+
+ this.lastStringEnc= null;
+
+ final FontSetting instr= new FontSetting(family, face, pointSize, lineHeight,
+ this.currentFontFamily.getSWTFont(this.currentFontStyle, this.currentFontSize),
+ this.currentFontFamily.getSWTFontProperties(this.currentFontStyle, this.currentFontSize) );
+ add(instr);
+ }
+
+ private String getFontName(final String family) {
+ if (family.length() == 0 || family.equals("sansserif")) {
+ return this.sansFontName;
+ }
+ else if (family.equals("serif")) {
+ return this.serifFontName;
+ }
+ else if (family.equals("mono")) {
+ return this.monoFontName;
+ }
+ else {
+ return family;
+ }
+ }
+
+ @Override
+ public void addSetLine(final int type, final float width,
+ final byte cap, final byte join, final float joinMiterLimit) {
+ final LineSetting instr= new LineSetting(type, width, cap, join, joinMiterLimit);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawLine(final double x0, final double y0, final double x1, final double y1) {
+ final LineElement instr= new LineElement(x0, y0, x1, y1);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawRect(final double x0, final double y0, final double x1, final double y1) {
+ final RectElement instr= new RectElement(x0, y0, x1, y1);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawPolyline(final double[] x, final double[] y) {
+ final PolylineElement instr= new PolylineElement(x, y);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawPolygon(final double[] x, final double[] y) {
+ final PolygonElement instr= new PolygonElement(x, y);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawPath(final int[] n, final double[] x, final double[] y, final int winding) {
+ final Path path= new Path(this.display);
+ int k= 0, end= 0;
+ for (int i= 0; i < n.length; i++) {
+ end+= n[i];
+ path.moveTo((float) Math.floor(x[k] + 0.5), (float) Math.floor(y[k++] + 0.5));
+ while (k < end) {
+ path.lineTo((float) Math.floor(x[k] + 0.5), (float) Math.floor(y[k++] + 0.5));
+ }
+ path.close();
+ }
+ final PathElement instr= new PathElement(n, x, y, winding, path);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawCircle(final double x, final double y, final double r) {
+ final CircleElement instr= new CircleElement(x, y, r);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawText(final String txt,
+ final double x, final double y, final double rDeg, final double hAdj) {
+// System.out.println("==\nDrawText: " + x + ", " + y + " " + hAdj + " \"" + txt + "\""); printFont();
+ final String text= (this.currentFontMapping != null) ? this.currentFontMapping.encode(txt) : txt;
+ final TextElement instr= new TextElement(text, x, y, rDeg, hAdj,
+ (hAdj != 0) ? computeStringWidthEnc(text)[0] : 0);
+ add(instr);
+ }
+
+ @Override
+ public void addDrawRaster(final byte[] imgData, final boolean hasAlpha,
+ final int imgWidth, final int imgHeight,
+ final double x, final double y, final double w, final double h,
+ final double rDeg, final boolean interpolate) {
+ final ImageData imageData= new ImageData(imgWidth, imgHeight, 32, DIRECT_PALETTE, 4, imgData);
+ if (hasAlpha) {
+ final byte[] alpha= new byte[imgWidth*imgHeight];
+ for (int i= 0; i < alpha.length; i++) {
+ alpha[i]= imgData[i*4 + 3];
+ }
+ imageData.alphaData= alpha;
+ }
+ final Image swtImage= new Image(this.display, imageData);
+ final RasterElement instr= new RasterElement(imgData, imgWidth, imgHeight, x, y, w, h,
+ rDeg, interpolate, swtImage );
+ add(instr);
+ }
+
+ @Override
+ public byte[] capture(final int width, final int height) {
+ ImageData imageData;
+ { Image image= null;
+ GC gc= null;
+ try {
+ image= new Image(this.display, width, height);
+ gc= new GC(image);
+ final DefaultGCRenderer renderer= new DefaultGCRenderer();
+ final List<ERGraphicInstruction> instructions= getCurrentInstructions();
+ if (instructions.isEmpty()) {
+ return null;
+ }
+ { final RGraphicInitialization init= (RGraphicInitialization) instructions.get(0);
+ double scale;
+ if (width == (int) (init.width + 0.5)) {
+ scale= 1.0;
+ }
+ else {
+ scale= width / init.width;
+ }
+ renderer.clear(scale);
+ }
+ renderer.paint(gc, instructions);
+ gc.dispose();
+ gc= null;
+ imageData= image.getImageData();
+ image.dispose();
+ image= null;
+ }
+ finally {
+ if (gc != null && !gc.isDisposed()) {
+ gc.dispose();
+ }
+ if (image != null && !image.isDisposed()) {
+ image.dispose();
+ }
+ }
+ }
+ if (imageData == null || !imageData.palette.isDirect) {
+ return null;
+ }
+ if (imageData.palette.redMask != DIRECT_RED_MASK
+ || imageData.palette.greenMask != DIRECT_GREEN_MASK
+ || imageData.palette.blueMask != DIRECT_BLUE_MASK
+ || imageData.scanlinePad != 4
+ || imageData.bytesPerLine != width * 4
+ || imageData.data.length != width * height * 4 ) {
+ final byte[] data= (imageData.data.length == width * height * 4) ?
+ imageData.data : new byte[width * height * 4];
+ final int blueMask= imageData.palette.blueMask;
+ final int blueShift= imageData.palette.blueShift;
+ final int greenMask= imageData.palette.greenMask;
+ final int greenShift= imageData.palette.greenShift;
+ final int redMask= imageData.palette.redMask;
+ final int redShift= imageData.palette.redShift;
+ int i= 0;
+ for (int y= 0; y < height; y++) {
+ for (int x= 0; x < width; x++) {
+ final int p= imageData.getPixel(x, y);
+ data[i++]= (blueShift < 0) ?
+ (byte) ((p & blueMask) >>> -blueShift) :
+ (byte) ((p & blueMask) << blueShift);
+ data[i++]= (greenShift < 0) ?
+ (byte) ((p & greenMask) >>> -greenShift) :
+ (byte) ((p & greenMask) << greenShift);
+ data[i++]= (redShift < 0) ?
+ (byte) ((p & redMask) >>> -redShift) :
+ (byte) ((p & redMask) << redShift);
+ data[i++]= (byte) 255;
+ }
+ }
+ return data;
+ }
+ return imageData.data;
+ }
+
+
+ protected void waitRUserExchange(final String type, final RService r, final IProgressMonitor monitor,
+ final Callable<Boolean> cancelListener) {
+ final RServiceControlExtension rControl= (r instanceof RServiceControlExtension) ?
+ (RServiceControlExtension) r : null;
+ if (rControl != null && cancelListener != null) {
+ rControl.addCancelHandler(cancelListener);
+ rControl.getWaitLock().lock();
+ }
+ try {
+ while (true) {
+ synchronized (this.userExchangeLock) {
+ if (this.userExchangeRType != type) {
+ this.userExchangeRCallback= null;
+ return;
+ }
+ if (this.isLocalClosed || this.isRClosed || monitor.isCanceled() ) {
+ this.userExchangeRType= null;
+ this.userExchangeRCallback= null;
+ return;
+ }
+ this.userExchangeRCallback= rControl;
+ }
+
+ if (rControl != null) {
+ rControl.waitingForUser(monitor);
+ }
+ else {
+ try {
+ Thread.sleep(50);
+ }
+ catch (final InterruptedException e) {
+ }
+ }
+ }
+ }
+ finally {
+ if (rControl != null && cancelListener != null) {
+ rControl.getWaitLock().unlock();
+ rControl.removeCancelHandler(cancelListener);
+ }
+ }
+ }
+
+
+ private void internalStartLocator(final LocatorCallback callback) {
+ this.locatorCallback= callback;
+ this.locatorMessage= new Status(IStatus.INFO, RGraphics.BUNDLE_ID, callback.getMessage());
+ this.locatorStopTypes= callback.getStopTypes();
+ this.locatorDeferredStamp= Long.MIN_VALUE;
+
+ if (this.display.isDisposed()) {
+ return;
+ }
+ if (!this.locatorNotificationDirectScheduled) {
+ execInDisplay(this.locatorNotificationRunnable);
+ }
+ }
+
+ private void internalStopLocator(final boolean deferred) {
+ if (deferred) {
+ this.locatorDeferredStamp= System.nanoTime() + 500 * MILLI_NANOS;
+ if (this.display.isDisposed()) {
+ return;
+ }
+ if (!(this.locatorNotificationDirectScheduled || this.locatorNotificationDeferredScheduled)) {
+ this.locatorNotificationDirectScheduled= true;
+ execInDisplay(this.locatorNotificationRunnable);
+ }
+ return;
+ }
+
+ this.locatorCallback= null;
+ this.locatorMessage= null;
+ this.locatorStopTypes= Collections.emptySet();
+ this.locatorDeferredStamp= Long.MIN_VALUE;
+
+ if (this.display.isDisposed()) {
+ return;
+ }
+ if (!this.locatorNotificationDirectScheduled) {
+ this.locatorNotificationDirectScheduled= true;
+ execInDisplay(this.locatorNotificationRunnable);
+ }
+ }
+
+ @Override
+ public double[] runRLocator(final RService r, final IProgressMonitor monitor) {
+ synchronized (this.userExchangeLock) {
+ if (this.locatorCallback != null && this.locatorCallback != R_LOCATOR_CALLBACK) {
+ return null;
+ }
+ this.userExchangeRType= "locator";
+ internalStartLocator(R_LOCATOR_CALLBACK);
+
+ this.locatorLocationValue= null;
+ }
+ waitRUserExchange("locator", r, monitor, new Callable<Boolean>() {
+ @Override
+ public Boolean call() {
+ return Boolean.valueOf(answerLocator(null, null, true));
+ }
+ });
+ final double[] value;
+ synchronized (this.userExchangeLock) {
+ value= this.locatorLocationValue;
+ if (this.userExchangeRType == "locator") {
+ this.userExchangeRType= null;
+ }
+ // avoid flickering as well as stale locators
+ internalStopLocator(value != null);
+ }
+ return value;
+ }
+
+ @Override
+ public IStatus startLocalLocator(final LocatorCallback callback) {
+ if (callback == null) {
+ throw new NullPointerException("callback"); //$NON-NLS-1$
+ }
+ synchronized (this.userExchangeLock) {
+ if (this.locatorCallback != null && this.locatorCallback != callback) {
+ return new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, "Another locator is already started.");
+ }
+ internalStartLocator(callback);
+ }
+ return Status.OK_STATUS;
+ }
+
+ @Override
+ public boolean isLocatorStarted() {
+ return (this.locatorCallback != null);
+ }
+
+ @Override
+ public Collection<String> getLocatorStopTypes() {
+ return this.locatorStopTypes;
+ }
+
+ @Override
+ public void returnLocator(final double x, final double y) {
+ answerLocator(null, new double[] { x, y }, false);
+ }
+
+ @Override
+ public void stopLocator(final String type) {
+ answerLocator(type, null, false);
+ }
+
+ private boolean answerLocator(final String type, final double[] xy,
+ final boolean onlyR) {
+ synchronized (this.locatorAnswerLock) {
+ RServiceControlExtension rControl= null;
+ LocatorCallback callback;
+ synchronized (this.userExchangeLock) {
+ if (this.locatorCallback == null || this.locatorDeferredStamp != Long.MIN_VALUE) {
+ return false;
+ }
+ if (this.locatorCallback == R_LOCATOR_CALLBACK) {
+ if (this.userExchangeRType == "locator") { //$NON-NLS-1$
+ this.userExchangeRType= null;
+ rControl= this.userExchangeRCallback;
+ }
+ else {
+ return false;
+ }
+ }
+ else if (onlyR) {
+ return false;
+ }
+ if (xy == null && type != null && !this.locatorStopTypes.contains(type)) {
+ return false;
+ }
+ this.locatorLocationValue= xy;
+ callback= this.locatorCallback;
+ }
+
+ final int code;
+ if (callback == R_LOCATOR_CALLBACK) {
+ if (xy != null) {
+ code= -1;
+ }
+ else {
+ code= LocatorCallback.STOP;
+ }
+ if (rControl != null) {
+ rControl.getWaitLock().lock();
+ try {
+ rControl.resume();
+ }
+ finally {
+ rControl.getWaitLock().unlock();
+ }
+ }
+ }
+ else {
+ if (xy != null) {
+ code= callback.located(xy[0], xy[1]);
+ }
+ else {
+ code= LocatorCallback.STOP;
+ callback.stopped(type);
+ }
+ }
+ synchronized (this.userExchangeLock) {
+ if (code == LocatorCallback.NEXT) {
+ internalStartLocator(callback);
+ }
+ else {
+ internalStopLocator((code == -1));
+ }
+ }
+ return true;
+ }
+ }
+
+
+ public void closeFromR() {
+ this.isRClosed= true;
+ if (this.isLocalClosed
+ || (this.options & RClientGraphicFactory.R_CLOSE_OFF) == 0) {
+ dispose();
+ }
+ answerLocator(null, null, true);
+ setActive(false);
+ }
+
+ protected void dispose() {
+ this.graphicListeners.clear();
+ Runnable runnable= null;
+ synchronized (this.stateLock) {
+ if (!this.isDisposed) {
+ this.isDisposed= true;
+ internalReset();
+ synchronized (this.instructionsLock) {
+ if (this.instructionsSize > 0) {
+ runnable= new DisposeRunnable(this.instructions, this.instructionsSize);
+ }
+ this.instructionsSize= 0;
+ this.instructions= null;
+ }
+ }
+ }
+ if (runnable != null) {
+ execInDisplay(runnable);
+ }
+ }
+
+
+ @Override
+ public List<ERGraphicInstruction> getInstructions() {
+ synchronized (this.instructionsLock) {
+ return (this.instructionsSize > 0) ?
+ ImCollections.newList(this.instructions).subList(0, this.instructionsSize) :
+ ImCollections.<ERGraphicInstruction>emptyList();
+ }
+ }
+
+ @Override
+ public Tool getRHandle() {
+ if (this.actions != null) {
+ return this.actions.getRHandle();
+ }
+ return null;
+ }
+
+ @Override
+ public IStatus resize(final double w, final double h) {
+ if (this.actions != null) {
+ this.nextSize= new double[] { w, h };
+ return this.actions.resizeGraphic(this.devId, new Runnable() {
+ @Override
+ public void run() {
+ EclipseRGraphic.this.size= EclipseRGraphic.this.nextSize;
+ }
+ });
+ }
+ return null;
+ }
+
+ @Override
+ public IStatus close() {
+ if (this.isRClosed) {
+ this.isLocalClosed= true;
+ dispose();
+ }
+ if (this.actions != null) {
+ answerLocator(null, null, false);
+ return this.actions.closeGraphic(this.devId);
+ }
+ else {
+ this.isLocalClosed= true;
+ answerLocator(null, null, false);
+ this.manager.close(this);
+ dispose();
+ }
+ return null;
+ }
+
+ @Override
+ public void addListener(final Listener listener) {
+ this.graphicListeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(final Listener listener) {
+ this.graphicListeners.remove(listener);
+ }
+
+ protected void updateMessage() {
+ IStatus message;
+ if (this.locatorMessage != null) {
+ message= this.locatorMessage;
+ }
+ else {
+ message= Status.OK_STATUS;
+ }
+ if (!this.message.equals(message)) {
+ this.message= message;
+ for (final StatusChangeListener listener : this.messageListeners.toList()) {
+ listener.statusChanged(message);
+ }
+ }
+ }
+
+ @Override
+ public IStatus getMessage() {
+ return this.message;
+ }
+
+ @Override
+ public void addMessageListener(final StatusChangeListener listener) {
+ this.messageListeners.add(listener);
+ }
+
+ @Override
+ public void removeMessageListener(final StatusChangeListener listener) {
+ this.messageListeners.remove(listener);
+ }
+
+
+ protected void preAction() throws CoreException {
+ if (this.actions == null || this.actions.getRHandle() == null) {
+ throw new UnsupportedOperationException();
+ }
+ if (this.isRClosed) {
+ throw new CoreException(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID,
+ "The R graphic device is already closed." ));
+ }
+ }
+
+ @Override
+ @Deprecated
+ public IStatus copy(final String toDev, final String toDevFile, final String toDevArgs)
+ throws CoreException {
+ preAction();
+ return this.actions.getRHandle().getQueue().add(new CopyToDevRunnable(this,
+ toDev, toDevFile, toDevArgs ));
+ }
+
+ @Override
+ public void copy(final String toDev, final String toDevFile, final String toDevArgs,
+ final IProgressMonitor monitor) throws CoreException {
+ preAction();
+ this.actions.copy(this.devId, toDev, toDevFile, toDevArgs, monitor);
+ }
+
+ @Override
+ public double[] convertGraphic2User(final double[] xy,
+ final IProgressMonitor monitor) throws CoreException {
+ preAction();
+ return this.actions.convertGraphic2User(this.devId, xy, monitor);
+ }
+
+ @Override
+ public double[] convertUser2Graphic(final double[] xy,
+ final IProgressMonitor monitor) throws CoreException {
+ preAction();
+ return this.actions.convertUser2Graphic(this.devId, xy, monitor);
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphicFactory.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphicFactory.java
new file mode 100644
index 0000000..d17aae4
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/EclipseRGraphicFactory.java
@@ -0,0 +1,271 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.core.runtime.preferences.IPreferencesService;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Display;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.ImIdentityList;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicsManager;
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicsPreferencePage;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ToolRClientGraphicActions;
+import org.eclipse.statet.rj.server.client.RClientGraphic;
+import org.eclipse.statet.rj.server.client.RClientGraphicActions;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+
+
+/**
+ * Factory and manager implementation for R graphics under Eclipse.
+ * <p>
+ * Public class is {@link org.eclipse.statet.rj.eclient.graphics.comclient.ERGraphicFactory}.</p>
+ */
+public class EclipseRGraphicFactory implements RClientGraphicFactory, ERGraphicsManager {
+
+
+ private static class AddedSafeRunnable implements ISafeRunnable {
+
+ ERGraphic graphic;
+ ERGraphicsManager.Listener listener;
+
+ @Override
+ public void run() {
+ this.listener.graphicAdded(this.graphic);
+ }
+
+ @Override
+ public void handleException(final Throwable exception) {
+// RGraphicsPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, RGraphicsPlugin.BUNDLE_ID, 0,
+// "An error occurred when notifying.", exception)); //$NON-NLS-1$
+ }
+
+ }
+
+ private static class RemovedSafeRunnable implements ISafeRunnable {
+
+ ERGraphic graphic;
+ ERGraphicsManager.Listener listener;
+
+ @Override
+ public void run() {
+ this.listener.graphicRemoved(this.graphic);
+ }
+
+ @Override
+ public void handleException(final Throwable exception) {
+ }
+
+ }
+
+ private static class ShowSafeRunnable implements ISafeRunnable {
+
+ ERGraphic graphic;
+ ERGraphicsManager.ListenerShowExtension listener;
+
+ int bestPriority;
+ ERGraphicsManager.ListenerShowExtension bestListener;
+
+ @Override
+ public void run() {
+ if (this.listener != null) {
+ final int priority= this.listener.canShowGraphic(this.graphic);
+ if (priority > this.bestPriority) {
+ this.bestPriority= priority;
+ this.bestListener= this.listener;
+ }
+ }
+ else {
+ this.bestListener.showGraphic(this.graphic);
+ }
+ }
+
+ @Override
+ public void handleException(final Throwable exception) {
+// RGraphicsPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, RGraphicsPlugin.BUNDLE_ID, 0,
+// "An error occurred when notifying.", exception)); //$NON-NLS-1$
+ }
+
+ }
+
+
+ private final CopyOnWriteIdentityListSet<EclipseRGraphic> graphics= new CopyOnWriteIdentityListSet<>();
+
+ private final CopyOnWriteIdentityListSet<ERGraphicsManager.Listener> listeners= new CopyOnWriteIdentityListSet<>();
+ private final AddedSafeRunnable addedRunnable= new AddedSafeRunnable();
+ private final RemovedSafeRunnable removedRunnable= new RemovedSafeRunnable();
+ private final ShowSafeRunnable showRunnable= new ShowSafeRunnable();
+
+ private final Display defaultDisplay;
+ private final FontManager fontManager;
+ private final ColorManager colorManager;
+
+
+ public EclipseRGraphicFactory() {
+ this.defaultDisplay= UIAccess.getDisplay();
+ this.fontManager= new FontManager(this.defaultDisplay);
+ this.colorManager= new ColorManager(this.defaultDisplay);
+ this.defaultDisplay.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ EclipseRGraphicFactory.this.defaultDisplay.disposeExec(new Runnable() {
+ @Override
+ public void run() {
+ EclipseRGraphicFactory.this.fontManager.dispose();
+ EclipseRGraphicFactory.this.colorManager.dispose();
+ }
+ });
+ }
+ });
+ }
+
+
+ @Override
+ public Map<String, ? extends Object> getInitServerProperties() {
+ final Map<String, Object> map= new HashMap<>();
+ final IPreferencesService preferences= Platform.getPreferencesService();
+ final AtomicReference<double[]> dpi= new AtomicReference<>();
+ dpi.set(RGraphicsPreferencePage.parseDPI(preferences.getString(
+ RGraphics.PREF_DISPLAY_QUALIFIER, RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY, null, null )));
+ if (dpi.get() == null) {
+ Display.getDefault().syncExec(new Runnable() {
+ @Override
+ public void run() {
+ final Point point= Display.getCurrent().getDPI();
+ dpi.set(new double[] { point.x, point.y });
+ }
+ });
+ if (dpi.get() == null) {
+ dpi.set(new double[] { 96.0, 96.0 });
+ }
+ }
+ map.put("display.ppi", dpi.get()); //$NON-NLS-1$
+ return map;
+ }
+
+ @Override
+ public RClientGraphic newGraphic(final int devId, final double w, final double h,
+ final RClientGraphic.InitConfig config,
+ final boolean active, final RClientGraphicActions actions, final int options) {
+ final EclipseRGraphic egraphic= new EclipseRGraphic(devId, w, h, config, active,
+ (actions instanceof ToolRClientGraphicActions) ? (ToolRClientGraphicActions) actions : null,
+ options, this );
+ if ((options & MANAGED_OFF) == 0) {
+ this.defaultDisplay.syncExec(new Runnable() {
+ @Override
+ public void run() {
+ EclipseRGraphicFactory.this.graphics.add(egraphic);
+ final ImIdentityList<Listener> listeners= EclipseRGraphicFactory.this.listeners.toList();
+
+ EclipseRGraphicFactory.this.showRunnable.graphic= egraphic;
+ EclipseRGraphicFactory.this.showRunnable.bestPriority= Integer.MIN_VALUE;
+ for (final Listener listener : listeners) {
+ if (listener instanceof ListenerShowExtension) {
+ EclipseRGraphicFactory.this.showRunnable.listener= (ListenerShowExtension) listener;
+ SafeRunner.run(EclipseRGraphicFactory.this.showRunnable);
+ }
+ }
+ EclipseRGraphicFactory.this.showRunnable.listener= null;
+ if (EclipseRGraphicFactory.this.showRunnable.bestPriority >= 0) {
+ SafeRunner.run(EclipseRGraphicFactory.this.showRunnable);
+ }
+ EclipseRGraphicFactory.this.showRunnable.bestListener= null;
+ EclipseRGraphicFactory.this.showRunnable.graphic= null;
+
+ EclipseRGraphicFactory.this.addedRunnable.graphic= egraphic;
+ for (final Listener listener : listeners) {
+ EclipseRGraphicFactory.this.addedRunnable.listener= listener;
+ SafeRunner.run(EclipseRGraphicFactory.this.addedRunnable);
+ }
+ EclipseRGraphicFactory.this.addedRunnable.listener= null;
+ EclipseRGraphicFactory.this.addedRunnable.graphic= null;
+ }
+ });
+ }
+ return egraphic;
+ }
+
+ @Override
+ public void closeGraphic(final RClientGraphic graphic) {
+ final EclipseRGraphic egraphic= (EclipseRGraphic) graphic;
+ close(egraphic);
+ egraphic.closeFromR();
+ }
+
+ void close(final EclipseRGraphic graphic) {
+ if (!this.defaultDisplay.isDisposed()) {
+ this.defaultDisplay.syncExec(new Runnable() {
+ @Override
+ public void run() {
+ EclipseRGraphicFactory.this.graphics.remove(graphic);
+ final ImIdentityList<Listener> listeners= EclipseRGraphicFactory.this.listeners.toList();
+
+ EclipseRGraphicFactory.this.removedRunnable.graphic= graphic;
+ for (final Listener listener : listeners) {
+ EclipseRGraphicFactory.this.removedRunnable.listener= listener;
+ SafeRunner.run(EclipseRGraphicFactory.this.removedRunnable);
+ }
+ EclipseRGraphicFactory.this.removedRunnable.listener= null;
+ EclipseRGraphicFactory.this.removedRunnable.graphic= null;
+ }
+ });
+ }
+ }
+
+
+ public FontManager getFontManager(final Display display) {
+ if (display == this.defaultDisplay) {
+ return this.fontManager;
+ }
+ return null;
+ }
+
+ public ColorManager getColorManager(final Display display) {
+ if (display == this.defaultDisplay) {
+ return this.colorManager;
+ }
+ return null;
+ }
+
+
+ @Override
+ public ImList<? extends ERGraphic> getAllGraphics() {
+ return this.graphics.toList();
+ }
+
+ @Override
+ public void addListener(final Listener listener) {
+ this.listeners.add(listener);
+ }
+
+ @Override
+ public void removeListener(final Listener listener) {
+ this.listeners.remove(listener);
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FillSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FillSetting.java
new file mode 100644
index 0000000..7661eee
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FillSetting.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RFillSetting;
+
+
+public class FillSetting extends RFillSetting implements ERGraphicInstruction {
+
+
+ public final Color swtColor;
+
+
+ public FillSetting(final int color, final Color swtColor) {
+ super(color);
+ this.swtColor= swtColor;
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontManager.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontManager.java
new file mode 100644
index 0000000..33afa74
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontManager.java
@@ -0,0 +1,570 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.ImageData;
+import org.eclipse.swt.widgets.Display;
+
+
+public class FontManager {
+
+ private static final int[] R2SWT_STYLE= new int[] {
+ SWT.NONE,
+ SWT.BOLD,
+ SWT.ITALIC,
+ SWT.BOLD | SWT.ITALIC,
+ };
+ private static final int R_STYLE_COUNT= 4;
+
+
+ private static final int HR_FONTSIZE= 60;
+ private static final double HR_FACTOR= HR_FONTSIZE;
+ private static final int HR_MIN_FONTSIZE= HR_FONTSIZE / 2;
+
+
+ private static final class FontInstance {
+
+ private static final double[] UNINITIALIZED= new double[0];
+
+ public final int size;
+ public final Font swtFont;
+
+ private double[] swtFontProperties; // [ baselineOffset ] -> FontSetting
+
+ private int baseLine;
+ private double metricTolerance= 0;
+ private double ascentUp= Integer.MIN_VALUE;
+ private double ascentLow= Integer.MIN_VALUE;
+
+ private int[] charAbove255;
+ private double[] charMetrics= UNINITIALIZED;
+ private double[] strWidth= UNINITIALIZED;
+
+
+ public FontInstance(final int size, final Font font) {
+ this.size= size;
+ this.swtFont= font;
+ }
+
+
+ public void init(final GC gc) {
+ final FontMetrics fontMetrics= gc.getFontMetrics();
+ this.baseLine= fontMetrics.getLeading() + fontMetrics.getAscent();
+ this.metricTolerance= fontMetrics.getAscent() * 0.05;
+
+ this.swtFontProperties= new double[] {
+ this.baseLine,
+ };
+ }
+
+ public int checkChar(final int ch) {
+ if (ch <= 0) {
+ return 0;
+ }
+ else if (ch <= 255) {
+ return ch;
+ }
+ else if (this.charAbove255 == null){
+ this.charAbove255= new int[256];
+ this.charAbove255[0]= ch;
+ return 256 + 0;
+ }
+ else {
+ for (int i= 0; i < this.charAbove255.length; i++) {
+ final int c= this.charAbove255[i];
+ if (c == 0) {
+ this.charAbove255[i]= c;
+ return 256 + i;
+ }
+ else if (c == ch) {
+ return 256 + i;
+ }
+ }
+ final int[] newChar= new int[this.charAbove255.length + 256];
+ System.arraycopy(this.charAbove255, 0, newChar, 0, this.charAbove255.length);
+ newChar[this.charAbove255.length]= ch;
+ this.charAbove255= newChar;
+ return this.charAbove255.length - 256;
+ }
+ }
+
+ }
+
+
+ private static final class TestGC {
+
+
+ private final GC testGC;
+
+ private FontInstance font;
+
+ private final Image image;
+ private final int imageWidth;
+ private final int imageHeigth;
+ private final int imagePixelBytes;
+ private final int imageLineBytes;
+ private final byte imageBlankData;
+
+ private ImageData imageData;
+
+
+ public TestGC(final Device device) {
+ final GC tempGC= new GC(device);
+ final Font tempFont= new Font(device, new FontData(device.getSystemFont().getFontData()[0].getName(), HR_FONTSIZE, 0));
+ tempGC.setFont(tempFont);
+ this.imageHeigth= (int) (tempGC.getFontMetrics().getHeight() * 1.5);
+ this.imageWidth= this.imageHeigth * 2;
+ tempGC.dispose();
+ tempFont.dispose();
+
+ this.image= new Image(device, this.imageWidth, this.imageHeigth);
+
+ this.testGC= new GC(this.image);
+ this.testGC.setAdvanced(true);
+ this.testGC.setAntialias(SWT.ON);
+ this.testGC.setTextAntialias(SWT.ON);
+ this.testGC.setInterpolation(SWT.HIGH);
+ this.testGC.setAlpha(255);
+ this.testGC.setBackground(device.getSystemColor(SWT.COLOR_WHITE));
+ this.testGC.setForeground(device.getSystemColor(SWT.COLOR_BLACK));
+ this.testGC.setFont(null);
+ this.font= null;
+
+ clearImage();
+ this.imageData= this.image.getImageData();
+ this.imageLineBytes= this.imageData.bytesPerLine;
+ this.imagePixelBytes= Math.max(this.imageData.bytesPerLine / this.imageData.width, 1);
+ this.imageBlankData= this.imageData.data[0];
+ }
+
+
+ public void setFont(final FontInstance font) {
+// if (gcFont != font) { // E-Bug #319125
+ this.font= font;
+ this.testGC.setFont(font.swtFont);
+// }
+ if (this.font.baseLine == 0) {
+ this.font.init(this.testGC);
+ this.testGC.setFont(font.swtFont); // E-Bug #319125
+ }
+ }
+
+ public FontInstance getFont() {
+ return this.font;
+ }
+
+ public int getStringWidth(final String txt) {
+ return this.testGC.stringExtent(txt).x;
+ }
+
+ public void clearImage() {
+ this.testGC.fillRectangle(0, 0, this.imageWidth, this.imageHeigth);
+ this.imageData= null;
+ }
+
+ private void drawText(final String txt) {
+ this.testGC.drawString(txt, 0, 0, true);
+ }
+
+ public int findFirstLine() {
+ if (this.imageData == null) {
+ this.imageData= this.image.getImageData();
+ }
+ final byte[] data= this.imageData.data;
+ for (int i= 0; i < data.length; i+= this.imagePixelBytes) {
+ if (data[i] != this.imageBlankData) {
+ return (i / this.imageLineBytes);
+ }
+ }
+ return -1;
+ }
+
+ public int findLastLine() {
+ if (this.imageData == null) {
+ this.imageData= this.image.getImageData();
+ }
+ final byte[] data= this.imageData.data;
+ for (int i= data.length - this.imagePixelBytes; i >= 0; i-= this.imagePixelBytes) {
+ if (data[i] != this.imageBlankData) {
+ return (i / this.imageLineBytes);
+ }
+ }
+ return -1;
+ }
+
+
+ public void dispose() {
+ if (!this.testGC.isDisposed()) {
+ this.testGC.dispose();
+ }
+ if (!this.image.isDisposed()) {
+ this.image.dispose();
+ }
+ }
+
+ }
+
+
+ public final class FontFamily {
+
+ private static final double POLISH_SMALL_MAX_FACTOR= 0.4;
+ private static final double POLISH_SMALL_ADD_CORR= 0.04;
+ private static final double POLISH_ADD_CONST= 0.05;
+ private static final double POLISH_ADD_REL= 0.1;
+
+ private static final int METRIC_IDX_ADVWIDTH= 0;
+ private static final int METRIC_IDX_ASCENT= 1;
+ private static final int METRIC_IDX_DESCENT= 2;
+ private static final int METRIC_COUNT= 3;
+
+
+ final String name;
+
+ final FontInstance[][] fonts= new FontInstance[R_STYLE_COUNT][];
+
+
+ private FontFamily(final String name) {
+ this.name= name;
+ }
+
+
+ private FontInstance get(final int style, final int size) {
+ FontInstance[] styleFonts= this.fonts[style];
+ if (styleFonts == null) {
+ this.fonts[style]= styleFonts= new FontInstance[4];
+ }
+ int idx;
+ if (size == HR_FONTSIZE) {
+ idx= 0;
+ }
+ else {
+ idx= styleFonts.length;
+ for (int i= 1; i < styleFonts.length; i++) {
+ if (styleFonts[i] != null) {
+ if (styleFonts[i].size == size) {
+ idx= i;
+ break;
+ }
+ }
+ else {
+ idx= i;
+ break;
+ }
+ }
+ if (idx >= styleFonts.length) {
+ this.fonts[style]= new FontInstance[styleFonts.length+4];
+ System.arraycopy(styleFonts, 0, this.fonts[style], 0, styleFonts.length);
+ styleFonts= this.fonts[style];
+ }
+ }
+ if (styleFonts[idx] == null) {
+ final FontData fontData= new FontData(this.name, size, R2SWT_STYLE[style]);
+ styleFonts[idx]= new FontInstance(size,
+ new Font(FontManager.this.display, fontData));
+ }
+ return styleFonts[idx];
+ }
+
+ public synchronized Font getSWTFont(final int style, final int size) {
+ return get(style, size).swtFont;
+ }
+
+ public synchronized double[] getCharMetrics(final int style, final int size, final int ch) {
+ final FontInstance font= get(style, HR_FONTSIZE);
+ final double factor= size / HR_FACTOR;
+ final int chIdx= font.checkChar(ch) * METRIC_COUNT;
+
+ final double[] answer= new double[3];
+
+ if (chIdx >= font.charMetrics.length
+ || font.charMetrics[chIdx] == 0) {
+ synchronized (getTestLock()) {
+ final TestGC gc= getTestGC();
+ gc.setFont(font);
+
+ if (font.charMetrics.length == 0) {
+ font.charMetrics= new double[Math.max(512 * METRIC_COUNT,
+ chIdx + 128 * METRIC_COUNT)];
+
+ font.charMetrics[' ' * METRIC_COUNT + METRIC_IDX_ADVWIDTH] =
+ (gc.testGC.getAdvanceWidth('m') * 0.2 + gc.testGC.getAdvanceWidth(' ') * 1.0) / 2.0;
+ font.charMetrics[' ' * METRIC_COUNT + METRIC_IDX_ASCENT]= 0;
+ font.charMetrics[' ' * METRIC_COUNT + METRIC_IDX_DESCENT]= 0;
+
+ font.ascentUp= checkCharAscentMean(gc, new char[] { 'A', 'M', 'O', 'E' });
+ font.ascentLow= checkCharAscentMean(gc, new char[] { 'a', 'm', 'p', 'w' });
+
+ font.charMetrics[0 * METRIC_COUNT + METRIC_IDX_ADVWIDTH] =
+ font.charMetrics['M' * METRIC_COUNT + METRIC_IDX_ADVWIDTH];
+ font.charMetrics[0 * METRIC_COUNT + METRIC_IDX_ASCENT] =
+ (font.ascentUp > 0) ? font.ascentUp : 0;
+ font.charMetrics[0 * METRIC_COUNT + METRIC_IDX_DESCENT]= 0;
+ }
+ else if (chIdx >= font.charMetrics.length) {
+ final double[] newArray= new double[(chIdx + 128 * METRIC_COUNT)];
+ System.arraycopy(font.charMetrics, 0, newArray, 0, font.charMetrics.length);
+ font.charMetrics= newArray;
+ }
+
+ if (font.charMetrics[chIdx] == 0) {
+ computeCharHeights(gc, ch, chIdx);
+ }
+
+// Point sext= gc.stringExtent(new String(new int[] { this.currentChar }, 0, 1));
+// Point text= gc.textExtent(new String(new int[] { this.currentChar }, 0, 1), SWT.TRANSPARENT);
+// System.out.println("height= " + gc.getHeight());
+// System.out.println("leading= " + gc.getLeading());
+// System.out.println("ascent= " + gc.getAscent());
+// System.out.println("descent= " + gc.getDescent());
+// System.out.println("stringExtend.y= " + sext.y);
+// System.out.println("textExtend.y= " + text.y);
+// System.out.println("stringExtend.x= " + sext.x);
+// System.out.println("textExtend.x= " + text.x);
+// System.out.println("advanceWidth= " + gc.getAdvanceWidth((char) this.currentChar));
+// System.out.println("charWidth= " + gc.getCharWidth((char) this.currentChar));
+// System.out.println("averageCharWidth= " + gc.getFontMetrics.getAverageCharWidth());
+// System.out.println(this.currentAnswer[2]);
+ }
+ }
+
+ answer[0]= polish(font.charMetrics[chIdx + METRIC_IDX_ASCENT] + 1.01 / factor, factor);
+ answer[1]= polish(font.charMetrics[chIdx + METRIC_IDX_DESCENT], factor);
+ answer[2]= polish(font.charMetrics[chIdx + METRIC_IDX_ADVWIDTH], factor);
+
+// System.out.println("-> " + Arrays.toString(answer));
+ return answer;
+ }
+
+ private void computeCharHeights(final TestGC gc, final int ch, final int idx) {
+ final FontInstance font= gc.getFont();
+ font.charMetrics[idx + METRIC_IDX_ADVWIDTH] =
+ gc.testGC.getAdvanceWidth((char) ch);
+
+ final String s= String.valueOf((char) ch);
+
+ gc.clearImage();
+ gc.drawText(s);
+ final int firstLine= gc.findFirstLine();
+ if (firstLine >= 0) {
+ double ascent= font.baseLine - firstLine;
+ if (Math.abs(ascent - font.ascentUp) <= font.metricTolerance) {
+ ascent= font.ascentUp;
+ }
+ else if (Math.abs(ascent - font.ascentLow) <= font.metricTolerance) {
+ ascent= font.ascentLow;
+ }
+ int descent= gc.findLastLine() - font.baseLine + 1;
+ if (Math.abs(descent) <= font.metricTolerance) {
+ descent= 0;
+ }
+ font.charMetrics[idx + METRIC_IDX_ASCENT]= ascent;
+ font.charMetrics[idx + METRIC_IDX_DESCENT]= descent;
+ }
+ else {
+ font.charMetrics[idx + METRIC_IDX_ASCENT]= 0;
+ font.charMetrics[idx + METRIC_IDX_DESCENT]= 0;
+ }
+
+ if (idx / METRIC_COUNT < font.strWidth.length
+ && font.strWidth[idx / METRIC_COUNT] == 0) {
+ font.strWidth[idx / METRIC_COUNT]= gc.getStringWidth(s);
+ }
+ }
+
+ private double checkCharAscentMean(final TestGC gc, final char[] chars) {
+ final FontInstance font= gc.getFont();
+ double mean= 0;
+ for (int i= 0; i < chars.length; i++) {
+ computeCharHeights(gc, chars[i], chars[i] * METRIC_COUNT);
+ mean+= font.charMetrics[chars[i] * METRIC_COUNT + METRIC_IDX_ASCENT];
+ gc.testGC.setFont(font.swtFont); // E-Bug #319125
+ }
+ mean /= chars.length;
+ mean= polish(mean * 2.0, 1.0) / 2.0;
+ for (int i= 0; i < chars.length; i++) {
+ if (Math.abs(mean - font.charMetrics[chars[i] * METRIC_COUNT + METRIC_IDX_ASCENT]) > font.metricTolerance) {
+ return Integer.MIN_VALUE;
+ }
+ }
+ for (int i= 0; i < chars.length; i++) {
+ font.charMetrics[chars[i] * METRIC_COUNT + METRIC_IDX_ASCENT]= mean;
+ }
+ return mean;
+ }
+
+ public synchronized double[] getStringWidth(final int style, final int size, final String text) {
+ final FontInstance font;
+ final double factor;
+ final int chIdx;
+ if (size < HR_MIN_FONTSIZE && text.length() == 1) {
+ font= get(style, HR_FONTSIZE);
+ factor= size / HR_FACTOR;
+ chIdx= font.checkChar(text.charAt(0));
+ }
+ else {
+ font= get(style, size);
+ factor= 1.0;
+ chIdx= -1;
+ }
+
+ final double[] answer= new double[] { (8 * text.length()) };
+
+ if (chIdx < 0
+ || chIdx >= font.strWidth.length
+ || font.strWidth[chIdx] == 0) {
+ synchronized (getTestLock()) {
+ final TestGC gc= getTestGC();
+ gc.setFont(font);
+
+ final double width= gc.getStringWidth(text);
+ answer[0]= width;
+ if (chIdx >= 0) {
+ if (font.strWidth.length == 0) {
+ font.strWidth= new double[Math.max(512, chIdx + 256)];
+ }
+ else if (chIdx >= font.strWidth.length) {
+ final double[] newWidth= new double[chIdx + 128];
+ System.arraycopy(font.strWidth, 0, newWidth, 0, font.strWidth.length);
+ font.strWidth= newWidth;
+ }
+ font.strWidth[chIdx]= width;
+ }
+ }
+ }
+ else {
+ answer[0]= font.strWidth[chIdx];
+ }
+ if (factor != 1.0) {
+// this.currentAnswer[0]= Math.round((this.currentAnswer[0] * (factor * HR_ROUND_FACTOR)) + HR_ROUND_ADD) / HR_ROUND_FACTOR;
+ answer[0]= polish(answer[0], factor);
+ }
+
+// System.out.println("-> " + Arrays.toString(answer));
+ return answer;
+ }
+
+ public synchronized double[] getSWTFontProperties(final int style, final int size) {
+ final FontInstance font= get(style, size); // no HR!
+ if (font.swtFontProperties == null) {
+ synchronized (getTestLock()) {
+ final TestGC gc= getTestGC();
+ gc.setFont(font);
+ }
+ }
+ return font.swtFontProperties;
+ }
+
+ private double polish(final double p, final double factor) {
+ if (p == 0) {
+ return 0;
+ }
+ final double add= (factor < POLISH_SMALL_MAX_FACTOR) ?
+ (POLISH_SMALL_ADD_CORR / factor + POLISH_ADD_CONST) :
+ (POLISH_SMALL_ADD_CORR/POLISH_SMALL_MAX_FACTOR + POLISH_ADD_CONST);
+ if (p > 0) {
+ return Math.round((p + POLISH_ADD_REL) * factor + add);
+ }
+ else {
+ return Math.round((p - POLISH_ADD_REL) * factor - add);
+ }
+ }
+
+
+ public void dispose() {
+ for (int style= 0; style < R_STYLE_COUNT; style++) {
+ final FontInstance[] styleFonts= this.fonts[style];
+ if (styleFonts != null) {
+ for (int i= 0; i < styleFonts.length; i++) {
+ if (styleFonts[i] != null && styleFonts[i].swtFont != null) {
+ if (!styleFonts[i].swtFont.isDisposed()) {
+ styleFonts[i].swtFont.dispose();
+ }
+ styleFonts[i]= null;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+
+ private final Display display;
+
+ private final Object testGCLock= new Object();
+ private TestGC testGC;
+ private boolean disposed;
+
+ private final Map<String, FontFamily> fontFamilies= new HashMap<>();
+
+
+ public FontManager(final Display display) {
+ this.display= display;
+ }
+
+
+ public synchronized FontFamily getFamily(final String family) {
+ FontFamily fontFamily= this.fontFamilies.get(family);
+ if (fontFamily == null) {
+ fontFamily= new FontFamily(family);
+ this.fontFamilies.put(family, fontFamily);
+ }
+ return fontFamily;
+ }
+
+
+ protected final Object getTestLock() {
+ return this.testGCLock;
+ }
+
+ protected final TestGC getTestGC() {
+ if (this.testGC == null) {
+ this.display.syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!FontManager.this.disposed) {
+ FontManager.this.testGC= new TestGC(FontManager.this.display);
+ }
+ }
+ });
+ }
+ return this.testGC;
+ }
+
+
+ public void dispose() {
+ this.disposed= true;
+ for (final FontFamily fontFamily : this.fontFamilies.values()) {
+ fontFamily.dispose();
+ }
+ this.fontFamilies.clear();
+
+ if (this.testGC != null) {
+ this.testGC.dispose();
+ this.testGC= null;
+ }
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontSetting.java
new file mode 100644
index 0000000..5c2c5d0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/FontSetting.java
@@ -0,0 +1,38 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Font;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RFontSetting;
+
+
+public final class FontSetting extends RFontSetting implements ERGraphicInstruction {
+
+
+ public final Font swtFont;
+ public final double[] swtProperties;
+
+
+ public FontSetting(final String family, final int face, final float pointSize, final double lineHeight,
+ final Font swtFont, final double[] swtProperties) {
+ super(family, face, pointSize, lineHeight);
+ this.swtFont= swtFont;
+ this.swtProperties= swtProperties;
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/GraphicInitialization.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/GraphicInitialization.java
new file mode 100644
index 0000000..05f2d9a
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/GraphicInitialization.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Color;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RGraphicInitialization;
+
+
+public class GraphicInitialization extends RGraphicInitialization implements ERGraphicInstruction {
+
+
+ public final Color swtCanvasColor;
+
+
+ public GraphicInitialization(final double width, final double height, final int canvasColor,
+ final Color swtCanvasColor) {
+ super(width, height, canvasColor);
+
+ this.swtCanvasColor= swtCanvasColor;
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineElement.java
new file mode 100644
index 0000000..dccf2e9
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RLine;
+
+
+public class LineElement extends RLine implements ERGraphicInstruction {
+
+
+ public LineElement(final double x0, final double y0, final double x1, final double y1) {
+ super(x0, y0, x1, y1);
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineSetting.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineSetting.java
new file mode 100644
index 0000000..077f969
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/LineSetting.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.SWT;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RLineSetting;
+
+
+public final class LineSetting extends RLineSetting implements ERGraphicInstruction {
+
+
+ public LineSetting(final int type, final float width, final byte cap, final byte join,
+ final float joinMiterLimit) {
+ super(type, width, cap, join, joinMiterLimit);
+ }
+
+
+ public int swtCap() {
+ switch(this.cap) {
+ case CAP_ROUND:
+ return SWT.CAP_ROUND;
+ case CAP_BUTT:
+ return SWT.CAP_FLAT;
+ case CAP_SQUARE:
+ return SWT.CAP_SQUARE;
+ default:
+ assert (false);
+ return SWT.CAP_ROUND;
+ }
+ }
+
+ public int swtJoin() {
+ switch (this.join) {
+ case JOIN_ROUND:
+ return SWT.JOIN_ROUND;
+ case JOIN_MITER:
+ return SWT.JOIN_MITER;
+ case JOIN_BEVEL:
+ return SWT.JOIN_BEVEL;
+ default:
+ assert (false);
+ return SWT.JOIN_ROUND;
+ }
+ }
+
+ public int[] swtDashes() {
+ int rPattern= this.type;
+ int length= 0;
+ while (rPattern != 0) {
+ length++;
+ rPattern>>>= 4;
+ }
+ final int[] dashes= new int[length];
+ rPattern= this.type;
+ for (int i= 0; i < length; i++) {
+ dashes[i]= (rPattern & 0xf);
+ rPattern>>>= 4;
+ }
+ return dashes;
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PathElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PathElement.java
new file mode 100644
index 0000000..278d274
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PathElement.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Path;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RPath;
+
+
+public class PathElement extends RPath implements ERGraphicInstruction {
+
+
+ public final Path swtPath;
+
+
+ public PathElement(final int[] n, final double[] x, final double[] y, final int mode,
+ final Path swtPath) {
+ super(n, x, y, mode);
+
+ this.swtPath= swtPath;
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolygonElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolygonElement.java
new file mode 100644
index 0000000..7602346
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolygonElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RPolygon;
+
+
+public class PolygonElement extends RPolygon implements ERGraphicInstruction {
+
+
+ public PolygonElement(final double[] x, final double[] y) {
+ super(x, y);
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolylineElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolylineElement.java
new file mode 100644
index 0000000..e51435f
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PolylineElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RPolyline;
+
+
+public class PolylineElement extends RPolyline implements ERGraphicInstruction {
+
+
+ public PolylineElement(final double[] x, final double[] y) {
+ super(x, y);
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PreferenceInitializer.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PreferenceInitializer.java
new file mode 100644
index 0000000..530ff4b
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/PreferenceInitializer.java
@@ -0,0 +1,51 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+
+
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+
+ public PreferenceInitializer() {
+ }
+
+
+ @Override
+ public void initializeDefaultPreferences() {
+ final DefaultScope defaultScope= new DefaultScope();
+ final IEclipsePreferences node= defaultScope.getNode(RGraphics.FONTS_PREF_QUALIFIER);
+ if (Platform.getOS().startsWith("win")) {
+ node.put(RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY, "Times New Roman"); //$NON-NLS-1$
+ node.put(RGraphics.PREF_FONTS_SANS_FONTNAME_KEY, "Arial"); //$NON-NLS-1$
+ node.put(RGraphics.PREF_FONTS_MONO_FONTNAME_KEY, "Courier New"); //$NON-NLS-1$
+ }
+ else {
+ node.put(RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY, "Serif"); //$NON-NLS-1$
+ node.put(RGraphics.PREF_FONTS_SANS_FONTNAME_KEY, "Sans"); //$NON-NLS-1$
+ node.put(RGraphics.PREF_FONTS_MONO_FONTNAME_KEY, "Mono"); //$NON-NLS-1$
+ }
+ node.putBoolean(RGraphics.PREF_FONTS_SYMBOL_USE_KEY, true);
+ node.put(RGraphics.PREF_FONTS_SYMBOL_FONTNAME_KEY, "Symbol"); //$NON-NLS-1$
+ node.put(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY, "AdobeSymbol"); //$NON-NLS-1$
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RGraphicsPlugin.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RGraphicsPlugin.java
new file mode 100644
index 0000000..c4d8406
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RGraphicsPlugin.java
@@ -0,0 +1,126 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import static org.eclipse.statet.ecommons.ui.util.ImageRegistryUtil.T_LOCTOOL;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.ui.util.ImageRegistryUtil;
+
+import org.eclipse.statet.rj.eclient.graphics.RGraphics;
+
+
+/**
+ * Plug-in <code>org.eclipse.statet.rj.eclient.graphics</code>.
+ */
+public class RGraphicsPlugin extends AbstractUIPlugin {
+
+
+ public static final String IMG_LOCTOOL_RESIZE_FIT_R= RGraphics.BUNDLE_ID + "/image/loctool/resize-fit-r"; //$NON-NLS-1$
+
+ public static final String IMG_LOCTOOL_LOCATOR_DONE= RGraphics.BUNDLE_ID + "/image/loctool/locator-done"; //$NON-NLS-1$
+ public static final String IMG_LOCTOOL_LOCATOR_CANCEL= RGraphics.BUNDLE_ID + "/image/loctool/locator-cancel"; //$NON-NLS-1$
+
+
+ private static RGraphicsPlugin instance;
+
+ /**
+ * Returns the shared plug-in instance
+ *
+ * @return the shared instance
+ */
+ public static RGraphicsPlugin getDefault() {
+ return instance;
+ }
+
+
+ private boolean started;
+
+ private final List<Disposable> disposables= new ArrayList<>();
+
+
+ public RGraphicsPlugin() {
+ }
+
+
+ @Override
+ public void start(final BundleContext context) throws Exception {
+ super.start(context);
+ instance= this;
+ this.started= true;
+ }
+
+ @Override
+ public void stop(final BundleContext context) throws Exception {
+ try {
+ synchronized (this) {
+ this.started= false;
+ }
+
+ for (final Disposable listener : this.disposables) {
+ try {
+ listener.dispose();
+ }
+ catch (final Throwable e) {
+ getLog().log(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, 0,
+ "Error occured when dispose module", e ));
+ }
+ }
+ this.disposables.clear();
+ }
+ finally {
+ instance= null;
+ super.stop(context);
+ }
+ }
+
+
+ @Override
+ protected void initializeImageRegistry(final ImageRegistry reg) {
+ if (!this.started) {
+ throw new IllegalStateException("Plug-in is not started.");
+ }
+ final ImageRegistryUtil util= new ImageRegistryUtil(this);
+
+ util.register(IMG_LOCTOOL_RESIZE_FIT_R, T_LOCTOOL, "resize-fit-r.png");
+
+ util.register(IMG_LOCTOOL_LOCATOR_DONE, T_LOCTOOL, "locator-done.png");
+ util.register(IMG_LOCTOOL_LOCATOR_CANCEL, T_LOCTOOL, "locator-cancel.png");
+ }
+
+ public void registerPluginDisposable(final Disposable listener) {
+ if (listener == null) {
+ throw new NullPointerException();
+ }
+ synchronized (this) {
+ if (!this.started) {
+ throw new IllegalStateException("Plug-in is not started.");
+ }
+ this.disposables.add(listener);
+ }
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RasterElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RasterElement.java
new file mode 100644
index 0000000..2ccb7e8
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RasterElement.java
@@ -0,0 +1,39 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RRaster;
+
+
+public class RasterElement extends RRaster implements ERGraphicInstruction {
+
+
+ public final Image swtImage;
+
+
+ public RasterElement(final byte[] imgData, final int imgWidth, final int imgHeight,
+ final double x, final double y, final double w, final double h,
+ final double rDeg, final boolean interpolate,
+ final Image swtImage) {
+ super(imgData, imgWidth, imgHeight, x, y, w, h, rDeg, interpolate);
+
+ this.swtImage= swtImage;
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RectElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RectElement.java
new file mode 100644
index 0000000..b5a69b7
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/RectElement.java
@@ -0,0 +1,29 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RRect;
+
+
+public class RectElement extends RRect implements ERGraphicInstruction {
+
+
+ public RectElement(final double x0, final double y0, final double x1, final double y1) {
+ super(x0, y0, x1, y1);
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/TextElement.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/TextElement.java
new file mode 100644
index 0000000..daef7be
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/internal/rj/eclient/graphics/TextElement.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RText;
+
+
+public class TextElement extends RText implements ERGraphicInstruction {
+
+
+ public final double swtStrWidth;
+
+
+ public TextElement(final String text,
+ final double x, final double y, final double rDeg, final double hAdj,
+ final double swtStrWidth) {
+ super(text, x, y, rDeg, hAdj);
+ this.swtStrWidth= swtStrWidth;
+ }
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/DefaultGCRenderer.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/DefaultGCRenderer.java
new file mode 100644
index 0000000..e1d451c
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/DefaultGCRenderer.java
@@ -0,0 +1,508 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.LineAttributes;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.graphics.Transform;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.CircleElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.ClipSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.ColorSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FillSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FontSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.GraphicInitialization;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.PathElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolygonElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolylineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.RasterElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.RectElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.TextElement;
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+import org.eclipse.statet.rj.graphic.core.RLineSetting;
+import org.eclipse.statet.rj.server.client.RClientGraphic;
+
+
+public class DefaultGCRenderer {
+
+
+ private static int swtLineJoin2Cap(final int join) {
+ return (join == SWT.JOIN_ROUND) ? SWT.CAP_ROUND : SWT.CAP_FLAT;
+ }
+
+
+ private double scale= 1.0f;
+
+ private final LineAttributes lineAttributes= new LineAttributes(1.0f);
+ private Color lineColor;
+ private int lineAlpha;
+ private Color fillColor;
+ private int fillAlpha;
+ private final double[] fontProperties= new double[1];
+ private int xMax;
+ private int yMax;
+
+
+ public void clear(final double scale) {
+ this.scale= scale;
+ this.lineColor= null;
+ this.lineAlpha= 0xff;
+ this.fillColor= null;
+ this.fillAlpha= 0xff;
+ this.lineAttributes.style= SWT.LINE_SOLID;
+ this.lineAttributes.width= (float) scale;
+ this.lineAttributes.cap= SWT.CAP_ROUND;
+ this.lineAttributes.join= SWT.JOIN_ROUND;
+ this.lineAttributes.miterLimit= (float) (10.0 * scale);
+ this.xMax= 0;
+ this.yMax= 0;
+ }
+
+ public void paint(final GC gc, final List<? extends ERGraphicInstruction> instructions) {
+ final Transform defaultTransform= null;
+ final Transform tempTransform= new Transform(gc.getDevice());
+ final double scale= this.scale;
+ int currentAlpha= -1;
+ int currentInterpolation= -1;
+ int currentFillRule= -1;
+ Color lineColor= this.lineColor;
+ int lineAlpha= this.lineAlpha;
+ Color fillColor= this.fillColor;
+ int fillAlpha= this.fillAlpha;
+
+ try {
+ gc.setAdvanced(true);
+ gc.setAntialias(SWT.ON);
+ gc.setTextAntialias(SWT.ON);
+ gc.setLineAttributes(this.lineAttributes);
+ gc.setTransform(defaultTransform);
+ gc.setAlpha(currentAlpha);
+ if (this.lineColor != null) {
+ gc.setForeground(this.lineColor);
+ }
+ if (this.fillColor != null) {
+ gc.setBackground(this.fillColor);
+ }
+ int ixmax= this.xMax;
+ int iymax= this.yMax;
+
+ for (final ERGraphicInstruction instr : instructions) {
+ switch (instr.getInstructionType()) {
+ case RGraphicInstruction.INIT: {
+ final GraphicInitialization init= (GraphicInitialization) instr;
+ ixmax= (int) (init.width * scale + 0.5);
+ iymax= (int) (init.height * scale + 0.5);
+ gc.setBackground(init.swtCanvasColor);
+ gc.setAlpha(currentAlpha= 0xff);
+ gc.setClipping((Rectangle) null);
+ gc.fillRectangle(0, 0, ixmax, iymax);
+ // gc.setBackground(fillColor= gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
+ // gc.setForeground(lineColor= gc.getDevice().getSystemColor(SWT.COLOR_BLACK));
+ gc.setClipping(0, 0, ixmax, iymax);
+ continue;
+ }
+
+ case RGraphicInstruction.SET_CLIP: {
+ final ClipSetting setting= (ClipSetting) instr;
+
+ final int ix0= (int) (setting.x0 * scale + 1.5);
+ final int iy0= (int) (setting.y0 * scale + 1.5);
+ gc.setClipping(ix0, iy0,
+ (int) Math.min((setting.x1 * scale + 0.5), ixmax) - ix0,
+ (int) Math.min((setting.y1 * scale + 0.5), iymax) - iy0 );
+ continue;
+ }
+
+ case RGraphicInstruction.SET_COLOR: {
+ final ColorSetting setting= (ColorSetting) instr;
+
+ lineAlpha= setting.getAlpha();
+ gc.setForeground(lineColor= setting.swtColor);
+ continue;
+ }
+
+ case RGraphicInstruction.SET_FILL: {
+ final FillSetting setting= (FillSetting) instr;
+
+ fillAlpha= setting.getAlpha();
+ gc.setBackground(fillColor= setting.swtColor);
+ continue;
+ }
+
+ case RGraphicInstruction.SET_LINE: {
+ final LineSetting setting= (LineSetting) instr;
+
+ this.lineAttributes.cap= setting.swtCap();
+ this.lineAttributes.join= setting.swtJoin();
+ this.lineAttributes.miterLimit= (float) (setting.joinMiterLimit * scale);
+ switch (setting.type) {
+ case RLineSetting.TYPE_SOLID:
+ this.lineAttributes.style= SWT.LINE_SOLID;
+ this.lineAttributes.width= (float) (setting.width * scale);
+ gc.setLineAttributes(this.lineAttributes);
+ continue;
+ case RLineSetting.TYPE_BLANK:
+ this.lineAttributes.style= SWT.LINE_SOLID;
+ this.lineAttributes.width= 0.0f;
+ gc.setLineAttributes(this.lineAttributes);
+ continue;
+// case 0x44:
+// this.tempLineAttributes.style= SWT.LINE_DASH;
+// this.tempLineAttributes.width= (float) (setting.width * scale);
+// gc.setLineAttributes(this.tempLineAttributes);
+// continue;
+// case 0x13:
+// this.tempLineAttributes.style= SWT.LINE_DOT;
+// this.tempLineAttributes.width= (float) (setting.width * scale);
+// gc.setLineAttributes(this.tempLineAttributes);
+// continue;
+// case 0x1343:
+// this.tempLineAttributes.style= SWT.LINE_DASHDOT;
+// this.tempLineAttributes.width= (float) (setting.width * scale);
+// gc.setLineAttributes(this.tempLineAttributes);
+// continue;
+ default:
+ this.lineAttributes.style= SWT.LINE_SOLID;
+ this.lineAttributes.width= (float) (setting.width * scale);
+ gc.setLineAttributes(this.lineAttributes);
+ gc.setLineDash(setting.swtDashes());
+ continue;
+ }
+ }
+
+ case RGraphicInstruction.SET_FONT: {
+ final FontSetting setting= (FontSetting) instr;
+
+ gc.setFont(setting.swtFont);
+ this.fontProperties[0]= setting.swtProperties[0];
+ continue;
+ }
+
+ case RGraphicInstruction.DRAW_LINE: {
+ final LineElement element= (LineElement) instr;
+
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawLine(
+ (int) (element.x0 * scale + 0.5),
+ (int) (element.y0 * scale + 0.5),
+ (int) (element.x1 * scale + 0.5),
+ (int) (element.y1 * scale + 0.5) );
+ continue;
+ }
+
+ case RGraphicInstruction.DRAW_RECTANGLE: {
+ final RectElement element= (RectElement) instr;
+
+ // small dots: priority on size / center
+ // default: priority on edges
+ final int ix0, iy0;
+ final int iw, ih;
+ if ((element.x1 - element.x0) < 5.1111 && (element.y1 - element.y0) < 5.1111) {
+ iw= (int) ((element.x1 - element.x0) * scale + 0.5);
+ if (lineAlpha == 0) {
+ ix0= (int) (((element.x0 + element.x1) * scale - iw) / 2.0 + 0.5);
+// System.out.println("(a==0) ix0= " + ix0 + " (" + (float) (((element.x0 + element.x1) * scale - iw) / 2.0) + ")"
+// + ", x0= " + (float) (element.x0 * scale) + ", iw= " + iw + " (" + (float) ((element.x1 - element.x0) * scale) + ")"
+// + ", c= " + (float) ((element.x0 + element.x1) * scale / 2.0));
+ }
+ else {
+ ix0= (int) (((element.x0 + element.x1) * scale - (iw + 1)) / 2.0 + 0.5);
+// System.out.println("(a!=0) ix0= " + ix0 + " (" + (float) (((element.x0 + element.x1) * scale - (iw + 1)) / 2.0) + ")"
+// + ", x0= " + (float) (element.x0 * scale) + ", iw= " + iw + "+1 (" + (float) ((element.x1 - element.x0) * scale) + ")"
+// + ", c= " + (float) ((element.x0 + element.x1) * scale / 2.0));
+ }
+ ih= (int) ((element.y1 - element.y0) * scale + 0.5);
+ if (lineAlpha == 0) {
+ iy0= (int) (((element.y0 + element.y1) * scale - ih) / 2.0 + 0.5);
+ }
+ else {
+ iy0= (int) (((element.y0 + element.y1) * scale - (ih + 1)) / 2.0 + 0.5);
+ }
+ }
+ else {
+ ix0= (int) (element.x0 * scale + 0.5);
+ if (lineAlpha == 0) {
+ iw= (int) (element.x1 * scale + 0.5) - ix0 + 1;
+ }
+ else {
+ iw= (int) (element.x1 * scale + 0.5) - ix0;
+ }
+ iy0= (int) (element.y0 * scale + 0.5);
+ if (lineAlpha == 0) {
+ ih= (int) (element.y1 * scale + 0.5) - iy0 + 1;
+ }
+ else {
+ ih= (int) (element.y1 * scale + 0.5) - iy0;
+ }
+ }
+
+ if (iw == 0 || ih == 0) {
+ if (lineAlpha == 0) {
+ continue;
+ }
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.setLineCap(swtLineJoin2Cap(this.lineAttributes.join));
+ gc.drawLine(ix0, iy0, ix0 + iw, iy0 + ih);
+ gc.setLineCap(this.lineAttributes.cap);
+ continue;
+ }
+ if (fillAlpha != 0) {
+ if (lineAlpha == 0) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ gc.fillRectangle(ix0, iy0, iw, ih);
+ continue;
+ }
+ if (iw > 1 && ih > 1) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ gc.fillRectangle(ix0 + 1, iy0 + 1, iw - 1, ih - 1);
+ }
+ }
+ if (lineAlpha != 0) {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawRectangle(ix0, iy0, iw, ih);
+ }
+ continue;
+ }
+
+ case RGraphicInstruction.DRAW_POLYLINE: {
+ final PolylineElement element= (PolylineElement) instr;
+
+ final int[] icoord;
+ { final int n= element.x.length;
+ icoord= new int[n * 2];
+ for (int i= 0, j= 0; j < n; j++) {
+ icoord[i++]= (int) (element.x[j] * scale + 0.5);
+ icoord[i++]= (int) (element.y[j] * scale + 0.5);
+ }
+ }
+
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawPolyline(icoord);
+ continue;
+ }
+
+ case RGraphicInstruction.DRAW_POLYGON: {
+ final PolygonElement element= (PolygonElement) instr;
+
+ final int[] icoord;
+ { final int n= element.x.length;
+ icoord= new int[n * 2];
+ for (int i= 0, j= 0; j < n; j++) {
+ icoord[i++]= (int) (element.x[j] * scale + 0.5);
+ icoord[i++]= (int) (element.y[j] * scale + 0.5);
+ }
+ }
+
+ if (fillAlpha != 0) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ if (SWT.FILL_EVEN_ODD != currentFillRule) {
+ gc.setFillRule(currentFillRule= SWT.FILL_EVEN_ODD);
+ }
+ gc.fillPolygon(icoord);
+ }
+ if (lineAlpha != 0) {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawPolygon(icoord);
+ }
+ continue;
+ }
+
+ case RGraphicInstruction.DRAW_PATH: {
+ final PathElement element= (PathElement) instr;
+
+ { final int fillRule= ((element.mode & RClientGraphic.MASK_FILL_RULE) == RClientGraphic.FILL_WIND_NON_ZERO) ?
+ SWT.FILL_WINDING : SWT.FILL_EVEN_ODD;
+ if (fillRule != currentFillRule) {
+ gc.setFillRule(currentFillRule= fillRule);
+ }
+ }
+ if (fillAlpha != 0) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ gc.fillPath(element.swtPath);
+ }
+ if (lineAlpha != 0) {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawPath(element.swtPath);
+ }
+ continue;
+ }
+
+ case RGraphicInstruction.DRAW_CIRCLE: {
+ final CircleElement element= (CircleElement) instr;
+
+ final int id= (int) (element.r * 2.0 + 0.5);
+ tempTransform.setElements(1, 0, 0, 1,
+ (float) (element.x - id / 2.0),
+ (float) (element.y - id / 2.0) );
+ gc.setTransform(tempTransform);
+
+ if (fillAlpha != 0) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ gc.fillOval(1, 1, id-1, id-1);
+ }
+ if (lineAlpha != 0) {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawOval(0, 0, id, id);
+ }
+
+ gc.setTransform(defaultTransform);
+ continue;
+ }
+
+ case RGraphicInstruction.DRAW_TEXT: {
+ final TextElement element= (TextElement) instr;
+
+ final double hShift;
+ if (element.horizontalAdjust != 0.0) {
+ hShift= element.horizontalAdjust * element.swtStrWidth;
+ }
+ else {
+ hShift= 0.0;
+ }
+
+ if (element.rotateDegree != 0.0) {
+ tempTransform.setElements(1, 0, 0, 1,
+ (float) (element.x * scale),
+ (float) (element.y * scale) );
+ tempTransform.rotate((float) -element.rotateDegree);
+ tempTransform.translate(
+ (float) Math.floor(1.1111 - hShift),
+ (float) Math.floor(0.0511 - this.fontProperties[0]) );
+ gc.setTransform(tempTransform);
+
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawString(element.text, 0, 0, true);
+
+ gc.setTransform(defaultTransform);
+ continue;
+ }
+ else {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawString(element.text,
+ (int) Math.floor(1.1111 + element.x - hShift),
+ (int) Math.floor(0.6111 + element.y - this.fontProperties[0]),
+ true );
+
+ continue;
+ }
+ }
+
+ case RGraphicInstruction.DRAW_RASTER: {
+ final RasterElement element= (RasterElement) instr;
+
+ if (0xff != currentAlpha) {
+ gc.setAlpha(currentAlpha= 0xff);
+ }
+ { final int interpolation= (element.interpolate) ? SWT.LOW : SWT.NONE;
+ if (interpolation != currentInterpolation) {
+ gc.setInterpolation(currentInterpolation= interpolation);
+ }
+ }
+
+ final int ix, iy;
+ final int ih, iw;
+ if (element.width >= 0) {
+ ix= (int) Math.floor(element.x * scale + 0.5);
+ iw= (int) (element.width * scale + 0.5);
+ }
+ else {
+ ix= (int) Math.floor((element.x + element.height) * scale + 0.5);
+ iw= (int) (-element.width * scale + 0.5);
+ }
+ if (element.height >= 0) {
+ iy= (int) Math.floor(element.y * scale + 0.5);
+ ih= (int) (element.height * scale + 0.5);
+ }
+ else {
+ iy= (int) Math.floor((element.y + element.height) * scale + 0.5);
+ ih= (int) (-element.height * scale + 0.5);
+ }
+
+ if (element.rotateDegree != 0.0) {
+ tempTransform.setElements(1, 0, 0, 1,
+ (float) (element.x * scale),
+ (float) (element.y * scale) );
+ tempTransform.rotate(-(float) element.rotateDegree);
+ if (element.width < 0 || element.height < 0) {
+ tempTransform.translate(
+ (element.width < 0) ? -iw : 0,
+ (element.height < 0) ? -ih : 0 );
+ }
+ gc.setTransform(tempTransform);
+
+ gc.drawImage(element.swtImage, 0, 0, element.imgWidth, element.imgHeight,
+ 0, 0, iw, ih );
+
+ gc.setTransform(defaultTransform);
+ continue;
+ }
+ else {
+ gc.drawImage(element.swtImage, 0, 0, element.imgWidth, element.imgHeight,
+ ix, iy, iw, ih );
+
+ continue;
+ }
+ }
+ }
+ }
+
+ this.lineColor= lineColor;
+ this.lineAlpha= lineAlpha;
+ this.fillColor= fillColor;
+ this.fillAlpha= fillAlpha;
+ this.xMax= ixmax;
+ this.yMax= iymax;
+ }
+ finally {
+ tempTransform.dispose();
+ }
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphic.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphic.java
new file mode 100644
index 0000000..7fa71da
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphic.java
@@ -0,0 +1,275 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+
+
+/**
+ * R graphic for Eclipse based clients.
+ *
+ * <h4>Coordinate systems:</h4>
+ * <p>
+ * The <b>graphic coordinate</b> system is used to draw the graphic, the point of origin is the upper
+ * left corner, values increasing to the right and downward respectively.</p>
+ * <p>
+ * The <b>user coordinate</b> system is defined by the main x-axis and y-axis of the plot using
+ * the original units of the plotted values, if possible.<p>
+ *
+ */
+public interface ERGraphic extends RGraphic {
+
+ /**
+ * @see ERGraphic#addListener(Listener)
+ * @see ERGraphic#removeListener(Listener)
+ * @since 1.0
+ */
+ interface ListenerLocatorExtension extends Listener {
+
+ /**
+ * Is called when a locator is started or restarted (next point).
+ * <p>
+ * The method is called in the display thread.</p>
+ */
+ void locatorStarted();
+
+ /**
+ * Is called when a locator is stopped.
+ * <p>
+ * The method is called in the display thread.</p>
+ */
+ void locatorStopped();
+
+ }
+
+
+ /**
+ * The default locator stop type indicating that the user does not want to select more points
+ * (OK, in R also called stop, default action for right mouse click).
+ *
+ * @since 1.0
+ */
+ String LOCATOR_DONE= "done"; //$NON-NLS-1$
+
+ /**
+ * Locator stop type indicating that the user wants to cancel the locator.
+ *
+ * @since 1.0
+ */
+ String LOCATOR_CANCEL= "cancel"; //$NON-NLS-1$
+
+ /**
+ * @since 1.0
+ */
+ interface ListenerInstructionsExtension extends Listener {
+
+ void instructionsChanged(boolean reset, List<ERGraphicInstruction> added);
+
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ int getDevId();
+
+ /**
+ * Returns the current label for this graphic
+ * <p>
+ * The label can change if the graphic (device) is activated or a locator is started or stopped.
+ * </p>
+ *
+ * @return the current label
+ */
+ String getLabel();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ boolean isActive();
+
+ Tool getRHandle();
+
+ @Override
+ List<? extends ERGraphicInstruction> getInstructions();
+
+ IStatus resize(double w, double h);
+
+ IStatus close();
+
+ /**
+ * Returns the current message for the graphic.
+ * <p>
+ * The standard OK message means there is no message. If the message changes messages listeners
+ * registered for this graphic ({@link #addMessageListener(StatusChangeListener)},
+ * {@link #removeMessageListener(StatusChangeListener)}) are notified.</p>
+ * <p>
+ * The message I can be shown for example in the status line of the application.</p>
+ *
+ * @return the current message to show
+ * @since 1.0
+ */
+ IStatus getMessage();
+
+ /**
+ * Registers a new message listener for this graphic.
+ *
+ * @param listener the listener to add
+ * @since 1.0
+ */
+ void addMessageListener(StatusChangeListener listener);
+
+ /**
+ * Removes a message listener registered for this graphic.
+ *
+ * @param listener the listener to remove
+ * @since 1.0
+ */
+ void removeMessageListener(StatusChangeListener listener);
+
+
+ /**
+ * Starts a local locator requesting the user to select a point in the graphic.
+ * <p>
+ * The method starts the locator and returns directly; it does not wait for an answer.
+ * If a locator is already installed for this graphic (local or from R), the method does
+ * nothing and returns an error status.</p>
+ * <p>
+ * The locator callback configures the request and receives the answer(s). The answer can be
+ * a coordinate located by the user ({@link LocatorCallback#located(double, double)}) or
+ * a stop command ({@link LocatorCallback#stopped(String)}.</p>
+ * <p>
+ * Graphic listeners implementing {@link ListenerLocatorExtension} and registered for this
+ * graphic ({@link #addListener(Listener)}, {@link #removeListener(Listener)}) are notified
+ * if the locator is started and if it is finally stopped.</p>
+ *
+ * @param callback the callback called to handover the answer(s)
+ * @return An OK status if the locator is started for the given callback, otherwise
+ * an error status
+ * @see LocatorCallback
+ * @since 1.0
+ */
+ IStatus startLocalLocator(LocatorCallback callback);
+
+ /**
+ * Returns true if any locator (local or from R) is started for this graphic.
+ *
+ * @return <code>true</code> if a locator is started, otherwise <code>false</code>
+ * @since 1.0
+ */
+ boolean isLocatorStarted();
+
+ /**
+ * Returns a collection of currently supported stop types.
+ * <p>
+ * If no locator is started, the method returns an empty collection.</p>
+ *
+ * @return a list of supported stop types
+ * @see LocatorCallback#getStopTypes()
+ * @since 1.0
+ */
+ Collection<String> getLocatorStopTypes();
+
+ /**
+ * Answers a locator request with the specified coordinates.
+ * <p>
+ * If no locator is started, the method does nothing.</p>
+ *
+ * @param x the x value of the graphic coordinate
+ * @param y the y value of the graphic coordinate
+ * @since 1.0
+ */
+ void returnLocator(double x, double y);
+
+ /**
+ * Answers a locator request with the specified stop command.
+ * <p>
+ * If no locator is started or does not support the specified type, the method does nothing.</p>
+ *
+ * @param type the stop type or <code>null</code>
+ * @see LocatorCallback#getStopTypes()
+ * @since 1.0
+ */
+ void stopLocator(String type);
+
+
+ /**
+ * @deprecated {@link #copy(String, String, String, IProgressMonitor)} or
+ * {@link org.eclipse.statet.rj.eclient.graphics.util.CopyToDevRunnable}
+ */
+ @Deprecated
+ IStatus copy(String toDev, String toDevFile, String toDevArgs) throws CoreException;
+
+ /**
+ * Copies the graphic to another R graphic device.
+ * <p>
+ * This is an R based function. The caller must have exclusive access to the R service. The
+ * graphic must be available in R.</p>
+ *
+ * @param toDev the name of the target device
+ * @param toDevFile the name of the file for file based devices
+ * @param toDevArgs other R arguments for the target arguments
+ * @param monitor
+ * @throws CoreException
+ * @since 1.0
+ */
+ void copy(String toDev, String toDevFile, String toDevArgs,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Converts a coordinate (x, y) from graphic to user coordinate system.
+ * <p>
+ * This is an R based function. The caller must have exclusive access to the R service. The
+ * graphic must be available in R.</p>
+ *
+ * @param xy the graphic coordinate to convert
+ * @param monitor
+ * @return the converted user coordinate
+ * @throws CoreException
+ * @see ERGraphic coordinate systems
+ * @since 1.0
+ */
+ double[] convertGraphic2User(double[] xy,
+ IProgressMonitor monitor) throws CoreException;
+
+ /**
+ * Converts a coordinate (x, y) from user to graphic coordinate system.
+ * <p>
+ * This is an R based function. The caller must have exclusive access to the R service. The
+ * graphic must be available in R.</p>
+ *
+ * @param xy the graphic coordinate to convert
+ * @param monitor
+ * @return the converted user coordinate
+ * @throws CoreException
+ * @see ERGraphic coordinate systems
+ * @since 1.0
+ */
+ double[] convertUser2Graphic(double[] xy,
+ IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicInstruction.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicInstruction.java
new file mode 100644
index 0000000..90ecd4f
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicInstruction.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+
+
+/**
+ * Instruction of an {@link ERGraphic}.
+ */
+public interface ERGraphicInstruction extends RGraphicInstruction {
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicsManager.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicsManager.java
new file mode 100644
index 0000000..15d6435
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/ERGraphicsManager.java
@@ -0,0 +1,62 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+
+/**
+ * Manager for a collection of R graphics.
+ */
+public interface ERGraphicsManager {
+
+
+ interface Listener {
+
+ void graphicAdded(ERGraphic graphic);
+
+ void graphicRemoved(ERGraphic graphic);
+
+ }
+
+ interface ListenerShowExtension extends Listener {
+
+ /**
+ * If the listener can show the graphic
+ *
+ * <code>-1</code> not supported
+ * <code>>= 0</code> priority (higher more appropriate)
+ * @param graphic the graphic to show
+ * @return
+ */
+ int canShowGraphic(ERGraphic graphic);
+
+ /**
+ * If the listener was selected (highest priority) to show the graphic
+ *
+ * @param graphic the graphic to show
+ */
+ void showGraphic(ERGraphic graphic);
+
+ }
+
+
+ void addListener(Listener listener);
+
+ void removeListener(Listener listener);
+
+ List<? extends ERGraphic> getAllGraphics();
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/LocatorCallback.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/LocatorCallback.java
new file mode 100644
index 0000000..df149e2
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/LocatorCallback.java
@@ -0,0 +1,119 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.Collection;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+
+/**
+ * Callback for a local locator.
+ * <p>
+ * When using the locator function of {@link ERGraphic}, the locator callback configures the
+ * request and receives the answer. When starting a local locator using {@link ERGraphic#startLocalLocator(LocatorCallback)}
+ * the callback must be specified as argument. The callback configures the locator request
+ * and receives the answer(s).</p>
+ * <p>
+ * The methods {@link #getMessage()} and {@link #getStopTypes()} allows to configure the behavior
+ * of the locator. The properties can be used for example in the GUI. The values can change
+ * for each point to locate; the properties are checked at beginning and again after
+ * {@link #located(double, double)} was called and request one more point.</p>
+ * <p>
+ * The callback is notified by points located by the user are by calling ({@link LocatorCallback#located(double, double)}).
+ * Note that the callback receives graphic coordinates. The method can return {@link #NEXT}
+ * to request a next point or {@link #STOP} to stop the locator. The locator is also stopped
+ * if the method {@link LocatorCallback#stopped(String)} was called.</p>
+ * <p>
+ * Stop types allow to specify a special user action when stopping the locator. Stop types known
+ * by the default implementation are {@link ERGraphic#LOCATOR_DONE} and {@link ERGraphic#LOCATOR_CANCEL}
+ * representing the usual OK and Cancel action. The {@link RGraphicCompositeActionSet} provides
+ * buttons for both actions.</p>
+ *
+ * @since 1.0
+ */
+public abstract class LocatorCallback {
+
+
+ protected static final ImList<String> DEFAULT_STOP_TYPES= ImCollections.newList(ERGraphic.LOCATOR_DONE);
+
+ /**
+ * Return code for {@link #located(double, double)} indicating to stop directly the locator
+ * ({@link #stopped(String)} is not called).
+ */
+ public static final int STOP= 0;
+
+ /**
+ * Return code for {@link #located(double, double)} indicating to restart/continue the locator
+ * requesting the next point.
+ */
+ public static final int NEXT= 1;
+
+
+ public LocatorCallback() {
+ }
+
+
+ /**
+ * Returns the current message for the locator.
+ *
+ * @return the current message
+ */
+ public String getMessage() {
+ return "→ Locate a point by mouse click";
+ }
+
+ /**
+ * Returns the currently supported stop types for the locator.
+ *
+ * @return a collection of stop types, an empty collection if no regular stop is supported
+ * @see #stopped(String)
+ */
+ public Collection<String> getStopTypes() {
+ return DEFAULT_STOP_TYPES;
+ }
+
+ /**
+ * Is called if the user selected a value.
+ * <p>
+ * The method is called by the graphic. Other class must use {@link ERGraphic#returnLocator(double, double)}
+ * to specify a located point.
+ * It is not guaranteed that the method is called in a special thread.</p>
+ *
+ * @param x value of the graphic coordinate
+ * @param y value of the graphic coordinate
+ * @return a known return code
+ * @see #STOP
+ * @see #NEXT
+ */
+ public abstract int located(double x, double y);
+
+ /**
+ * Is called if the locator was stopped by the user or graphic manager.
+ * <p>
+ * The stop type is one of the {@link #getStopTypes() supported stop types} of the locator or
+ * also <code>null</code>. <code>null</code> as stop type is always allowed and is used for
+ * example if the graphic was closed.</p>
+ * <p>
+ * The method is called by the graphic. Other class must use {@link ERGraphic#stopLocator(String)}
+ * to stop the locator.
+ * It is not guaranteed that the method is called in a special thread.</p>
+ *
+ * @param type the stop type
+ */
+ public abstract void stopped(String type);
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/OldGCRenderer.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/OldGCRenderer.java
new file mode 100644
index 0000000..a4e9e27
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/OldGCRenderer.java
@@ -0,0 +1,299 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.LineAttributes;
+import org.eclipse.swt.graphics.Transform;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.CircleElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.ClipSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.ColorSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FillSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.FontSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.GraphicInitialization;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.LineSetting;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolygonElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.PolylineElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.RectElement;
+import org.eclipse.statet.internal.rj.eclient.graphics.TextElement;
+import org.eclipse.statet.rj.graphic.core.RGraphicInstruction;
+
+
+public class OldGCRenderer {
+
+
+ private float scale= 1.0f;
+
+ private final LineAttributes lineAttributes= new LineAttributes(1.0f);
+ private Color lineColor;
+ private int lineAlpha;
+ private Color fillColor;
+ private int fillAlpha;
+ private int xMax;
+ private int yMax;
+
+
+ public void clear(final float scale) {
+ this.scale= scale;
+ this.lineColor= null;
+ this.lineAlpha= 0xff;
+ this.fillColor= null;
+ this.fillAlpha= 0xff;
+ this.lineAttributes.style= SWT.LINE_SOLID;
+ this.lineAttributes.width= scale;
+ this.xMax= 0;
+ this.yMax= 0;
+ }
+
+ public void paint(final GC gc, final List<? extends ERGraphicInstruction> instructions) {
+ final Transform defaultTransform= null;
+ Transform tempTransform= null;
+ final float scale= this.scale;
+ int currentAlpha= -1;
+ int lineAlpha= this.lineAlpha;
+ int fillAlpha= this.fillAlpha;
+ try {
+ gc.setAdvanced(true);
+ gc.setAntialias(SWT.ON);
+ gc.setTextAntialias(SWT.ON);
+ gc.setLineAttributes(this.lineAttributes);
+ gc.setTransform(defaultTransform);
+ gc.setAlpha(currentAlpha);
+ if (this.lineColor != null) {
+ gc.setForeground(this.lineColor);
+ }
+ if (this.fillColor != null) {
+ gc.setBackground(this.fillColor);
+ }
+ int ixmax= this.xMax;
+ int iymax= this.yMax;
+
+ for (final ERGraphicInstruction instr : instructions) {
+ switch (instr.getInstructionType()) {
+ case RGraphicInstruction.INIT:
+ final GraphicInitialization init= (GraphicInitialization) instr;
+ ixmax= (int) (((init.width) * scale) + 0.5);
+ iymax= (int) (((init.height) * scale) + 0.5);
+ gc.setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
+ gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_BLACK));
+ gc.setAlpha(0xff);
+ gc.fillRectangle(0, 0, ixmax, iymax);
+ gc.setClipping(0, 0, ixmax, iymax);
+ continue;
+ case RGraphicInstruction.SET_CLIP: {
+ final ClipSetting setting= (ClipSetting) instr;
+ final int ix0= (int) ((setting.x0 * scale) + 0.5);
+ final int iy0= (int) ((setting.y0 * scale) + 0.5);
+ gc.setClipping(ix0, iy0,
+ (int) Math.min(((setting.x1 * scale) + 0.5), ixmax) - ix0,
+ (int) Math.min(((setting.y1 * scale) + 0.5), iymax) - iy0 );
+ continue; }
+ case RGraphicInstruction.SET_COLOR: {
+ final ColorSetting setting= (ColorSetting) instr;
+ lineAlpha= setting.getAlpha();
+ gc.setForeground(setting.swtColor);
+ continue; }
+ case RGraphicInstruction.SET_FILL: {
+ final FillSetting setting= (FillSetting) instr;
+ fillAlpha= setting.getAlpha();
+ gc.setBackground(setting.swtColor);
+ continue; }
+ case RGraphicInstruction.SET_LINE: {
+ final LineSetting setting= (LineSetting) instr;
+ switch (setting.type) {
+ case 0:
+ this.lineAttributes.style= SWT.LINE_SOLID;
+ this.lineAttributes.width= setting.width * scale;
+ gc.setLineAttributes(this.lineAttributes);
+ continue;
+ case -1:
+ this.lineAttributes.style= SWT.LINE_SOLID;
+ this.lineAttributes.width= 0.0f;
+ gc.setLineAttributes(this.lineAttributes);
+ continue;
+ // case 0x44:
+ // this.tempLineAttributes.style= SWT.LINE_DASH;
+ // this.tempLineAttributes.width= (float) (setting.width * scale);
+ // gc.setLineAttributes(this.tempLineAttributes);
+ // continue;
+ // case 0x13:
+ // this.tempLineAttributes.style= SWT.LINE_DOT;
+ // this.tempLineAttributes.width= (float) (setting.width * scale);
+ // gc.setLineAttributes(this.tempLineAttributes);
+ // continue;
+ // case 0x1343:
+ // this.tempLineAttributes.style= SWT.LINE_DASHDOT;
+ // this.tempLineAttributes.width= (float) (setting.width * scale);
+ // gc.setLineAttributes(this.tempLineAttributes);
+ // continue;
+ }
+
+ int rPattern= setting.type;
+ int length= 0;
+ while (rPattern != 0) {
+ length++;
+ rPattern >>>= 4;
+ }
+ final int[] dashes= new int[length];
+ rPattern= setting.type;
+ for (int i= 0; i < length; i++) {
+ dashes[i]= (rPattern & 0xf);
+ rPattern >>>= 4;
+ }
+ gc.setLineDash(dashes);
+ gc.setLineWidth((int) (setting.width * scale + 0.5));
+ continue; }
+ case RGraphicInstruction.SET_FONT: {
+ final FontSetting setting= (FontSetting) instr;
+ gc.setFont(setting.swtFont);
+ continue; }
+ case RGraphicInstruction.DRAW_LINE: {
+ final LineElement element= (LineElement) instr;
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawLine(
+ (int) (element.x0 * scale + 0.5),
+ (int) (element.y0 * scale + 0.5),
+ (int) (element.x1 * scale + 0.5),
+ (int) (element.y1 * scale + 0.5) );
+ continue; }
+ case RGraphicInstruction.DRAW_RECTANGLE: {
+ final RectElement element= (RectElement) instr;
+ final int ix0= (int) (element.x0 * scale + 0.5);
+ final int iy0= (int) (element.y0 * scale + 0.5);
+ final int iw= (int) (element.x1 * scale + 0.5) - ix0;
+ final int ih= (int) (element.y1 * scale + 0.5) - iy0;
+ if (fillAlpha != 0) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ gc.fillRectangle(ix0, iy0, iw, ih);
+ }
+ if (lineAlpha != 0) {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawRectangle(ix0, iy0, iw, ih);
+ }
+ continue; }
+ case RGraphicInstruction.DRAW_POLYLINE: {
+ final PolylineElement element= (PolylineElement) instr;
+ final int n= element.x.length;
+ final int[] icoord= new int[n * 2];
+ for (int i= 0, j= 0; j < n; j++) {
+ icoord[i++]= (int) (element.x[j] * scale + 0.5);
+ icoord[i++]= (int) (element.y[j] * scale + 0.5);
+ }
+ gc.drawPolyline(icoord);
+ continue; }
+ case RGraphicInstruction.DRAW_POLYGON: {
+ final PolygonElement element= (PolygonElement) instr;
+ final int n= element.x.length;
+ final int[] icoord= new int[n * 2];
+ for (int i= 0, j= 0; j < n; j++) {
+ icoord[i++]= (int) (element.x[j] * scale + 0.5);
+ icoord[i++]= (int) (element.y[j] * scale + 0.5);
+ }
+ if (fillAlpha != 0) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ gc.fillPolygon(icoord);
+ }
+ if (lineAlpha != 0) {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawPolygon(icoord);
+ }
+ continue; }
+ case RGraphicInstruction.DRAW_CIRCLE: {
+ final CircleElement element= (CircleElement) instr;
+ final int id= (int) (element.r * scale * 2.0 + 0.5);
+ final int ix0= (int) ((element.x - element.r) * scale + 0.5);
+ final int iy0= (int) ((element.y - element.r) * scale + 0.5);
+ if (fillAlpha != 0) {
+ if (fillAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= fillAlpha);
+ }
+ gc.fillOval(ix0, iy0, id, id);
+ }
+ if (lineAlpha != 0) {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawOval(ix0, iy0, id, id);
+ }
+ continue; }
+ case RGraphicInstruction.DRAW_TEXT: {
+ final TextElement element= (TextElement) instr;
+ final double hShift;
+ if (element.horizontalAdjust != 0.0) {
+ hShift= element.horizontalAdjust * gc.textExtent(element.text, (SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT)).x;
+ }
+ else {
+ hShift= 0.0;
+ }
+ if (element.rotateDegree != 0.0) {
+ if (tempTransform == null) {
+ tempTransform= new Transform(gc.getDevice());
+ }
+ tempTransform.identity();
+ tempTransform.translate((float) (element.x * scale), (float) (element.y * scale));
+ tempTransform.rotate((float) -element.rotateDegree);
+ tempTransform.translate((float) - hShift, - gc.getFontMetrics().getAscent());
+ gc.setTransform(tempTransform);
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawText(element.text, 0, 0,
+ (SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT) );
+ gc.setTransform(defaultTransform);
+ }
+ else {
+ if (lineAlpha != currentAlpha) {
+ gc.setAlpha(currentAlpha= lineAlpha);
+ }
+ gc.drawText(element.text,
+ (int) (((element.x - hShift) * scale) + 0.5),
+ (int) ((element.y * scale) + 0.5) - gc.getFontMetrics().getAscent(),
+ (SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_TRANSPARENT) );
+ }
+ continue; }
+ }
+ }
+
+ this.lineColor= gc.getForeground();
+ this.lineAlpha= lineAlpha;
+ this.fillColor= gc.getBackground();
+ this.fillAlpha= fillAlpha;
+ this.xMax= ixmax;
+ this.yMax= iymax;
+ }
+ finally {
+ if (tempTransform != null) {
+ tempTransform.dispose();
+ }
+ }
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/PageBookRGraphicView.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/PageBookRGraphicView.java
new file mode 100644
index 0000000..55ccb42
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/PageBookRGraphicView.java
@@ -0,0 +1,538 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.jface.action.IStatusLineManager;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.StatusLineContributionItem;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IViewSite;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.part.IPageBookViewPage;
+import org.eclipse.ui.services.IServiceLocator;
+import org.eclipse.ui.statushandlers.StatusManager;
+import org.eclipse.ui.views.IViewDescriptor;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ui.SharedUIResources;
+import org.eclipse.statet.ecommons.ui.actions.HandlerCollection;
+import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem;
+import org.eclipse.statet.ecommons.ui.actions.SimpleContributionItem;
+import org.eclipse.statet.ecommons.ui.mpbv.ISession;
+import org.eclipse.statet.ecommons.ui.mpbv.ManagedPageBookView;
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+
+
+/**
+ * Multi page view for R graphics.
+ * <p>
+ * No view is registered by this plug-in.</p>
+ */
+public abstract class PageBookRGraphicView extends ManagedPageBookView<PageBookRGraphicView.RGraphicSession> {
+
+
+ public class RGraphicSession implements ISession {
+
+
+ private final ERGraphic graphic;
+
+
+ public RGraphicSession(final ERGraphic graphic) {
+ this.graphic= graphic;
+ }
+
+
+ @Override
+ public ImageDescriptor getImageDescriptor() {
+ return ImageDescriptor.createFromImage(getTitleImage());
+ }
+
+ @Override
+ public String getLabel() {
+ return this.graphic.getLabel();
+ }
+
+ public ERGraphic getGraphic() {
+ return this.graphic;
+ }
+
+ }
+
+ public static class ShowRequiredViewListener implements ERGraphicsManager.ListenerShowExtension {
+
+
+ private final String viewId;
+
+
+ public ShowRequiredViewListener(final String viewId) {
+ this.viewId= viewId;
+ }
+
+
+ @Override
+ public int canShowGraphic(final ERGraphic graphic) {
+ return 0;
+ }
+
+ private static String getId(final IViewReference ref) {
+ // E-Bug #405563
+ final String id= ref.getId();
+ final int idx= id.indexOf(':');
+ return (idx >= 0) ? id.substring(0, idx) : id;
+ }
+
+ @Override
+ public void showGraphic(final ERGraphic graphic) {
+ try {
+ final IWorkbenchPage page= getBestPage(graphic);
+ String secondaryId= ""; //$NON-NLS-1$
+ final IViewReference[] refs= page.getViewReferences();
+ for (int i= 0; i < refs.length; i++) { // search views not yet instanced
+ if (this.viewId.equals(getId(refs[i])) && refs[i].getView(false) == null) {
+ if (refs[i].getSecondaryId() == null) {
+ secondaryId= null;
+ break;
+ }
+ if (secondaryId == "") { //$NON-NLS-1$
+ secondaryId= refs[i].getSecondaryId();
+ }
+ }
+ }
+ if (secondaryId == "") { //$NON-NLS-1$
+ secondaryId= "t"+System.currentTimeMillis(); //$NON-NLS-1$
+ }
+ newViewGraphic= graphic;
+ page.showView(this.viewId, secondaryId, IWorkbenchPage.VIEW_VISIBLE );
+ }
+ catch (final PartInitException e) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID,
+ "An error occurred when opening a new R Graphics view.", e ));
+ }
+ finally {
+ newViewGraphic= null;
+ }
+ }
+
+ protected IWorkbenchPage getBestPage(final ERGraphic graphic) {
+ return UIAccess.getActiveWorkbenchPage(true);
+ }
+
+ @Override
+ public void graphicAdded(final ERGraphic graphic) {
+ }
+
+ @Override
+ public void graphicRemoved(final ERGraphic graphic) {
+ }
+
+ }
+
+
+ protected static abstract class NewDevHandler extends AbstractHandler {
+
+
+ public NewDevHandler() {
+ }
+
+
+ protected abstract Tool getTool() throws CoreException;
+
+ @Override
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ try {
+ final Tool tool= getTool();
+ if (tool != null) {
+ tool.getQueue().add(new AbstractRToolRunnable(
+ "r/rj/gd/new", "New R Graphic") { //$NON-NLS-1$
+
+ @Override
+ public void run(final RToolService r,
+ final IProgressMonitor monitor) throws CoreException {
+ r.evalVoid("rj.gd::rj.GD()", monitor); //$NON-NLS-1$
+ }
+
+ });
+ }
+ }
+ catch (final CoreException e) {
+ if (e.getStatus().getSeverity() != IStatus.CANCEL) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+ "An error occurrend when creating a new graphic device.", e),
+ StatusManager.LOG | StatusManager.SHOW);
+ }
+ }
+ return null;
+ }
+
+ }
+
+
+ private static class RGraphicComparator implements Comparator<RGraphicSession> {
+
+ public RGraphicComparator() {
+ }
+
+ @Override
+ public int compare(final RGraphicSession o1, final RGraphicSession o2) {
+ final Tool handle1= o1.graphic.getRHandle();
+ final Tool handle2= o2.graphic.getRHandle();
+ if (handle1 == null) {
+ if (handle2 == null) {
+ return 0;
+ }
+ return Integer.MIN_VALUE;
+ }
+ else if (handle2 == null) {
+ return Integer.MAX_VALUE;
+ }
+ if (handle1 != handle2) {
+ final int diff= handle1.getLabel(Tool.LONG_LABEL).compareTo(handle2.getLabel(Tool.LONG_LABEL));
+ if (diff != 0) {
+ return diff;
+ }
+ }
+ return o1.graphic.getDevId() - o2.graphic.getDevId();
+ }
+
+ }
+
+
+ private static class OpenAdditionalViewHandler extends AbstractHandler {
+
+ private final IViewSite viewSite;
+
+ public OpenAdditionalViewHandler(final IViewSite viewSite) {
+ this.viewSite= viewSite;
+ }
+
+ @Override
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ try {
+ final String secondaryId= "t" + System.currentTimeMillis(); //$NON-NLS-1$
+ this.viewSite.getWorkbenchWindow().getActivePage().showView(this.viewSite.getId(),
+ secondaryId, IWorkbenchPage.VIEW_ACTIVATE );
+ }
+ catch (final PartInitException e) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+ "An error occurred when opening an additional R graphics view.", e));
+ }
+ return null;
+ }
+
+ }
+
+ private class PinPageAction extends SimpleContributionItem {
+
+ public PinPageAction() {
+ super(SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_PIN_PAGE_IMAGE_ID),
+ SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOLD_PIN_PAGE_IMAGE_ID),
+ "Pin Graphic Page", "P", SimpleContributionItem.STYLE_CHECK);
+ setChecked(PageBookRGraphicView.this.pinPage);
+ }
+
+ @Override
+ protected void execute() throws ExecutionException {
+ PageBookRGraphicView.this.pinPage= !PageBookRGraphicView.this.pinPage;
+ setChecked(PageBookRGraphicView.this.pinPage);
+ }
+
+ }
+
+
+ private static ERGraphic newViewGraphic;
+
+ private ERGraphicsManager manager;
+ private final ERGraphicsManager.ListenerShowExtension managerListener= new ERGraphicsManager.ListenerShowExtension() {
+ private ERGraphic toShow;
+ @Override
+ public int canShowGraphic(final ERGraphic graphic) {
+ return PageBookRGraphicView.this.canShowGraphic(graphic);
+ }
+ @Override
+ public void showGraphic(final ERGraphic graphic) {
+ this.toShow= graphic;
+ final IViewSite site= getViewSite();
+ try {
+ site.getPage().showView(site.getId(), site.getSecondaryId(), IWorkbenchPage.VIEW_VISIBLE);
+ }
+ catch (final PartInitException e) {}
+ }
+ @Override
+ public void graphicAdded(final ERGraphic graphic) {
+ add(graphic, graphic == this.toShow
+ || (graphic.isActive() && (!PageBookRGraphicView.this.pinPage || getCurrentSession() == null)) );
+ this.toShow= null;
+ }
+ @Override
+ public void graphicRemoved(final ERGraphic graphic) {
+ final RGraphicSession session= getSession(graphic);
+ if (session != null) {
+ PageBookRGraphicView.super.closePage(session);
+ }
+ }
+ };
+
+ private boolean pinPage;
+
+ private final ERGraphic.Listener graphicListener= new ERGraphic.ListenerLocatorExtension() {
+ @Override
+ public void activated() {
+ updateTitle();
+ }
+ @Override
+ public void deactivated() {
+ updateTitle();
+ }
+ @Override
+ public void drawingStarted() {
+ }
+ @Override
+ public void drawingStopped() {
+ }
+ @Override
+ public void locatorStarted() {
+ updateTitle();
+ }
+ @Override
+ public void locatorStopped() {
+ updateTitle();
+ }
+ };
+
+ private StatusLineContributionItem positionStatusLineItem;
+
+
+ public PageBookRGraphicView() {
+ }
+
+
+ @Override
+ public void init(final IViewSite site, final IMemento memento) throws PartInitException {
+ setSessionComparator(new RGraphicComparator());
+ super.init(site, memento);
+ this.manager= loadManager();
+ }
+
+ protected abstract ERGraphicsManager loadManager();
+
+ @Override
+ public void createPartControl(final Composite parent) {
+ super.createPartControl(parent);
+ if (this.manager != null) {
+ this.manager.addListener(this.managerListener);
+ ERGraphic active= newViewGraphic;
+ if (active != null) {
+ final List<? extends ERGraphic> graphics= this.manager.getAllGraphics();
+ for (final ERGraphic graphic : graphics) {
+ add(graphic, false);
+ }
+ }
+ else {
+ final List<? extends ERGraphic> graphics= this.manager.getAllGraphics();
+ for (final ERGraphic graphic : graphics) {
+ add(graphic, false);
+ if (graphic.isActive()) {
+ active= graphic;
+ }
+ }
+ if (active == null && !graphics.isEmpty()) {
+ active= graphics.get(graphics.size()-1);
+ }
+ }
+ if (active != null) {
+ final RGraphicSession session= getSession(active);
+ if (session != null) {
+ showPage(session);
+ }
+ }
+ }
+ }
+
+ public RGraphicSession getSession(final ERGraphic graphic) {
+ final List<RGraphicSession> sessions= getSessions();
+ for (final RGraphicSession session : sessions) {
+ if (session.getGraphic() == graphic) {
+ return session;
+ }
+ }
+ return null;
+ }
+
+ protected int canShowGraphic(final ERGraphic graphic) {
+ final RGraphicSession session= getCurrentSession();
+ int canShow;
+ if (session != null && session.getGraphic() == graphic) {
+ canShow= (this.pinPage) ? 20 : 10;
+ }
+ else if (this.pinPage && session != null) {
+ return -1;
+ }
+ else {
+ canShow= 1;
+ }
+ if (getViewSite().getPage().isPartVisible(this)) {
+ canShow+=2;
+ }
+ return canShow;
+ }
+
+ protected void add(final ERGraphic graphic, final boolean show) {
+ super.newPage(new RGraphicSession(graphic), show);
+ }
+
+ @Override
+ protected String getNoPageTitle() {
+ return "No graphics at this time.";
+ }
+
+ @Override
+ protected IHandler2 createNewPageHandler() {
+ return null;
+ }
+
+
+ @Override
+ protected void initActions(final IServiceLocator serviceLocator, final HandlerCollection handlers) {
+ super.initActions(serviceLocator, handlers);
+
+ final OpenAdditionalViewHandler openViewHandler= new OpenAdditionalViewHandler(getViewSite());
+ handlers.add(".OpenView", openViewHandler);
+ }
+
+ @Override
+ protected void contributeToActionBars(final IServiceLocator serviceLocator, final IActionBars actionBars, final HandlerCollection handlers) {
+ super.contributeToActionBars(serviceLocator, actionBars, handlers);
+
+ final IMenuManager menuManager= actionBars.getMenuManager();
+ menuManager.add(new Separator("view"));
+ final IViewDescriptor viewDescriptor= PlatformUI.getWorkbench().getViewRegistry().find(getViewSite().getId());
+ menuManager.add(new HandlerContributionItem(new CommandContributionItemParameter(serviceLocator,
+ null, HandlerContributionItem.NO_COMMAND_ID, null,
+ viewDescriptor.getImageDescriptor(), null, null,
+ NLS.bind("Open Additional {0} View", viewDescriptor.getLabel()), "O", null,
+ HandlerContributionItem.STYLE_PUSH, null, false), handlers.get(".OpenView")));
+ menuManager.add(new Separator("save"));
+ menuManager.add(new Separator(SharedUIResources.ADDITIONS_MENU_ID));
+
+ menuManager.add(new Separator("settings")); //$NON-NLS-1$
+ menuManager.add(new SimpleContributionItem("Preferences...", "P") {
+ @Override
+ protected void execute() throws ExecutionException {
+ final Shell shell= getViewSite().getShell();
+ final String[] preferencePages= collectContextMenuPreferencePages();
+ if (preferencePages.length > 0 && (shell == null || !shell.isDisposed())) {
+ org.eclipse.ui.dialogs.PreferencesUtil.createPreferenceDialogOn(shell, preferencePages[0], preferencePages, null).open();
+ }
+ }
+ });
+
+ final IToolBarManager toolBarManager= actionBars.getToolBarManager();
+ toolBarManager.insertAfter("page_control.change_page", new PinPageAction()); //$NON-NLS-1$
+
+ final IStatusLineManager lineManager= actionBars.getStatusLineManager();
+ this.positionStatusLineItem= new StatusLineContributionItem(RGraphicCompositeActionSet.POSITION_STATUSLINE_ITEM_ID, 20);
+ lineManager.add(this.positionStatusLineItem);
+ }
+
+ private String[] collectContextMenuPreferencePages() {
+ final List<String> pageIds= new ArrayList<>();
+ collectContextMenuPreferencePages(pageIds);
+ return pageIds.toArray(new String[pageIds.size()]);
+ }
+
+ protected void collectContextMenuPreferencePages(final List<String> pageIds) {
+ }
+
+
+ @Override
+ protected RGraphicPage doCreatePage(final RGraphicSession session) {
+ return new RGraphicPage(session.getGraphic());
+ }
+
+ @Override
+ protected void initPage(final IPageBookViewPage page) {
+ super.initPage(page);
+ if (page instanceof RGraphicPage) {
+ ((RGraphicPage) page).init(this.positionStatusLineItem);
+ }
+ }
+
+ @Override
+ public void closePage(final RGraphicSession session) {
+ final IStatus status= session.getGraphic().close();
+ if (status != null && status.getSeverity() < IStatus.ERROR) {
+ return;
+ }
+ super.closePage(session);
+ }
+
+ @Override
+ protected void onPageShowing(final IPageBookViewPage page, final RGraphicSession session) {
+ if (session != null) {
+ session.getGraphic().addListener(this.graphicListener);
+ }
+ super.onPageShowing(page, session);
+ }
+
+ @Override
+ protected void onPageHiding(final IPageBookViewPage page, final RGraphicSession session) {
+ if (session != null) {
+ session.getGraphic().removeListener(this.graphicListener);
+ }
+ if (this.positionStatusLineItem != null) {
+ this.positionStatusLineItem.setText(""); //$NON-NLS-1$
+ }
+ super.onPageHiding(page, session);
+ }
+
+ @Override
+ public void dispose() {
+ if (this.manager != null) {
+ this.manager.removeListener(this.managerListener);
+ }
+ final RGraphicSession session= getCurrentSession();
+ if (session != null) {
+ session.getGraphic().removeListener(this.graphicListener);
+ }
+ super.dispose();
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCanvas.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCanvas.java
new file mode 100644
index 0000000..aef25a8
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCanvas.java
@@ -0,0 +1,106 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Composite;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.GraphicInitialization;
+
+
+/**
+ * SWT control to paint an R graphic.
+ * <p>
+ * See {@link RGraphicComposite} for a higher API widget.</p>
+ */
+public class RGraphicCanvas extends Canvas implements PaintListener {
+
+
+ public static final List<ERGraphicInstruction> NO_GRAPHIC= Collections.emptyList();
+
+
+ private List<? extends ERGraphicInstruction> graphicInstructions;
+ private final DefaultGCRenderer renderer;
+
+ private GraphicInitialization init;
+
+
+ public RGraphicCanvas(final Composite parent) {
+ super(parent, checkStyle(0));
+
+ this.graphicInstructions= Collections.emptyList();
+ this.renderer= new DefaultGCRenderer();
+ addPaintListener(this);
+ }
+
+ private static int checkStyle(int style) {
+ style |= SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND;
+ style |= SWT.DOUBLE_BUFFERED;
+ return style;
+ }
+
+ public void setInstructions(final List<? extends ERGraphicInstruction> graphicData) {
+ this.graphicInstructions= graphicData;
+ if (!this.graphicInstructions.isEmpty()) {
+ this.init= (GraphicInitialization) this.graphicInstructions.get(0);
+ }
+ else {
+ this.init= null;
+ }
+ }
+
+ @Override
+ public Point computeSize(final int wHint, final int hHint, final boolean changed) {
+ final GraphicInitialization init= this.init;
+ if (init != null) {
+ return new Point((int) (init.width + 0.5), (int) (init.height + 0.5));
+ }
+ else {
+ return super.computeSize(wHint, hHint, changed);
+ }
+ }
+
+ public double widget2graphicsX(final double x) {
+ return x; // scale
+ }
+
+ public double widget2graphicY(final double y) {
+ return y; // scale
+ }
+
+ @Override
+ public void paintControl(final PaintEvent e) {
+ final GC gc= e.gc;
+
+ final Rectangle clientArea= getClientArea();
+ setBackground(gc.getDevice().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
+ drawBackground(gc, 0, 0, clientArea.width, clientArea.height);
+ if (this.graphicInstructions.isEmpty()) {
+ return;
+ }
+ this.renderer.clear(1.0f); // scale
+ this.renderer.paint(gc, this.graphicInstructions);
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicComposite.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicComposite.java
new file mode 100644
index 0000000..9654a69
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicComposite.java
@@ -0,0 +1,550 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.List;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ScrollBar;
+
+
+/**
+ * Composite to display an R graphic.
+ */
+public class RGraphicComposite extends Composite
+ implements ERGraphic.ListenerInstructionsExtension, ERGraphic.ListenerLocatorExtension {
+
+
+ /**
+ * This class provides the layout for RGraphicComposite
+ */
+ private static class ScrolledCompositeLayout extends Layout {
+
+ static final int DEFAULT_WIDTH = 64;
+ static final int DEFAULT_HEIGHT = 64;
+
+
+ private boolean inLayout= false;
+
+
+ public ScrolledCompositeLayout() {
+ }
+
+
+ @Override
+ protected boolean flushCache(final Control control) {
+ return true;
+ }
+
+ @Override
+ protected Point computeSize(final Composite composite, final int wHint, final int hHint, final boolean flushCache) {
+ final RGraphicComposite sc= (RGraphicComposite) composite;
+ final Point size= new Point(wHint, hHint);
+ if (wHint == SWT.DEFAULT) {
+ size.x= Math.max(DEFAULT_WIDTH, sc.width);
+ }
+ if (hHint == SWT.DEFAULT) {
+ size.y= Math.max(DEFAULT_HEIGHT, sc.height);
+ }
+ return size;
+ }
+
+ @Override
+ protected void layout(final Composite composite, final boolean flushCache) {
+ if (this.inLayout || composite == null) {
+ return;
+ }
+ final RGraphicComposite sc= (RGraphicComposite) composite;
+ final ScrollBar hBar= sc.getHorizontalBar();
+ final ScrollBar vBar= sc.getVerticalBar();
+
+ if (hBar.getSize().y >= sc.getSize().y) {
+ return;
+ }
+ if (vBar.getSize().x >= sc.getSize().x) {
+ return;
+ }
+
+ this.inLayout= true;
+
+ final Rectangle previousBounds= sc.canvas.getBounds();
+ boolean hVisible= sc.needHBar(previousBounds, false);
+ final boolean vVisible= sc.needVBar(previousBounds, hVisible);
+ if (!hVisible && vVisible) {
+ hVisible= sc.needHBar(previousBounds, vVisible);
+ }
+ hBar.setVisible(hVisible);
+ vBar.setVisible(vVisible);
+
+ final Rectangle clientArea= sc.getClientArea();
+ final int x;
+ final int y;
+ final int width= sc.width;
+ final int height= sc.height;
+ hBar.setThumb(clientArea.width);
+ hBar.setPageIncrement(clientArea.width);
+ if (hVisible) {
+ x= (sc.changedLayout || previousBounds.x >= 0) ? 0 :
+ Math.max(previousBounds.x, clientArea.width - width);
+ hBar.setSelection(-x);
+ }
+ else {
+ x= (clientArea.width - width) / 2;
+ hBar.setSelection(0);
+ }
+ vBar.setThumb(clientArea.height);
+ vBar.setPageIncrement(clientArea.height);
+ if (vVisible) {
+ y= (sc.changedLayout || previousBounds.y >= 0) ? 0 :
+ Math.max(previousBounds.y, clientArea.height - height);
+ vBar.setSelection(-y);
+ }
+ else {
+ y= (clientArea.height - height) / 2;
+ vBar.setSelection(0);
+ }
+
+ sc.changedLayout= false;
+ sc.canvas.setBounds(x, y, width, height);
+ this.inLayout= false;
+ }
+
+ }
+
+ private class PanListener implements Listener {
+
+ private boolean started;
+ private Point startMouse;
+
+ @Override
+ public void handleEvent(final Event event) {
+ switch (event.type) {
+ case SWT.MouseDown:
+ if (event.button == 2) {
+ this.started= true;
+ updateCursor();
+
+ this.startMouse= checkedPoint(event);
+ return;
+ }
+ else {
+ this.started= false;
+ return;
+ }
+ case SWT.MouseExit:
+ case SWT.MouseMove:
+ if (this.started) {
+ pan(checkedPoint(event));
+ return;
+ }
+ else {
+ return;
+ }
+ case SWT.MouseUp:
+ if (this.started && event.button == 2) {
+ this.started= false;
+ updateCursor();
+ return;
+ }
+ else {
+ return;
+ }
+ case SWT.KeyDown:
+ switch (event.keyCode) {
+ case SWT.ARROW_DOWN:
+ if (update(getVerticalBar(), RGraphicComposite.this.panIncrement)) {
+ scrollV();
+ }
+ return;
+ case SWT.ARROW_UP:
+ if (update(getVerticalBar(), -RGraphicComposite.this.panIncrement)) {
+ scrollV();
+ }
+ return;
+ case SWT.ARROW_RIGHT:
+ if (update(getHorizontalBar(), RGraphicComposite.this.panIncrement)) {
+ scrollH();
+ }
+ return;
+ case SWT.ARROW_LEFT:
+ if (update(getHorizontalBar(), -RGraphicComposite.this.panIncrement)) {
+ scrollH();
+ }
+ return;
+ default:
+ return;
+ }
+ }
+ }
+
+ private Point checkedPoint(final Event event) {
+ if (event.item == RGraphicComposite.this) {
+ return new Point(event.x, event.y);
+ }
+ else {
+ final Point point= ((Control) event.widget).toDisplay(event.x, event.y);
+ return RGraphicComposite.this.toControl(point);
+ }
+ }
+
+ private void pan(final Point point) {
+ if (update(getHorizontalBar(), this.startMouse.x - point.x)) {
+ scrollH();
+ }
+ if (update(getVerticalBar(), this.startMouse.y - point.y)) {
+ scrollV();
+ }
+ this.startMouse= point;
+ }
+
+ private boolean update(final ScrollBar bar, final int step) {
+ if (bar != null && bar.isVisible()) {
+ int selection= bar.getSelection() + step;
+ if (selection < 0) {
+ selection= 0;
+ }
+ else if (selection > bar.getMaximum()) {
+ selection= bar.getMaximum() - bar.getThumb();
+ }
+ bar.setSelection(selection);
+ return true;
+ }
+ return false;
+ }
+
+ }
+
+
+ private static int checkStyle (final int style) {
+ final int mask= SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ return style & mask;
+ }
+
+
+ private ERGraphic graphic;
+
+ private RGraphicCanvas canvas;
+
+ private int width= 0;
+ private int height= 0;
+
+ private boolean changedLayout;
+ private boolean changedContent;
+
+ private int panIncrement;
+ private final PanListener panListener;
+
+ private MouseListener locatorListener;
+
+
+ public RGraphicComposite(final Composite parent, final ERGraphic graphic) {
+ super(parent, checkStyle(SWT.H_SCROLL | SWT.V_SCROLL));
+ super.setLayout(new ScrolledCompositeLayout());
+
+ this.panIncrement= 10;
+
+ final ScrollBar hBar= getHorizontalBar();
+ hBar.setVisible(false);
+ hBar.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ scrollH();
+ }
+ });
+ hBar.setIncrement(this.panIncrement);
+ final ScrollBar vBar= getVerticalBar();
+ vBar.setVisible(false);
+ vBar.addListener(SWT.Selection, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ scrollV();
+ }
+ });
+ vBar.setIncrement(this.panIncrement);
+ addListener(SWT.Resize, new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+// checkContentSize();
+ }
+ });
+ createCanvas();
+ final Listener updateListener= new Listener() {
+ @Override
+ public void handleEvent(final Event event) {
+ if (RGraphicComposite.this.changedContent) {
+ updateGraphic();
+ }
+ }
+ };
+ addListener(SWT.Show, updateListener);
+ addListener(SWT.Activate, updateListener);
+
+ this.panListener= new PanListener();
+ addListener(SWT.MouseDown, this.panListener);
+ addListener(SWT.MouseMove, this.panListener);
+ addListener(SWT.MouseExit, this.panListener);
+ addListener(SWT.MouseUp, this.panListener);
+ addListener(SWT.KeyDown, this.panListener);
+ this.canvas.addListener(SWT.MouseDown, this.panListener);
+ this.canvas.addListener(SWT.MouseMove, this.panListener);
+ this.canvas.addListener(SWT.MouseExit, this.panListener);
+ this.canvas.addListener(SWT.MouseUp, this.panListener);
+ this.canvas.addListener(SWT.KeyDown, this.panListener);
+
+ setGraphic(graphic);
+
+ addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(final DisposeEvent e) {
+ disconnect();
+ }
+ });
+ }
+
+ private void createCanvas() {
+ this.canvas= new RGraphicCanvas(this);
+ }
+
+ boolean needHBar(final Rectangle contentRect, final boolean vVisible) {
+ final Rectangle hostRect= getBounds();
+ hostRect.width-= 2 * getBorderWidth();
+ if (vVisible) {
+ hostRect.width-= getVerticalBar().getSize().x;
+ }
+ return (this.width > hostRect.width);
+ }
+
+ boolean needVBar(final Rectangle contentRect, final boolean hVisible) {
+ final Rectangle hostRect= getBounds();
+ hostRect.height-= 2 * getBorderWidth();
+ if (hVisible) {
+ hostRect.height-= getHorizontalBar().getSize().y;
+ }
+ return (this.height > hostRect.height);
+ }
+
+ private void scrollH() {
+ final Point location= this.canvas.getLocation();
+ final ScrollBar hBar= getHorizontalBar();
+ if (hBar != null && hBar.isVisible()) {
+ final int hSelection= hBar.getSelection();
+ this.canvas.setLocation(-hSelection, location.y);
+ }
+ }
+
+ private void scrollV() {
+ final Point location= this.canvas.getLocation();
+ final ScrollBar vBar= getVerticalBar();
+ if (vBar != null && vBar.isVisible()) {
+ final int vSelection= vBar.getSelection();
+ this.canvas.setLocation(location.x, -vSelection);
+ }
+ }
+
+
+ protected void disconnect() {
+ if (this.graphic != null) {
+ this.graphic.removeListener(this);
+ }
+ locatorStopped();
+ }
+
+ public void setGraphic(final ERGraphic graphic) {
+ disconnect();
+
+ this.graphic= graphic;
+ if (this.graphic != null) {
+ this.graphic.addListener(this);
+ }
+
+ instructionsChanged(true, null);
+
+ if (this.graphic != null && this.graphic.isLocatorStarted()) {
+ locatorStarted();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Note: No Layout can be set on this Control because it already
+ * manages the size and position of its children.</p>
+ */
+ @Override
+ public void setLayout (final Layout layout) {
+ checkWidget();
+ return;
+ }
+
+ @Override
+ public void activated() {
+ }
+
+ @Override
+ public void deactivated() {
+ }
+
+ @Override
+ public void drawingStarted() {
+ }
+
+ @Override
+ public void instructionsChanged(final boolean reset, final List<ERGraphicInstruction> added) {
+ this.changedContent= true;
+ if (isVisible()) {
+ updateGraphic();
+ }
+ }
+
+ @Override
+ public void drawingStopped() {
+ }
+
+ @Override
+ public void locatorStarted() {
+ if (this.locatorListener == null) {
+ this.locatorListener= new MouseListener() {
+ @Override
+ public void mouseDown(final MouseEvent e) {
+ switch (e.button) {
+ case 1:
+ RGraphicComposite.this.graphic.returnLocator(
+ RGraphicComposite.this.canvas.widget2graphicsX(e.x), RGraphicComposite.this.canvas.widget2graphicY(e.y));
+ break;
+ case 3:
+ RGraphicComposite.this.graphic.stopLocator(ERGraphic.LOCATOR_DONE);
+ break;
+ default:
+ break;
+ }
+ }
+ @Override
+ public void mouseUp(final MouseEvent e) {
+ }
+ @Override
+ public void mouseDoubleClick(final MouseEvent e) {
+ }
+ };
+ this.canvas.addMouseListener(this.locatorListener);
+ updateCursor();
+ }
+ }
+
+ @Override
+ public void locatorStopped() {
+ if (this.locatorListener != null) {
+ this.canvas.removeMouseListener(this.locatorListener);
+ this.locatorListener= null;
+ updateCursor();
+ }
+ }
+
+ private void updateCursor() {
+ if (this.panListener.started) {
+ this.canvas.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_HAND));
+ }
+ else if (this.locatorListener != null) {
+ this.canvas.setCursor(Display.getCurrent().getSystemCursor(SWT.CURSOR_CROSS));
+ }
+ else {
+ this.canvas.setCursor(null);
+ }
+ }
+
+ private void checkContentSize() {
+ final Point size= this.canvas.computeSize(SWT.DEFAULT, SWT.DEFAULT);
+ if (this.width == size.x && this.height == size.y) {
+ return;
+ }
+ this.changedLayout= true;
+ this.width= size.x;
+ this.height= size.y;
+ this.canvas.setSize(this.width, this.height);
+
+ final ScrollBar hBar= getHorizontalBar();
+ hBar.setMaximum(this.width);
+
+ final ScrollBar vBar= getVerticalBar();
+ vBar.setMaximum(this.height);
+ layout(false);
+ }
+
+
+ public void redrawGraphic() {
+ this.canvas.redraw();
+ }
+
+ private void updateGraphic() {
+ this.changedContent= false;
+ final List<? extends ERGraphicInstruction> instructions= (this.graphic != null) ?
+ this.graphic.getInstructions() : RGraphicCanvas.NO_GRAPHIC;
+ this.canvas.setInstructions(instructions);
+ checkContentSize();
+ this.canvas.redraw();
+ }
+
+ public double[] getGraphicFitSize() {
+ final Rectangle bounds= getBounds();
+ return new double[] { bounds.width, bounds.height };
+ }
+
+ public Control getControl() {
+ return this;
+ }
+
+ /**
+ * Returns the control on which the graphic is painted
+ *
+ * @since 1.0
+ */
+ public Control getGraphicWidget() {
+ return this.canvas;
+ }
+
+ /**
+ * Converts a horizontal display coordinate of the {@link #getGraphicWidget() graphic widget}
+ * to its graphic coordinate value.
+ *
+ * @since 1.0
+ * @see ERGraphic Coordinate systems of R graphics
+ */
+ public double convertWidget2GraphicX(final int x) {
+ return this.canvas.widget2graphicsX(x);
+ }
+
+ /**
+ * Converts a vertical display coordinate of the {@link #getGraphicWidget() graphic widget}
+ * to its graphic coordinate value.
+ *
+ * @since 1.0
+ * @see ERGraphic Coordinate systems of R graphics
+ */
+ public double convertWidget2GraphicY(final int y) {
+ return this.canvas.widget2graphicY(y);
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCompositeActionSet.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCompositeActionSet.java
new file mode 100644
index 0000000..fc7fff4
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicCompositeActionSet.java
@@ -0,0 +1,485 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.menus.CommandContributionItemParameter;
+import org.eclipse.ui.services.IServiceLocator;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.ImIdentityList;
+
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ui.SharedUIResources;
+import org.eclipse.statet.ecommons.ui.actions.HandlerCollection;
+import org.eclipse.statet.ecommons.ui.actions.HandlerContributionItem;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.RGraphicsPlugin;
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.eclient.graphics.util.AbstractLocalLocator;
+
+
+/**
+ * Actions for R graphics in an {@link RGraphicComposite}.
+ */
+public class RGraphicCompositeActionSet implements ERGraphic.ListenerLocatorExtension {
+
+
+ public static final String POSITION_STATUSLINE_ITEM_ID= "position"; //$NON-NLS-1$
+
+ public static final String CONTEXT_MENU_GROUP_ID= "context"; //$NON-NLS-1$
+ public static final String SIZE_MENU_GROUP_ID= "size"; //$NON-NLS-1$
+
+ private static final String LOCATOR_DONE_COMMAND_ID= ".locator.done"; //$NON-NLS-1$
+ private static final String LOCATOR_CANCEL_COMMAND_ID= ".locator.cancel"; //$NON-NLS-1$
+ private static final String RESIZE_FIT_COMMAND_ID= ".resize.fit"; //$NON-NLS-1$
+
+
+ public static interface LocationListener {
+
+ void loading();
+
+ void located(double x, double y);
+
+ }
+
+
+ private class ResizeFitRHandler extends AbstractHandler {
+
+ public ResizeFitRHandler() {
+ }
+
+ @Override
+ public void setEnabled(final Object evaluationContext) {
+ setBaseEnabled(RGraphicCompositeActionSet.this.graphic != null);
+ }
+
+ @Override
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ if (RGraphicCompositeActionSet.this.graphic == null) {
+ return null;
+ }
+ final double[] size= RGraphicCompositeActionSet.this.graphicComposite.getGraphicFitSize();
+ final IStatus status= RGraphicCompositeActionSet.this.graphic.resize(size[0], size[1]);
+ if (status == null || !status.isOK()) {
+ // TODO: Status message
+ Display.getCurrent().beep();
+ }
+ return null;
+ }
+
+ }
+
+ protected class StopLocatorHandler extends AbstractHandler {
+
+ private final String type;
+
+ public StopLocatorHandler(final String type) {
+ this.type= type;
+ }
+
+ @Override
+ public void setEnabled(final Object evaluationContext) {
+ setBaseEnabled(RGraphicCompositeActionSet.this.graphic != null && RGraphicCompositeActionSet.this.graphic.isLocatorStarted()
+ && RGraphicCompositeActionSet.this.graphic.getLocatorStopTypes().contains(this.type) );
+ }
+
+ @Override
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ if (RGraphicCompositeActionSet.this.graphic == null) {
+ return null;
+ }
+ RGraphicCompositeActionSet.this.graphic.stopLocator(this.type);
+ return null;
+ }
+
+ }
+
+ private static abstract class ConversionRunnable extends AbstractRToolRunnable implements SystemRunnable {
+
+ private final ERGraphic graphic;
+
+ private boolean scheduled;
+
+ private double[] todoSource;
+
+ private double[] convertedSource;
+ private double[] convertedTarget;
+
+
+ public ConversionRunnable(final ERGraphic graphic) {
+ super("r/rjgd/position", "Converting graphic coordinates"); //$NON-NLS-1$
+ this.graphic= graphic;
+ }
+
+
+ public boolean schedule(final double[] source) {
+ synchronized (this) {
+ this.todoSource= source;
+ if (this.scheduled) {
+ return true;
+ }
+ final IStatus status= this.graphic.getRHandle().getQueue().addHot(this);
+ if (status.isOK()) {
+ this.scheduled= true;
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public void cancel() {
+ synchronized (this) {
+ if (this.scheduled) {
+ this.scheduled= false;
+ this.todoSource= null;
+ this.graphic.getRHandle().getQueue().removeHot(this);
+ }
+ }
+ }
+
+
+ @Override
+ public boolean canRunIn(final Tool tool) {
+ return (tool == this.graphic.getRHandle() && super.canRunIn(tool));
+ }
+
+ @Override
+ public boolean changed(final int event, final Tool tool) {
+ switch (event) {
+ case MOVING_FROM:
+ return false;
+ case REMOVING_FROM:
+ case BEING_ABANDONED:
+ case FINISHING_ERROR:
+ case FINISHING_CANCEL:
+ synchronized (this) {
+ this.scheduled= false;
+ break;
+ }
+ case FINISHING_OK:
+ converted(this.graphic, this.convertedSource, this.convertedTarget);
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ protected void run(final RToolService service,
+ final IProgressMonitor monitor) throws CoreException {
+ double[] source= null;
+ double[] target= null;
+ while (true) {
+ synchronized (this) {
+ this.convertedSource= source;
+ this.convertedTarget= target;
+
+ source= this.todoSource;
+ if (source == null) {
+ this.scheduled= false;
+ return;
+ }
+ this.todoSource= null;
+ }
+ target= this.graphic.convertGraphic2User(source, monitor);
+ }
+ }
+
+ protected abstract void converted(ERGraphic graphic, double[] source, double[] target);
+
+ }
+
+ private class MouseLocationListener implements Listener {
+
+ private double[] currentGraphic;
+ private double[] currentTarget;
+
+
+ @Override
+ public void handleEvent(final Event event) {
+ switch (event.type) {
+ case SWT.MouseDown:
+ if (event.button == 1) {
+ final double[] request= this.currentGraphic= new double[] {
+ RGraphicCompositeActionSet.this.graphicComposite.convertWidget2GraphicX(event.x),
+ RGraphicCompositeActionSet.this.graphicComposite.convertWidget2GraphicY(event.y) };
+ this.currentTarget= null;
+ event.display.timerExec(1000, new Runnable() {
+ @Override
+ public void run() {
+ if (MouseLocationListener.this.currentTarget == null && MouseLocationListener.this.currentGraphic == request
+ && !RGraphicCompositeActionSet.this.graphicComposite.isDisposed()) {
+ notifyMouseLocationListeners(null);
+ }
+ }
+ });
+ if (RGraphicCompositeActionSet.this.mouseLocationRunnable == null) {
+ RGraphicCompositeActionSet.this.mouseLocationRunnable= new ConversionRunnable(RGraphicCompositeActionSet.this.graphic) {
+ @Override
+ protected void converted(final ERGraphic graphic,
+ final double[] source, final double[] target) {
+ if (RGraphicCompositeActionSet.this.graphic == graphic) {
+ RGraphicCompositeActionSet.this.display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (RGraphicCompositeActionSet.this.graphic == graphic
+ && source != null && target != null && MouseLocationListener.this.currentGraphic != null
+ && source[0] == MouseLocationListener.this.currentGraphic[0] && source[1] == MouseLocationListener.this.currentGraphic[1]) {
+ MouseLocationListener.this.currentTarget= target;
+ notifyMouseLocationListeners(target);
+ }
+ }
+ });
+ }
+ }
+ };
+ }
+ RGraphicCompositeActionSet.this.mouseLocationRunnable.schedule(this.currentGraphic);
+ }
+ break;
+ }
+ }
+
+ }
+
+
+ private final List<IActionBars> actionBars= new ArrayList<>(4);
+
+ private ERGraphic graphic;
+ private final RGraphicComposite graphicComposite;
+ private final Display display;
+
+ private HandlerCollection handlerCollection;
+
+ private final CopyOnWriteIdentityListSet<LocationListener> mouseLocationListeners= new CopyOnWriteIdentityListSet<>();
+ private MouseLocationListener mouseListenerListener;
+ private ConversionRunnable mouseLocationRunnable;
+
+
+ public RGraphicCompositeActionSet(final RGraphicComposite composite) {
+ this.graphicComposite= composite;
+ this.display= this.graphicComposite.getDisplay();
+ }
+
+
+ public void setGraphic(final ERGraphic graphic) {
+ if (this.graphic != null) {
+ this.graphic.removeListener(this);
+ if (this.mouseLocationRunnable != null) {
+ this.mouseLocationRunnable.cancel();
+ this.mouseLocationRunnable= null;
+ }
+ }
+ this.graphic= graphic;
+ if (this.graphic != null) {
+ this.graphic.addListener(this);
+ }
+
+ update();
+ }
+
+ public void initActions(final IServiceLocator serviceLocator) {
+ this.handlerCollection= new HandlerCollection();
+ this.handlerCollection.add(LOCATOR_DONE_COMMAND_ID,
+ new StopLocatorHandler(ERGraphic.LOCATOR_DONE) );
+ this.handlerCollection.add(LOCATOR_CANCEL_COMMAND_ID,
+ new StopLocatorHandler(ERGraphic.LOCATOR_CANCEL) );
+ this.handlerCollection.add(RESIZE_FIT_COMMAND_ID,
+ new ResizeFitRHandler() );
+ }
+
+ public void contributeToActionsBars(final IServiceLocator serviceLocator,
+ final IActionBars actionBars) {
+ this.actionBars.add(actionBars);
+
+ final IToolBarManager toolBar= actionBars.getToolBarManager();
+ if (toolBar.find(CONTEXT_MENU_GROUP_ID) == null) {
+ toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(CONTEXT_MENU_GROUP_ID));
+ }
+ if (toolBar.find(SIZE_MENU_GROUP_ID) == null) {
+ toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(SIZE_MENU_GROUP_ID));
+ }
+
+ final ImageRegistry rGraphicsImageRegistry= RGraphicsPlugin.getDefault().getImageRegistry();
+
+ toolBar.appendToGroup(CONTEXT_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+ serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+ rGraphicsImageRegistry.getDescriptor(RGraphicsPlugin.IMG_LOCTOOL_LOCATOR_DONE), null, null,
+ "Stop Locator", null, null, HandlerContributionItem.STYLE_PUSH, null, true),
+ this.handlerCollection.get(LOCATOR_DONE_COMMAND_ID) ));
+ toolBar.appendToGroup(CONTEXT_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+ serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+ rGraphicsImageRegistry.getDescriptor(RGraphicsPlugin.IMG_LOCTOOL_LOCATOR_CANCEL), null, null,
+ "Cancel Locator", null, null, HandlerContributionItem.STYLE_PUSH, null, true),
+ this.handlerCollection.get(LOCATOR_CANCEL_COMMAND_ID) ));
+ }
+
+ protected void addTestLocator(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+ final IToolBarManager toolBar= actionBars.getToolBarManager();
+
+ final IHandler2 handler= new AbstractHandler() {
+ @Override
+ public void setEnabled(final Object evaluationContext) {
+ setBaseEnabled(RGraphicCompositeActionSet.this.graphic != null && !RGraphicCompositeActionSet.this.graphic.isLocatorStarted());
+ }
+ @Override
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ if (RGraphicCompositeActionSet.this.graphic == null || RGraphicCompositeActionSet.this.graphic.isLocatorStarted()) {
+ return null;
+ }
+ final AbstractLocalLocator locator= new AbstractLocalLocator(RGraphicCompositeActionSet.this.graphic) {
+ @Override
+ protected void finished(final List<double[]> graphic, final List<double[]> user) {
+ final StringBuilder sb= new StringBuilder();
+ for (int i= 0; i < user.size(); i++) {
+ sb.append(Arrays.toString(user.get(i))).append("\n");
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ MessageDialog.openInformation(null, "Locator Result",
+ sb.toString());
+ }
+ });
+ };
+ @Override
+ protected void canceled() {
+ };
+ };
+ locator.start();
+ return null;
+ }
+ };
+ this.handlerCollection.add(".locator.startTest", handler);
+ toolBar.appendToGroup(CONTEXT_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+ serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+ SharedUIResources.getImages().getDescriptor(SharedUIResources.LOCTOOL_SORT_SCORE_IMAGE_ID), null, null,
+ "Test Locator", null, null, HandlerContributionItem.STYLE_PUSH, null, false),
+ handler ));
+ }
+
+ protected void addSizeActions(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+ final IToolBarManager toolBar= actionBars.getToolBarManager();
+
+ final ImageRegistry rGraphicsImageRegistry= RGraphicsPlugin.getDefault().getImageRegistry();
+
+ toolBar.appendToGroup(SIZE_MENU_GROUP_ID, new HandlerContributionItem(new CommandContributionItemParameter(
+ serviceLocator, null, HandlerContributionItem.NO_COMMAND_ID, null,
+ rGraphicsImageRegistry.getDescriptor(RGraphicsPlugin.IMG_LOCTOOL_RESIZE_FIT_R), null, null,
+ "Resize Fit in R", null, null, HandlerContributionItem.STYLE_PUSH, null, false ),
+ this.handlerCollection.get(RESIZE_FIT_COMMAND_ID) ));
+
+ update();
+ }
+
+ protected void update() {
+ if (this.actionBars.isEmpty()) {
+ return;
+ }
+
+ this.handlerCollection.update(null);
+
+ for (final IActionBars actionBars : this.actionBars) {
+ actionBars.getToolBarManager().update(true);
+ }
+ }
+
+
+ @Override
+ public void activated() {
+ }
+
+ @Override
+ public void deactivated() {
+ }
+
+ @Override
+ public void drawingStarted() {
+ }
+
+ @Override
+ public void drawingStopped() {
+ }
+
+ @Override
+ public void locatorStarted() {
+ update();
+ }
+
+ @Override
+ public void locatorStopped() {
+ update();
+ }
+
+
+ public void addMouseClickLocationListener(final LocationListener listener) {
+ this.mouseLocationListeners.add(listener);
+ if (this.mouseListenerListener == null) {
+ this.mouseListenerListener= new MouseLocationListener();
+ final Control widget= this.graphicComposite.getGraphicWidget();
+ widget.addListener(SWT.MouseDown, this.mouseListenerListener);
+ }
+ }
+
+ public void removeMouseLocationListener(final LocationListener listener) {
+ this.mouseLocationListeners.remove(listener);
+ }
+
+ private void notifyMouseLocationListeners(final double[] xy) {
+ final ImIdentityList<LocationListener> listeners= this.mouseLocationListeners.toList();
+ if (xy != null) {
+ for (final LocationListener listener : listeners) {
+ listener.located(xy[0], xy[1]);
+ }
+ }
+ else {
+ for (final LocationListener listener : listeners) {
+ listener.loading();
+ }
+ }
+ }
+
+
+ public void dispose(final IActionBars actionBars) {
+ this.actionBars.remove(actionBars);
+ }
+
+ public void dispose() {
+ setGraphic(null);
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicPage.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicPage.java
new file mode 100644
index 0000000..33401f0
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicPage.java
@@ -0,0 +1,185 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Locale;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IHandler2;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.jface.action.StatusLineContributionItem;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.part.Page;
+import org.eclipse.ui.services.IServiceLocator;
+
+import org.eclipse.statet.ecommons.runtime.core.StatusChangeListener;
+import org.eclipse.statet.ecommons.ui.SharedUIResources;
+import org.eclipse.statet.ecommons.ui.util.UIAccess;
+
+import org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet.LocationListener;
+
+
+/**
+ * Single graphic page for {@link PageBookRGraphicView}.
+ */
+public class RGraphicPage extends Page implements StatusChangeListener {
+
+
+ private final ERGraphic graphic;
+
+ private RGraphicComposite control;
+
+ private RGraphicCompositeActionSet actions;
+
+ private StatusLineContributionItem locationStatusItem;
+ private String locationStatusText;
+ private LocationListener mouseLocationListener;
+
+
+ public RGraphicPage(final ERGraphic graphic) {
+ this.graphic= graphic;
+ }
+
+
+ protected ERGraphic getGraphic() {
+ return this.graphic;
+ }
+
+ protected void init(final StatusLineContributionItem locationStatusItem) {
+ this.locationStatusItem= locationStatusItem;
+ }
+
+ @Override
+ public void createControl(final Composite parent) {
+ this.control= new RGraphicComposite(parent, this.graphic);
+
+ initActions(getSite(), getSite().getActionBars());
+
+ this.graphic.addMessageListener(this);
+ statusChanged(this.graphic.getMessage());
+ }
+
+ protected void initActions(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+ final IHandlerService handlerService= serviceLocator.getService(IHandlerService.class);
+
+ final IHandler2 refreshHandler= new AbstractHandler() {
+ @Override
+ public Object execute(final ExecutionEvent event) throws ExecutionException {
+ RGraphicPage.this.control.redrawGraphic();
+ return null;
+ }
+ };
+ handlerService.activateHandler(IWorkbenchCommandConstants.FILE_REFRESH, refreshHandler);
+
+ final IToolBarManager toolBar= actionBars.getToolBarManager();
+ toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(RGraphicCompositeActionSet.CONTEXT_MENU_GROUP_ID));
+ toolBar.insertBefore(SharedUIResources.ADDITIONS_MENU_ID, new Separator(RGraphicCompositeActionSet.SIZE_MENU_GROUP_ID));
+
+ this.actions= createActionSet();
+ this.actions.setGraphic(this.graphic);
+ this.actions.initActions(serviceLocator);
+ this.actions.contributeToActionsBars(serviceLocator, actionBars);
+
+ // Can find wrong item from other view
+// locationStatusItem= (StatusLineContributionItem) actionBars.getStatusLineManager().find(RGraphicCompositeActionSet.POSITION_STATUSLINE_ITEM_ID);
+ if (this.locationStatusItem != null) {
+ this.mouseLocationListener= new LocationListener() {
+
+ final DecimalFormat format= new DecimalFormat("0.0####", new DecimalFormatSymbols(Locale.US)); //$NON-NLS-1$
+
+ @Override
+ public void loading() {
+ if (RGraphicPage.this.locationStatusItem != null) {
+ RGraphicPage.this.locationStatusItem.setText("..."); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public void located(final double x, final double y) {
+ if (RGraphicPage.this.locationStatusItem != null && UIAccess.isOkToUse(RGraphicPage.this.control)) {
+ if (Double.isNaN(x) || Double.isInfinite(x)
+ || Double.isNaN(y) || Double.isInfinite(y) ) {
+ RGraphicPage.this.locationStatusText= "NA"; //$NON-NLS-1$
+ }
+ else {
+ final StringBuilder sb= new StringBuilder(32);
+ sb.append('(');
+ sb.append(this.format.format(x));
+ sb.append(", "); //$NON-NLS-1$
+ sb.append(this.format.format(y));
+ sb.append(')');
+ RGraphicPage.this.locationStatusText= sb.toString();
+ }
+ RGraphicPage.this.locationStatusItem.setText(RGraphicPage.this.locationStatusText);
+ }
+ }
+ };
+ this.actions.addMouseClickLocationListener(this.mouseLocationListener);
+ }
+ }
+
+ protected RGraphicCompositeActionSet createActionSet() {
+ return new RGraphicCompositeActionSet(this.control);
+ }
+
+ @Override
+ public void statusChanged(final IStatus status) {
+ final String message;
+ if (status.getSeverity() > 0) {
+ message= status.getMessage();
+ }
+ else {
+ message= null;
+ }
+ getSite().getActionBars().getStatusLineManager().setMessage(message);
+ }
+
+ @Override
+ public Control getControl() {
+ return this.control;
+ }
+
+ protected RGraphicComposite getGraphicComposite() {
+ return this.control;
+ }
+
+ @Override
+ public void setFocus() {
+ this.control.setFocus();
+ }
+
+ @Override
+ public void dispose() {
+ if (this.actions != null) {
+ this.actions.dispose();
+ this.actions= null;
+ }
+ if (this.graphic != null) {
+ this.graphic.removeMessageListener(this);
+ }
+ super.dispose();
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphics.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphics.java
new file mode 100644
index 0000000..29b979c
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphics.java
@@ -0,0 +1,59 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+
+public class RGraphics {
+
+
+ public static final String BUNDLE_ID= "org.eclipse.statet.rj.eclient.graphics"; //$NON-NLS-1$
+
+
+ public static final String PREF_DISPLAY_QUALIFIER= BUNDLE_ID + "/display"; //$NON-NLS-1$
+
+ /**
+ * Preference key: custom dpi setting (string "horizontal,vertical"), none/empty for default
+ *
+ * @since 1.0
+ */
+ public static final String PREF_DISPLAY_CUSTOM_DPI_KEY= "dpi.xy"; //$NON-NLS-1$
+
+
+ public static final String FONTS_PREF_QUALIFIER= BUNDLE_ID + "/fonts"; //$NON-NLS-1$
+ public static final String PREF_FONTS_SERIF_FONTNAME_KEY= "serif.name"; //$NON-NLS-1$
+ public static final String PREF_FONTS_SANS_FONTNAME_KEY= "sans.name"; //$NON-NLS-1$
+ public static final String PREF_FONTS_MONO_FONTNAME_KEY= "mono.name"; //$NON-NLS-1$
+
+ /**
+ * Preference key: if (boolean) a special symbol font should be used
+ *
+ * @since 1.0
+ */
+ public static final String PREF_FONTS_SYMBOL_USE_KEY= "symbol.use"; //$NON-NLS-1$
+ /**
+ * Preference key: name (string) of the symbol font (if special symbol font is enabled)
+ *
+ * @since 1.0
+ */
+ public static final String PREF_FONTS_SYMBOL_FONTNAME_KEY= "symbol.name"; //$NON-NLS-1$
+ /**
+ * Preference key: encoding (known key) of the symbol font (if special symbol font is enabled)
+ *
+ * @since 1.0
+ */
+ public static final String PREF_FONTS_SYMBOL_ENCODING_KEY= "symbol.enc"; //$NON-NLS-1$
+
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicsPreferencePage.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicsPreferencePage.java
new file mode 100644
index 0000000..7829a05
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/RGraphicsPreferencePage.java
@@ -0,0 +1,603 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.osgi.service.prefs.BackingStoreException;
+
+import org.eclipse.core.databinding.AggregateValidationStatus;
+import org.eclipse.core.databinding.DataBindingContext;
+import org.eclipse.core.databinding.UpdateValueStrategy;
+import org.eclipse.core.databinding.observable.Realm;
+import org.eclipse.core.databinding.observable.value.IValueChangeListener;
+import org.eclipse.core.databinding.observable.value.ValueChangeEvent;
+import org.eclipse.core.databinding.observable.value.WritableValue;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.IScopeContext;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.eclipse.jface.databinding.swt.SWTObservables;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.ComboViewer;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTError;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FontDialog;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.ecommons.databinding.DecimalValidator;
+import org.eclipse.statet.ecommons.ui.components.StatusInfo;
+import org.eclipse.statet.ecommons.ui.dialogs.DialogUtils;
+import org.eclipse.statet.ecommons.ui.util.LayoutUtil;
+
+
+/**
+ * Preference page with options to configure R graphic options:
+ * <ul>
+ * <li>Default font families ('serif', 'sans', 'mono')</li>
+ * </ul>
+ *
+ * The page is not registered by this plug-in.
+ */
+public class RGraphicsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
+
+
+ public static double[] parseDPI(final String prefValue) {
+ if (prefValue != null) {
+ final String[] strings= prefValue.split(",");
+ if (strings.length == 2) {
+ try {
+ return new double[] {
+ Double.parseDouble(strings[0]),
+ Double.parseDouble(strings[1]),
+ };
+ }
+ catch (final Exception e) {}
+ }
+ }
+ return null;
+ }
+
+
+ private static class FontPref {
+
+ final String prefKey;
+
+ String defaultName;
+ String currentName;
+
+ Font currentFont;
+
+ Label valueLabel;
+
+
+ public FontPref(final String key) {
+ this.prefKey= key;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return this.prefKey.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (this == obj
+ || (obj instanceof FontPref
+ && this.prefKey.equals(((FontPref) obj).prefKey) ));
+ }
+
+ }
+
+ private static class Encoding {
+
+ final String label;
+ final String prefValue;
+
+
+ public Encoding(final String label, final String prefValue) {
+ this.label= label;
+ this.prefValue= prefValue;
+ }
+
+
+ @Override
+ public int hashCode() {
+ return this.prefValue.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return (this == obj
+ || (obj instanceof Encoding
+ && this.prefValue.equals(((Encoding) obj).prefValue) ));
+ }
+
+ @Override
+ public String toString() {
+ return this.label.toString();
+ };
+
+ }
+
+ private static final Encoding[] SYMBOL_ENCODINGS= new Encoding[] {
+ new Encoding("Unicode", "Unicode"),
+ new Encoding("Adobe Symbol", "AdobeSymbol"),
+ };
+
+ private static final Encoding SYMBOL_ENCODING_DEFAULT= SYMBOL_ENCODINGS[1];
+
+
+ private DataBindingContext dbc;
+
+ private FontPref serifPref;
+ private FontPref sansPref;
+ private FontPref monoPref;
+ private FontPref symbolFontPref;
+ private FontPref[] fontPrefs;
+ private Button symbolUseControl;
+ private ComboViewer symbolEncodingControl;
+ private Control[] symbolChildControls;
+
+ private final int size= 10;
+
+ private Button customDpiControl;
+ private Composite customDpiComposite;
+ private Text customHDpiControl;
+ private Text customVDpiControl;
+
+ private boolean customEnabled;
+ private WritableValue customHDpiVisibleValue;
+ private WritableValue customVDpiVisibleValue;
+ private double customHDpiUserValue;
+ private double customVDpiUserValue;
+
+
+ /**
+ * Created via extension point
+ */
+ public RGraphicsPreferencePage() {
+ }
+
+
+ @Override
+ public void init(final IWorkbench workbench) {
+ this.serifPref= new FontPref(RGraphics.PREF_FONTS_SERIF_FONTNAME_KEY);
+ this.sansPref= new FontPref(RGraphics.PREF_FONTS_SANS_FONTNAME_KEY);
+ this.monoPref= new FontPref(RGraphics.PREF_FONTS_MONO_FONTNAME_KEY);
+ this.symbolFontPref= new FontPref(RGraphics.PREF_FONTS_SYMBOL_FONTNAME_KEY);
+ this.fontPrefs= new FontPref[] { this.serifPref, this.sansPref, this.monoPref, this.symbolFontPref };
+
+ final IEclipsePreferences node= DefaultScope.INSTANCE.getNode(RGraphics.FONTS_PREF_QUALIFIER);
+ for (final FontPref pref : this.fontPrefs) {
+ pref.defaultName= (node != null) ? node.get(pref.prefKey, "") : "";
+ }
+ }
+
+ @Override
+ protected Control createContents(final Composite parent) {
+ final Composite pageComposite= new Composite(parent, SWT.NONE);
+ pageComposite.setLayout(LayoutUtil.applyCompositeDefaults(new GridLayout(), 1));
+
+ final Group displayGroup= createDisplayGroup(pageComposite);
+ displayGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+
+ final Group fontGroup= createFontGroup(pageComposite);
+ fontGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+
+ initBindings();
+ loadDisplayOptions();
+ loadFontOptions();
+
+ applyDialogFont(pageComposite);
+
+ return pageComposite;
+ }
+
+ protected Group createDisplayGroup(final Composite parent) {
+ final Group group= new Group(parent, SWT.NONE);
+ group.setText("Display:");
+ group.setLayout(LayoutUtil.applyGroupDefaults(new GridLayout(), 2));
+
+ this.customDpiControl= new Button(group, SWT.CHECK);
+ this.customDpiControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+ this.customDpiControl.setText("Use custom DPI (instead of system setting):");
+
+ this.customDpiComposite= new Composite(group, SWT.NONE);
+
+ { final GridData gd= new GridData(SWT.FILL, SWT.FILL, true, false);
+ gd.horizontalIndent= LayoutUtil.defaultIndent();
+ this.customDpiComposite.setLayoutData(gd);
+ this.customDpiComposite.setLayout(LayoutUtil.applyCompositeDefaults(new GridLayout(), 2));
+ }
+
+ { final Label label= new Label(this.customDpiComposite, SWT.LEFT);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ label.setText("&Horizontal (x):");
+ }
+ { final Text text= new Text(this.customDpiComposite, SWT.BORDER | SWT.RIGHT);
+ final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ gd.widthHint= LayoutUtil.hintWidth(text, 8);
+ text.setLayoutData(gd);
+ this.customHDpiControl= text;
+ }
+ { final Label label= new Label(this.customDpiComposite, SWT.LEFT);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ label.setText("&Vertical (y):");
+ }
+ { final Text text= new Text(this.customDpiComposite, SWT.BORDER | SWT.RIGHT);
+ final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ gd.widthHint= LayoutUtil.hintWidth(text, 8);
+ text.setLayoutData(gd);
+ this.customVDpiControl= text;
+ }
+
+ this.customDpiControl.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ updateDisplayGroup();
+ }
+ });
+
+ return group;
+ }
+
+ private void updateDisplayGroup() {
+ this.customEnabled= this.customDpiControl.getSelection();
+ DialogUtils.setEnabled(this.customDpiComposite, null, this.customEnabled);
+
+ final double hvalue;
+ final double vvalue;
+ if (!this.customEnabled || this.customHDpiUserValue <= 0 || this.customVDpiUserValue <= 0) {
+ final Point dpi= Display.getDefault().getDPI();
+ hvalue= dpi.x;
+ vvalue= dpi.y;
+ if (this.customEnabled) {
+ this.customHDpiUserValue= hvalue;
+ this.customVDpiUserValue= vvalue;
+ }
+ }
+ else {
+ hvalue= this.customHDpiUserValue;
+ vvalue= this.customVDpiUserValue;
+ }
+ this.customHDpiVisibleValue.setValue(hvalue);
+ this.customVDpiVisibleValue.setValue(vvalue);
+ }
+
+ protected Group createFontGroup(final Composite parent) {
+ final Group group= new Group(parent, SWT.NONE);
+ group.setText("Fonts:");
+ group.setLayout(LayoutUtil.applyGroupDefaults(new GridLayout(), 3));
+
+ addFont(group, this.serifPref, "Default &Serif Font ('serif'):");
+ addFont(group, this.sansPref, "Default S&ansserif Font ('sans'):");
+ addFont(group, this.monoPref, "Default &Monospace Font ('mono'):");
+
+ LayoutUtil.addSmallFiller(group, false);
+
+ this.symbolUseControl= new Button(group, SWT.CHECK);
+ this.symbolUseControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 3, 1));
+ this.symbolUseControl.setText("Use special S&ymbol Font");
+ final List<Control> symbolControls= new ArrayList<>();
+ addFont(group, this.symbolFontPref, "Symbol &Font:",
+ LayoutUtil.defaultIndent(), symbolControls );
+ { final Label label= new Label(group, SWT.NONE);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, false, false);
+ gd.horizontalIndent= LayoutUtil.defaultIndent();
+ label.setLayoutData(gd);
+ label.setText("Encoding:");
+ symbolControls.add(label);
+ }
+ { this.symbolEncodingControl= new ComboViewer(group, SWT.DROP_DOWN | SWT.READ_ONLY);
+ final GridData gd= new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1);
+ gd.widthHint= LayoutUtil.hintWidth(this.symbolEncodingControl.getCombo(), 15);
+ this.symbolEncodingControl.getControl().setLayoutData(gd);
+ this.symbolEncodingControl.setContentProvider(new ArrayContentProvider());
+ this.symbolEncodingControl.setInput(SYMBOL_ENCODINGS);
+ symbolControls.add(this.symbolEncodingControl.getControl());
+ }
+ this.symbolChildControls= symbolControls.toArray(new Control[symbolControls.size()]);
+ this.symbolUseControl.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ updateSymbolControls();
+ }
+ });
+
+ return group;
+ }
+
+ private void addFont(final Group group, final FontPref pref, final String text) {
+ addFont(group, pref, text, 0, null);
+ }
+
+ private void addFont(final Group group, final FontPref pref, final String text,
+ final int indent, final List<Control> controls) {
+ final Label label= new Label(group, SWT.NONE);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, false, false);
+ gd.horizontalIndent= indent;
+ label.setLayoutData(gd);
+ label.setText(text);
+
+ pref.valueLabel= new Label(group, SWT.BORDER);
+ pref.valueLabel.setBackground(label.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ pref.valueLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ final Button button= new Button(group, SWT.PUSH);
+ button.setText("Edit...");
+ button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ button.addSelectionListener(new SelectionListener() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final FontDialog dialog= new FontDialog(button.getShell(), SWT.NONE);
+ dialog.setFontList((pref.currentFont != null) ? pref.currentFont.getFontData() : null);
+ final FontData result= dialog.open();
+ if (result != null) {
+ set(pref, result.getName());
+ }
+ }
+ @Override
+ public void widgetDefaultSelected(final SelectionEvent e) {
+ }
+ });
+
+ if (controls != null) {
+ controls.add(label);
+ controls.add(pref.valueLabel);
+ controls.add(button);
+ }
+ }
+
+ protected void initBindings() {
+ final Realm realm= Realm.getDefault();
+ this.dbc= new DataBindingContext(realm);
+ addBindings(this.dbc, realm);
+
+ final AggregateValidationStatus validationStatus= new AggregateValidationStatus(this.dbc, AggregateValidationStatus.MAX_SEVERITY);
+ validationStatus.addValueChangeListener(new IValueChangeListener() {
+ @Override
+ public void handleValueChange(final ValueChangeEvent event) {
+ final IStatus currentStatus= (IStatus) event.diff.getNewValue();
+ updateStatus(currentStatus);
+ }
+ });
+ }
+
+ protected void addBindings(final DataBindingContext dbc, final Realm realm) {
+ this.customHDpiVisibleValue= new WritableValue(realm, 96.0, Double.class);
+ this.customVDpiVisibleValue= new WritableValue(realm, 96.0, Double.class);
+
+ dbc.bindValue(SWTObservables.observeText(this.customHDpiControl, SWT.Modify),
+ this.customHDpiVisibleValue,
+ new UpdateValueStrategy().setAfterGetValidator(new DecimalValidator(10.0, 10000.0,
+ "The value for Horizontal (x) DPI is invalid (10-10000)." )), null);
+ dbc.bindValue(SWTObservables.observeText(this.customVDpiControl, SWT.Modify),
+ this.customVDpiVisibleValue,
+ new UpdateValueStrategy().setAfterGetValidator(new DecimalValidator(10.0, 10000.0,
+ "The value for Vertical (x) DPI is invalid (10-10000)." )), null);
+
+ this.customHDpiVisibleValue.addValueChangeListener(new IValueChangeListener() {
+ @Override
+ public void handleValueChange(final ValueChangeEvent event) {
+ if (RGraphicsPreferencePage.this.customEnabled) {
+ RGraphicsPreferencePage.this.customHDpiUserValue= (Double) RGraphicsPreferencePage.this.customHDpiVisibleValue.getValue();
+ }
+ }
+ });
+ this.customVDpiVisibleValue.addValueChangeListener(new IValueChangeListener() {
+ @Override
+ public void handleValueChange(final ValueChangeEvent event) {
+ if (RGraphicsPreferencePage.this.customEnabled) {
+ RGraphicsPreferencePage.this.customVDpiUserValue= (Double) RGraphicsPreferencePage.this.customVDpiVisibleValue.getValue();
+ }
+ }
+ });
+ }
+
+ protected void updateStatus(final IStatus status) {
+ setValid(!status.matches(IStatus.ERROR));
+ StatusInfo.applyToStatusLine(this, status);
+ }
+
+ protected void setCustomDpi(final String prefValue) {
+ final double[] dpi= parseDPI(prefValue);
+ if (dpi != null) {
+ this.customHDpiUserValue= dpi[0];
+ this.customVDpiUserValue= dpi[1];
+ this.customDpiControl.setSelection(true);
+ }
+ else {
+ this.customDpiControl.setSelection(false);
+ }
+ updateDisplayGroup();
+ }
+
+ protected void updateSymbolControls() {
+ DialogUtils.setEnabled(this.symbolChildControls, null, this.symbolUseControl.getSelection());
+ }
+
+ protected void set(final FontPref pref, final String value) {
+ if (value.equals(pref.currentName)) {
+ return;
+ }
+ pref.valueLabel.setText("");
+ Font font;
+ try {
+ font= new Font(pref.valueLabel.getDisplay(), value, this.size, SWT.NONE);
+ if (pref != this.symbolFontPref) {
+ pref.valueLabel.setFont(font);
+ }
+ pref.valueLabel.setText(value);
+ }
+ catch (final SWTError e) {
+ font= JFaceResources.getDialogFont();
+ pref.valueLabel.setFont(font);
+ pref.valueLabel.setText(value + " (not available)");
+ }
+ if (pref.currentFont != null && !pref.currentFont.isDisposed()) {
+ pref.currentFont.dispose();
+ }
+ pref.currentName= value;
+ pref.currentFont= font;
+ }
+
+ @Override
+ protected void performDefaults() {
+ setCustomDpi(null);
+ this.symbolUseControl.setSelection(true);
+ this.symbolEncodingControl.setSelection(new StructuredSelection(SYMBOL_ENCODING_DEFAULT));
+ for (final FontPref pref : this.fontPrefs) {
+ set(pref, pref.defaultName);
+ }
+ updateSymbolControls();
+ super.performDefaults();
+ }
+
+ @Override
+ protected void performApply() {
+ saveDisplayOptions(true);
+ saveFontOptions(true);
+ }
+
+ @Override
+ public boolean performOk() {
+ saveDisplayOptions(false);
+ saveFontOptions(false);
+ return true;
+ }
+
+
+ protected IScopeContext getScope() {
+ return InstanceScope.INSTANCE;
+ }
+
+ protected void loadDisplayOptions() {
+ final IEclipsePreferences node= getScope().getNode(RGraphics.PREF_DISPLAY_QUALIFIER);
+ setCustomDpi(node.get(RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY, null));
+ }
+
+ protected void saveDisplayOptions(final boolean flush) {
+ final IEclipsePreferences node= getScope().getNode(RGraphics.PREF_DISPLAY_QUALIFIER);
+ if (this.customEnabled) {
+ node.put(RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY,
+ Double.toString(this.customHDpiUserValue) + "," + Double.toString(this.customVDpiUserValue));
+ }
+ else {
+ node.remove(RGraphics.PREF_DISPLAY_CUSTOM_DPI_KEY);
+ }
+ if (flush) {
+ try {
+ node.flush();
+ }
+ catch (final BackingStoreException e) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+ "An error occurred when storing R graphics display preferences.", e));
+ }
+ }
+ }
+
+ protected void loadFontOptions() {
+ if (this.fontPrefs != null) {
+ final IEclipsePreferences node= getScope().getNode(RGraphics.FONTS_PREF_QUALIFIER);
+ this.symbolUseControl.setSelection(node.getBoolean(RGraphics.PREF_FONTS_SYMBOL_USE_KEY, true));
+ final String s= node.get(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY, (String) null);
+ this.symbolEncodingControl.setSelection(new StructuredSelection((s != null) ?
+ new Encoding(null, s) : SYMBOL_ENCODING_DEFAULT ));
+ for (final FontPref pref : this.fontPrefs) {
+ final String value= node.get(pref.prefKey, ""); //$NON-NLS-1$
+ set(pref, (value.length() > 0) ? value : pref.defaultName);
+ }
+ updateSymbolControls();
+ }
+ }
+
+ protected void saveFontOptions(final boolean flush) {
+ if (this.fontPrefs != null) {
+ final IEclipsePreferences node= getScope().getNode(RGraphics.FONTS_PREF_QUALIFIER);
+ node.putBoolean(RGraphics.PREF_FONTS_SYMBOL_USE_KEY, this.symbolUseControl.getSelection());
+ final IStructuredSelection selection= (IStructuredSelection) this.symbolEncodingControl.getSelection();
+ if (selection.getFirstElement() instanceof Encoding
+ && !SYMBOL_ENCODING_DEFAULT.equals(selection.getFirstElement())) {
+ node.put(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY,
+ ((Encoding) selection.getFirstElement()).prefValue );
+ }
+ else {
+ node.remove(RGraphics.PREF_FONTS_SYMBOL_ENCODING_KEY);
+ }
+ for (final FontPref pref : this.fontPrefs) {
+ if (pref.currentName == null || pref.currentName.equals(pref.defaultName)) {
+ node.remove(pref.prefKey);
+ }
+ else {
+ node.put(pref.prefKey, pref.currentName);
+ }
+ }
+ updateSymbolControls();
+ if (flush) {
+ try {
+ node.flush();
+ }
+ catch (final BackingStoreException e) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, RGraphics.BUNDLE_ID, -1,
+ "An error occurred when storing R graphics font preferences.", e));
+ }
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ if (this.dbc != null) {
+ this.dbc.dispose();
+ this.dbc= null;
+ }
+ if (this.fontPrefs != null) {
+ for (final FontPref pref : this.fontPrefs) {
+ if (pref.currentFont != null && !pref.currentFont.isDisposed()) {
+ pref.currentFont.dispose();
+ pref.currentFont= null;
+ }
+ }
+ }
+ super.dispose();
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActions.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActions.java
new file mode 100644
index 0000000..6d90c44
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActions.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.collections.IntArrayMap;
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.server.client.AbstractRJComClient;
+import org.eclipse.statet.rj.server.client.AbstractRJComClientGraphicActions;
+
+
+public class ERClientGraphicActions extends AbstractRJComClientGraphicActions
+ implements ToolRClientGraphicActions {
+
+
+ private final Tool tool;
+
+ private final IntArrayMap<Boolean> resizeTasks= new IntArrayMap<>();
+ private final IntArrayMap<Boolean> closeTasks= new IntArrayMap<>();
+
+
+ public ERClientGraphicActions(final AbstractRJComClient rjs, final Tool tool) {
+ super(rjs);
+ this.tool= tool;
+ }
+
+
+ private class ResizeRunnable extends AbstractRToolRunnable implements SystemRunnable {
+
+ private final int devId;
+ private final Runnable beforeResize;
+
+ public ResizeRunnable(final int devId, final Runnable beforeResize) {
+ super("r/rj/gd/resize", "Resize R Graphic"); //$NON-NLS-1$
+ this.devId= devId;
+ this.beforeResize= beforeResize;
+ }
+
+ @Override
+ public boolean changed(final int event, final Tool process) {
+ switch (event) {
+ case MOVING_FROM:
+ case REMOVING_FROM:
+ return false;
+ case BEING_ABANDONED:
+ synchronized (ERClientGraphicActions.this.closeTasks) {
+ ERClientGraphicActions.this.resizeTasks.put(this.devId, Boolean.FALSE);
+ }
+ return true;
+ default:
+ return true;
+ }
+ }
+
+ @Override
+ public void run(final RToolService r,
+ final IProgressMonitor monitor) throws CoreException {
+ synchronized (ERClientGraphicActions.this.closeTasks) {
+ ERClientGraphicActions.this.resizeTasks.put(this.devId, Boolean.FALSE);
+ }
+ this.beforeResize.run();
+ doResizeGraphic(this.devId, monitor);
+ }
+
+ }
+
+ private class CloseRunnable extends AbstractRToolRunnable implements SystemRunnable {
+
+
+ private final int devId;
+
+ public CloseRunnable(final int devId) {
+ super("r/rj/gd/close", "Close R Graphic ("+(devId+1)+")"); //$NON-NLS-1$
+ this.devId= devId;
+ }
+
+ @Override
+ public boolean changed(final int event, final Tool tool) {
+ switch (event) {
+ case MOVING_FROM:
+ return false;
+ case REMOVING_FROM:
+ case BEING_ABANDONED:
+ case FINISHING_OK:
+ case FINISHING_ERROR:
+ case FINISHING_CANCEL:
+ synchronized (ERClientGraphicActions.this.closeTasks) {
+ ERClientGraphicActions.this.closeTasks.put(this.devId, Boolean.FALSE);
+ }
+ return true;
+ default:
+ return true;
+ }
+ }
+
+ @Override
+ public void run(final RToolService r,
+ final IProgressMonitor monitor) throws CoreException {
+ doCloseGraphic(this.devId, monitor);
+ }
+
+ }
+
+
+ @Override
+ public Tool getRHandle() {
+ return this.tool;
+ }
+
+ @Override
+ public String getRLabel() {
+ return this.tool.getLabel(Tool.DEFAULT_LABEL);
+ }
+
+ @Override
+ public IStatus resizeGraphic(final int devId, final Runnable beforeResize) {
+ synchronized (this.resizeTasks) {
+ if (this.resizeTasks.put(devId, Boolean.TRUE) == Boolean.TRUE) {
+ return Status.OK_STATUS;
+ }
+ }
+ return this.tool.getQueue().add(new ResizeRunnable(devId, beforeResize));
+ }
+
+ @Override
+ public IStatus closeGraphic(final int devId) {
+ synchronized (this.closeTasks) {
+ if (this.closeTasks.put(devId, Boolean.TRUE) == Boolean.TRUE) {
+ return Status.OK_STATUS;
+ }
+ }
+ return this.tool.getQueue().add(new CloseRunnable(devId));
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActionsFactory.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActionsFactory.java
new file mode 100644
index 0000000..812aa5a
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERClientGraphicActionsFactory.java
@@ -0,0 +1,34 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.server.client.AbstractRJComClient;
+import org.eclipse.statet.rj.server.client.AbstractRJComClientGraphicActions;
+
+
+public class ERClientGraphicActionsFactory implements AbstractRJComClientGraphicActions.Factory {
+
+
+ @Override
+ public AbstractRJComClientGraphicActions create(final AbstractRJComClient rjs, final Object rHandle) {
+ if (rHandle instanceof Tool) {
+ return new ERClientGraphicActions(rjs, (Tool) rHandle);
+ }
+ return null;
+ }
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERGraphicFactory.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERGraphicFactory.java
new file mode 100644
index 0000000..cf79821
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ERGraphicFactory.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.statet.internal.rj.eclient.graphics.EclipseRGraphicFactory;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphicsManager;
+
+
+/**
+ * Factory and manager for R graphics under Eclipse.
+ */
+public class ERGraphicFactory extends EclipseRGraphicFactory
+ implements ERGraphicsManager {
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ToolRClientGraphicActions.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ToolRClientGraphicActions.java
new file mode 100644
index 0000000..c5e5a52
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/comclient/ToolRClientGraphicActions.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.comclient;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.server.client.RClientGraphicActions;
+
+
+public interface ToolRClientGraphicActions extends RClientGraphicActions {
+
+
+ @Override
+ Tool getRHandle();
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/AbstractLocalLocator.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/AbstractLocalLocator.java
new file mode 100644
index 0000000..17da038
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/AbstractLocalLocator.java
@@ -0,0 +1,249 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.LocatorCallback;
+
+
+/**
+ * Basic implementation for a local locator for R graphics.
+ * <p>
+ * Requests the user to locate point and converts the graphic coordinates to user coordinates.
+ * It uses the tool service API (org.eclipse.statet.ecommons.ts.core) to schedule the R job.</p>
+ */
+public abstract class AbstractLocalLocator extends LocatorCallback implements SystemRunnable {
+
+ protected static final ImList<String> OK_CANCEL_STOP_TYPES= ImCollections.newList(
+ ERGraphic.LOCATOR_DONE, ERGraphic.LOCATOR_CANCEL );
+
+
+ private final ERGraphic graphic;
+ private final Tool tool;
+
+ private boolean started;
+ private boolean graphicLocatorStarted;
+ private boolean runnableScheduled;
+
+ private final List<double[]> toConvert= new ArrayList<>();
+
+ private final List<double[]> locatedGraphic= new ArrayList<>();
+ private final List<double[]> locatedUser= new ArrayList<>();
+
+ private volatile int counter;
+
+
+ public AbstractLocalLocator(final ERGraphic graphic) {
+ this.graphic= graphic;
+ this.tool= graphic.getRHandle();
+ }
+
+
+ @Override
+ public Collection<String> getStopTypes() {
+ return OK_CANCEL_STOP_TYPES;
+ }
+
+ @Override
+ public String getMessage() {
+ return super.getMessage() + " (" + this.counter + " selected)";
+ }
+
+ @Override
+ public int located(final double x, final double y) {
+ synchronized (this) {
+ this.counter++;
+ this.toConvert.add(new double[] { x, y });
+ if (!internalScheduleConversion()) {
+ internalStop(null);
+ return STOP;
+ }
+ }
+ return NEXT;
+ }
+
+ @Override
+ public void stopped(final String type) {
+ synchronized (this) {
+ this.graphicLocatorStarted= false;
+ if (type == ERGraphic.LOCATOR_DONE) {
+ if (this.toConvert.isEmpty()) {
+ internalStop(ERGraphic.LOCATOR_DONE);
+ return;
+ }
+ else if (internalScheduleConversion()) {
+ return;
+ }
+ // scheduling failed
+ }
+ internalStop(null);
+ return;
+ }
+ }
+
+ @Override
+ public String getTypeId() {
+ return "r/rjgd/locallocator"; //$NON-NLS-1$
+ }
+
+ @Override
+ public String getLabel() {
+ return "Resolve Graphic Points";
+ }
+
+ @Override
+ public boolean canRunIn(final Tool tool) {
+ return (tool == this.tool);
+ }
+
+ @Override
+ public boolean changed(final int event, final Tool tool) {
+ switch (event) {
+ case REMOVING_FROM:
+ return false;
+ case BEING_ABANDONED:
+ case FINISHING_CANCEL:
+ case FINISHING_ERROR:
+ synchronized (this) {
+ this.runnableScheduled= false;
+ if (!this.graphicLocatorStarted) {
+ internalStop(null);
+ break;
+ }
+ }
+ this.graphic.stopLocator(null);
+ break;
+ case FINISHING_OK:
+ synchronized (this) {
+ if (!this.graphicLocatorStarted && this.toConvert.isEmpty()) {
+ internalStop(ERGraphic.LOCATOR_DONE);
+ break;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void run(final ToolService service,
+ final IProgressMonitor monitor) throws CoreException {
+ double[] graphic= null;
+ double[] user= null;
+ while (true) {
+ synchronized (this) {
+ if (graphic != null) {
+ if (user != null) {
+ this.locatedGraphic.add(graphic);
+ this.locatedUser.add(user);
+ }
+ else {
+ // invalid point?
+ }
+ }
+ if (this.toConvert.isEmpty()) {
+ this.counter= this.locatedGraphic.size();
+ this.runnableScheduled= false;
+ return;
+ }
+ graphic= this.toConvert.remove(0);
+ user= null;
+ }
+ user= this.graphic.convertGraphic2User(graphic, monitor);
+ }
+ }
+
+ /**
+ * synchronized
+ */
+ protected boolean internalScheduleConversion() {
+ if (!this.runnableScheduled) {
+ if (this.tool.getQueue().addHot(this).isOK()) {
+ this.runnableScheduled= true;
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * synchronized
+ *
+ * @param type the stop type
+ */
+ protected void internalStop(final String type) {
+ assert (!this.graphicLocatorStarted);
+ if (this.runnableScheduled) {
+ this.tool.getQueue().removeHot(this);
+ this.runnableScheduled= false;
+ }
+ this.started= false;
+ if (type == ERGraphic.LOCATOR_DONE) {
+ finished(new ArrayList<>(this.locatedGraphic), new ArrayList<>(this.locatedUser));
+ }
+ else {
+ canceled();
+ }
+ }
+
+
+ public boolean start() {
+ synchronized (this) {
+ if (this.started) {
+ return false;
+ }
+ this.toConvert.clear();
+ this.locatedGraphic.clear();
+ this.locatedUser.clear();
+ this.started= this.graphicLocatorStarted= true;
+ this.counter= 0;
+ if (this.graphic.startLocalLocator(this).isOK()) {
+ return true;
+ }
+ else {
+ this.started= this.graphicLocatorStarted= false;
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Is called if the locator and conversion is finished.
+ *
+ * @param graphic the graphic coordinates
+ * @param user the user coordinates
+ */
+ protected abstract void finished(final List<double[]> graphic, final List<double[]> user);
+
+ /**
+ * Is called if the locator was canceled
+ */
+ protected abstract void canceled();
+
+}
diff --git a/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/CopyToDevRunnable.java b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/CopyToDevRunnable.java
new file mode 100644
index 0000000..419597a
--- /dev/null
+++ b/eclient/org.eclipse.statet.rj.eclient.graphics/src/org/eclipse/statet/rj/eclient/graphics/util/CopyToDevRunnable.java
@@ -0,0 +1,61 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.eclient.graphics.util;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import org.eclipse.statet.ecommons.ts.core.Tool;
+
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+
+
+public class CopyToDevRunnable extends AbstractRToolRunnable {
+
+
+ private final ERGraphic graphic;
+ private final String toDev;
+ private final String toDevFile;
+ private final String toDevArgs;
+
+
+ public CopyToDevRunnable(final ERGraphic graphic, final String toDev,
+ final String toDevFile, final String toDevArgs) {
+ super("r/rj/gd/copy", "Copy R Graphic ('" + toDev + "')"); //$NON-NLS-1$
+ this.graphic= graphic;
+ this.toDev= toDev;
+ this.toDevFile= toDevFile;
+ this.toDevArgs= toDevArgs;
+ }
+
+ @Override
+ public boolean changed(final int event, final Tool tool) {
+ switch (event) {
+ case MOVING_FROM:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ @Override
+ public void run(final RToolService r,
+ final IProgressMonitor monitor) throws CoreException {
+ this.graphic.copy(this.toDev, this.toDevFile, this.toDevArgs, monitor);
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.classpath b/examples/org.eclipse.statet.rj.servi.demo/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.gitignore b/examples/org.eclipse.statet.rj.servi.demo/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.project b/examples/org.eclipse.statet.rj.servi.demo/.project
new file mode 100644
index 0000000..e001a87
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.servi.demo</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.resources.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.runtime.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.core.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.ui.prefs b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/examples/org.eclipse.statet.rj.servi.demo/META-INF/MANIFEST.MF b/examples/org.eclipse.statet.rj.servi.demo/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..00e705a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi.demo
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi Demo
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.rj.data;bundle-version="1.1.0",
+ org.eclipse.statet.rj.servi;bundle-version="1.1.0",
+ org.eclipse.swt;bundle-version="3.4.0",
+ org.eclipse.statet.ecommons.runtime.core
+Import-Package: org.eclipse.core.runtime,
+ org.eclipse.statet.jcommons.lang;version="1.0.0",
+ org.eclipse.statet.rj.services,
+ org.eclipse.statet.rj.services.util
diff --git a/examples/org.eclipse.statet.rj.servi.demo/about.html b/examples/org.eclipse.statet.rj.servi.demo/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/examples/org.eclipse.statet.rj.servi.demo/build.properties b/examples/org.eclipse.statet.rj.servi.demo/build.properties
new file mode 100644
index 0000000..9f02c9f
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/build.properties
@@ -0,0 +1,8 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ .,\
+ about.html
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/DemoApp.java b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/DemoApp.java
new file mode 100644
index 0000000..96f5940
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/DemoApp.java
@@ -0,0 +1,724 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.demo;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.ShellAdapter;
+import org.eclipse.swt.events.ShellEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.program.Program;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.FileDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.util.Graphic;
+import org.eclipse.statet.rj.services.util.PngGraphic;
+import org.eclipse.statet.rj.services.util.RPkgInstallation;
+
+
+public class DemoApp {
+
+
+ public static void main(String[] args) {
+ Display display= new Display();
+ Shell shell= new Shell(display);
+ shell.setText("(RJ) - RServi Demo/Test");
+ shell.setLayout(new FillLayout());
+
+ new DemoApp(shell);
+
+ shell.pack();
+ shell.open();
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+ display.dispose();
+ }
+
+
+ private Text fInitRemoteText;
+ private Button fInitRemoteButton;
+ private Text fInitLocalText;
+ private Button fInitLocalButton;
+ private Button fCloseButton;
+ private Text fLogText;
+
+ private Text fEvalText;
+ private Button fEvalVoidButton;
+ private Button fEvalDataButton;
+ private Button fAssignDataButton;
+
+ private Text fRemoteFileText;
+ private Button fUploadButton;
+ private Button fDownloadButton;
+ private Button fOpenButton;
+
+ private Button fInstPkgButton;
+
+ private FunctionCall fFunctionBuilder;
+ private Text fFunctionNameText;
+ private Button fFunctionNewButton;
+ private Text fFunctionArgumentText;
+ private Button fFunctionAddDataButton;
+ private Text fFunctionAddExpressionText;
+ private Button fFunctionAddExpressionButton;
+ private Button fFunctionEvalData;
+
+ private Button fCombinedHistButton;
+
+ private RServi fRServi;
+
+ private RObject fData;
+ private File fFile;
+
+
+ public DemoApp(Composite parent) {
+ EAppEnvSWT eAppEnv= new EAppEnvSWT();
+ Control content= createContent(parent);
+
+ parent.getShell().addDisposeListener(eAppEnv);
+ parent.getShell().addShellListener(new ShellAdapter() {
+ @Override
+ public void shellClosed(ShellEvent e) {
+ if (fRServi != null) {
+ close();
+ }
+ }
+ });
+ checkedEnabled();
+ }
+
+
+ private Control createContent(Composite parent) {
+ SashForm form= new SashForm(parent, SWT.HORIZONTAL);
+
+ Composite composite= new Composite(form, SWT.NONE);
+ composite.setLayout(new GridLayout(2, false));
+
+ { Composite log= new Composite(form, SWT.NONE);
+ GridLayout layout= new GridLayout(1, false);
+ layout.marginRight+= layout.marginWidth;
+ layout.marginWidth= 0;
+ log.setLayout(layout);
+
+ fLogText= new Text(log, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
+ GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true, 1, 20);
+ gd.widthHint= 300;
+ gd.heightHint= fLogText.getLineHeight()*10;
+ fLogText.setLayoutData(gd);
+ }
+ { addLabel(composite, "Pool:");
+ fInitRemoteText= new Text(composite, SWT.SINGLE | SWT.BORDER);
+ fInitRemoteText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+
+ addDummy(composite);
+ fInitRemoteButton= new Button(composite, SWT.PUSH);
+ GridData gd= new GridData(SWT.FILL, SWT.FILL, true, false);
+ gd.widthHint= 300;
+ fInitRemoteButton.setLayoutData(gd);
+ fInitRemoteButton.setText("Start - Connect Remote");
+ fInitRemoteButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ initRemote();
+ }
+ });
+
+// addLabel(composite, "R_HOME:");
+// fInitLocalText= new Text(composite, SWT.SINGLE | SWT.BORDER);
+// fInitLocalText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+//
+// addDummy(composite);
+// fInitLocalButton= new Button(composite, SWT.PUSH);
+// fInitLocalButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+// fInitLocalButton.setText("Start - Local");
+// fInitLocalButton.addSelectionListener(new SelectionAdapter() {
+// @Override
+// public void widgetSelected(SelectionEvent e) {
+// initLocal();
+// }
+// });
+ addDummy(composite);
+ fCloseButton= new Button(composite, SWT.PUSH);
+ fCloseButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fCloseButton.setText("Close");
+ fCloseButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ close();
+ }
+ });
+ }
+
+ new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+ .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ { addLabel(composite, "Expression:");
+ fEvalText= new Text(composite, SWT.BORDER);
+ fEvalText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ addDummy(composite);
+ fEvalVoidButton= new Button(composite, SWT.PUSH);
+ fEvalVoidButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fEvalVoidButton.setText("Execute #evalVoid");
+ fEvalVoidButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ evalVoid();
+ }
+ });
+
+ addDummy(composite);
+ fEvalDataButton= new Button(composite, SWT.PUSH);
+ fEvalDataButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fEvalDataButton.setText("Execute #evalData");
+ fEvalDataButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ evalData();
+ }
+ });
+
+ addDummy(composite);
+ fAssignDataButton= new Button(composite, SWT.PUSH);
+ fAssignDataButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fAssignDataButton.setText("Execute #assignData");
+ fAssignDataButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ assignData();
+ }
+ });
+ }
+
+ new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+ .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ { addLabel(composite, "Remote file:");
+ fRemoteFileText= new Text(composite, SWT.BORDER);
+ fRemoteFileText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ addDummy(composite);
+ fUploadButton= new Button(composite, SWT.PUSH);
+ fUploadButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fUploadButton.setText("Upload File...");
+ fUploadButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ uploadFile();
+ }
+ });
+
+ fOpenButton= new Button(composite, SWT.PUSH);
+ fOpenButton.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, false, false));
+ fOpenButton.setText("Open File <-");
+ fOpenButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ openFile();
+ }
+ });
+ fDownloadButton= new Button(composite, SWT.PUSH);
+ fDownloadButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fDownloadButton.setText("Download File...");
+ fDownloadButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ downloadFile();
+ }
+ });
+
+ }
+
+ new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+ .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ { addLabel(composite, "Package:");
+ fInstPkgButton= new Button(composite, SWT.PUSH);
+ fInstPkgButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fInstPkgButton.setText("Install Package file...");
+ fInstPkgButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ instPkgFile();
+ }
+ });
+ }
+
+
+ new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+ .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ { addLabel(composite, "Function:");
+ fFunctionNameText= new Text(composite, SWT.BORDER);
+ fFunctionNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ addDummy(composite);
+ fFunctionNewButton= new Button(composite, SWT.PUSH);
+ fFunctionNewButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fFunctionNewButton.setText("New (Restart builder)");
+ fFunctionNewButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ try {
+ fFunctionBuilder= fRServi.createFunctionCall(fFunctionNameText.getText());
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ logFunction();
+ checkedEnabled();
+ }
+ });
+
+ addLabel(composite, "Argument:");
+ fFunctionArgumentText= new Text(composite, SWT.BORDER);
+ fFunctionArgumentText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ addLabel(composite, "Expression:");
+ fFunctionAddExpressionText= new Text(composite, SWT.BORDER);
+ fFunctionAddExpressionText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ addDummy(composite);
+ fFunctionAddDataButton= new Button(composite, SWT.PUSH);
+ fFunctionAddDataButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fFunctionAddDataButton.setText("Add data argument");
+ fFunctionAddDataButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String arg= fFunctionArgumentText.getText();
+ fFunctionBuilder.add(arg.length() > 0 ? arg : null, fData);
+ logFunction();
+ }
+ });
+
+ addDummy(composite);
+ fFunctionAddExpressionButton= new Button(composite, SWT.PUSH);
+ fFunctionAddExpressionButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fFunctionAddExpressionButton.setText("Add expression argument");
+ fFunctionAddExpressionButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String arg= fFunctionArgumentText.getText();
+ fFunctionBuilder.add(arg.length() > 0 ? arg : null, fFunctionAddExpressionText.getText());
+ logFunction();
+ }
+ });
+
+ addDummy(composite);
+ fFunctionEvalData= new Button(composite, SWT.PUSH);
+ fFunctionEvalData.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+ fFunctionEvalData.setText("Execute #evalData");
+ fFunctionEvalData.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ evalFunctionData();
+ }
+ });
+ }
+
+ new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL)
+ .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
+
+ { fCombinedHistButton= new Button(composite, SWT.PUSH);
+ fCombinedHistButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+ fCombinedHistButton.setText("Create and Show 'hist(x)'");
+ fCombinedHistButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ showHist();
+ }
+ });
+ }
+
+ form.setWeights(new int[] { 2, 3 });
+
+ fInitRemoteText.setText("rmi://localhost/rservi-pool");
+ String rHome= System.getenv("R_HOME");
+ if (rHome != null) {
+ fInitLocalText.setText(rHome);
+ }
+
+ return composite;
+ }
+
+ private Label addLabel(Composite composite, String text) {
+ final Label label= new Label(composite, SWT.NONE);
+ label.setText(text);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ return label;
+ }
+
+ private void addDummy(Composite composite) {
+ final Label label= new Label(composite, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ }
+
+ private void logOK() {
+ fLogText.append(" OK\n");
+ }
+
+ private void logCancelled() {
+ fLogText.append(" CANCELLED\n");
+ }
+
+ private void logFailed() {
+ fLogText.append(" FAILED\n");
+ }
+
+ private void logFunction() {
+ fLogText.append("Current Function:\n");
+ fLogText.append(fFunctionBuilder.toString());
+ fLogText.append("\n");
+ }
+
+ private void logError(Throwable t) {
+ StringWriter sw= new StringWriter();
+ PrintWriter pw= new PrintWriter(sw, true);
+ t.printStackTrace(pw);
+ pw.flush();
+ sw.flush();
+ fLogText.append(" FAILED\n");
+ fLogText.append(sw.toString());
+ fLogText.append("\n");
+ }
+
+ private void checkedEnabled() {
+ boolean ok= (fRServi != null);
+ fInitRemoteButton.setEnabled(!ok);
+ if (fInitLocalButton != null) {
+ fInitLocalButton.setEnabled(!ok);
+ }
+ fCloseButton.setEnabled(ok);
+
+ fEvalVoidButton.setEnabled(ok);
+ fEvalDataButton.setEnabled(ok);
+ fAssignDataButton.setEnabled(ok && fData != null);
+
+ fUploadButton.setEnabled(ok);
+ fDownloadButton.setEnabled(ok);
+ fOpenButton.setEnabled(fFile != null);
+
+ fInstPkgButton.setEnabled(ok);
+
+ fCombinedHistButton.setEnabled(ok);
+
+ fFunctionNewButton.setEnabled(ok);
+ ok= ok && (fFunctionBuilder != null);
+ fFunctionAddDataButton.setEnabled(ok && fData != null);
+ fFunctionAddExpressionButton.setEnabled(ok);
+ fFunctionEvalData.setEnabled(ok);
+ }
+
+ private void initRemote() {
+ fLogText.setText("");
+ fLogText.append("Requesting RServi instance...");
+ try {
+ fRServi= RServiUtil.getRServi(fInitRemoteText.getText(), "demo/test");
+ logOK();
+ }
+ catch (Exception e) {
+ fRServi= null;
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+// private void initLocal() {
+// fLogText.setText("");
+// fLogText.append("Requesting RServi instance...");
+// try {
+// TODO
+// logOK();
+// }
+// catch (Exception e) {
+// fRServi= null;
+// logError(e);
+// }
+// checkedEnabled();
+// }
+
+ private void close() {
+ fLogText.append("Closing RServi instance...");
+ try {
+ fFunctionBuilder= null;
+ fRServi.close();
+ fRServi= null;
+ logOK();
+ }
+ catch (Exception e) {
+ fRServi= null;
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+ private void evalVoid() {
+ fLogText.append("Executing #evalVoid:\n\t");
+ String command= fEvalText.getText();
+ fLogText.append(command);
+ try {
+ fRServi.evalVoid(command, null);
+ fLogText.append("\n----\n");
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+ private void evalData() {
+ fLogText.append("Executing #evalData:\n\t");
+ final String command= fEvalText.getText();
+ fLogText.append(command);
+ try {
+ RObject data= fRServi.evalData(command, null);
+ fLogText.append("\n");
+ fLogText.append(data.toString());
+ fLogText.append("\n----\n");
+ fData= data;
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+ private void evalFunctionData() {
+ fLogText.append("Executing FunctionCall#evalData:\n\t");
+ final String command= fEvalText.getText();
+ fLogText.append(command);
+ try {
+ RObject data= fFunctionBuilder.evalData(null);
+ fLogText.append("\n");
+ fLogText.append(data.toString());
+ fLogText.append("\n----\n");
+ fData= data;
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+ private void assignData() {
+ fLogText.append("Executing #assignData:\n\t");
+ final String command= fEvalText.getText();
+ fLogText.append(command);
+ try {
+ fRServi.assignData(command, fData, null);
+ logOK();
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+ private void uploadFile() {
+ fLogText.append("Uploading file...");
+ final FileDialog dialog= new FileDialog(fLogText.getShell(), SWT.OPEN);
+ final String local= dialog.open();
+ if (local == null) {
+ logCancelled();
+ return;
+ }
+
+ final String remote= fRemoteFileText.getText();
+ fLogText.append("\n\t");
+ fLogText.append("local: ");
+ fLogText.append(local);
+ fLogText.append(" -> ");
+ fLogText.append("remote: ");
+ fLogText.append(remote);
+ fLogText.append("\n");
+
+ FileInputStream in= null;
+ try {
+ File file= new File(local);
+ in= new FileInputStream(file);
+ fRServi.uploadFile(in, file.length(), remote, 0, null);
+ logOK();
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ finally {
+ if (in != null) {
+ try {
+ in.close();
+ }
+ catch (IOException e) {}
+ }
+ }
+ checkedEnabled();
+ }
+
+ private void downloadFile() {
+ fLogText.append("Downloading file...");
+ final FileDialog dialog= new FileDialog(fLogText.getShell(), SWT.SAVE);
+ final String local= dialog.open();
+ if (local == null) {
+ logCancelled();
+ return;
+ }
+
+ File file= new File(local);
+ if (file.exists()) {
+ MessageBox box= new MessageBox(fLogText.getShell(), SWT.YES | SWT.NO);
+ box.setText("Downloading File");
+ box.setMessage("Overwrite existing file '"+file.getName()+"'?");
+ if (box.open() != SWT.YES) {
+ logCancelled();
+ return;
+ }
+ }
+ final String remote= fRemoteFileText.getText();
+ fLogText.append("\n\t");
+ fLogText.append("local: ");
+ fLogText.append(local);
+ fLogText.append(" <- ");
+ fLogText.append("remote: ");
+ fLogText.append(remote);
+ fLogText.append("\n");
+ FileOutputStream out= null;
+ try {
+ out= new FileOutputStream(file);
+ fRServi.downloadFile(out, remote, 0, null);
+ logOK();
+ fFile= file;
+ }
+ catch (Exception e) {
+ fFile= null;
+ logError(e);
+ }
+ finally {
+ if (out != null) {
+ try {
+ out.close();
+ }
+ catch (IOException e) {}
+ }
+ }
+ checkedEnabled();
+ }
+
+ private void openFile() {
+ String local= fFile.getPath();
+ fLogText.append("Opening file...\n\t");
+ fLogText.append(local);
+ fLogText.append("\n");
+ if (Program.launch(local)) {
+ logOK();
+ }
+ else {
+ logFailed();
+ }
+ }
+
+ private void instPkgFile() {
+ fLogText.append("Install package file...");
+ final FileDialog dialog= new FileDialog(fLogText.getShell(), SWT.OPEN);
+ final String local= dialog.open();
+ if (local == null) {
+ logCancelled();
+ return;
+ }
+
+ try {
+ File file= new File(local);
+ RPkgInstallation inst= new RPkgInstallation(file);
+
+ fLogText.append("\n\t");
+ fLogText.append("local: ");
+ fLogText.append(local);
+ fLogText.append(" -> rpkg: ");
+ fLogText.append(inst.getPkg().toString());
+ fLogText.append("\n");
+
+ inst.install(fRServi, null);
+ logOK();
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+ private void showHist() {
+ fLogText.append("Create and Show 'hist(x)'...");
+
+ try {
+ final PngGraphic pngGraphic= new PngGraphic();
+ pngGraphic.setSize(400, 500, Graphic.UNIT_PX);
+
+ final FunctionCall hist= fRServi.createFunctionCall("hist");
+ hist.add("x");
+
+ final byte[] plot= pngGraphic.create(hist, fRServi, null);
+ final Shell shell= new Shell(fLogText.getShell(), SWT.DIALOG_TRIM | SWT.RESIZE);
+ shell.setSize(500, 600);
+ shell.setText("PNG Graphic");
+ shell.setLayout(new GridLayout());
+
+ final Image image= new Image(Display.getCurrent(), new ByteArrayInputStream(plot));
+ shell.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ image.dispose();
+ }
+ });
+ final Label label= new Label(shell, SWT.NONE);
+ label.setImage(image);
+ label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
+
+ shell.open();
+ logOK();
+ }
+ catch (Exception e) {
+ logError(e);
+ }
+ checkedEnabled();
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/EAppEnvSWT.java b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/EAppEnvSWT.java
new file mode 100644
index 0000000..453d4a8
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/demo/EAppEnvSWT.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.demo;
+
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+
+/** Replaces missing Eclipse environment */
+public class EAppEnvSWT implements ECommonsRuntime.AppEnvironment, DisposeListener {
+
+
+ private final CopyOnWriteArraySet<Disposable> stopListeners= new CopyOnWriteArraySet<>();
+
+
+ public EAppEnvSWT() {
+ ECommonsRuntime.init("org.eclipse.statet.rj.services.eruntime", this);
+ }
+
+
+ @Override
+ public void addStoppingListener(Disposable listener) {
+ stopListeners.add(listener);
+ }
+
+ @Override
+ public void removeStoppingListener(Disposable listener) {
+ stopListeners.add(listener);
+ }
+
+ @Override
+ public void log(IStatus status) {
+ System.out.println(status.toString());
+ }
+
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ try {
+ for (final Disposable listener : stopListeners) {
+ listener.dispose();
+ }
+ }
+ finally {
+ stopListeners.clear();
+ }
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/examples/CorrelationPlotter.java b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/examples/CorrelationPlotter.java
new file mode 100644
index 0000000..8416634
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.demo/src/org/eclipse/statet/rj/servi/examples/CorrelationPlotter.java
@@ -0,0 +1,290 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Tobias Verbeke - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.examples;
+
+import java.io.ByteArrayInputStream;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Scale;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.demo.EAppEnvSWT;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.util.Graphic;
+import org.eclipse.statet.rj.services.util.PngGraphic;
+
+
+public class CorrelationPlotter {
+
+
+ Display display= new Display();
+ Shell shell= new Shell(display);
+
+ Label nPointsLabel;
+ Text nPointsText;
+ Label correlationLabel;
+ Label correlationValueLabel;
+ Scale correlationScale;
+ Label pngLabel;
+ Label messageLabel;
+
+ RServi fRservi;
+
+ RObject muObj;
+ RObject nObj;
+ RObject rObj;
+ double rValue= 1001; // corresponds to zero correlation
+ int nValue= 100; // initial number of points
+
+
+ public CorrelationPlotter(){
+ EAppEnvSWT eAppEnvSWT= new EAppEnvSWT();
+ shell.addDisposeListener(eAppEnvSWT);
+
+ shell.setText("Correlation Plotter"); // set window title
+ GridLayout gridLayout= new GridLayout();
+ gridLayout.numColumns= 2;
+ shell.setLayout(gridLayout);
+
+ nPointsLabel= new Label(shell, SWT.NULL);
+ nPointsLabel.setText("Number of points: ");
+ nPointsLabel.setVisible(true);
+
+ nPointsText= new Text(shell, SWT.RIGHT | SWT.SINGLE | SWT.BORDER);
+ GridData gridDataNPointsText= new GridData(GridData.FILL_HORIZONTAL);
+ gridDataNPointsText.horizontalSpan= 1;
+ nPointsText.setLayoutData(gridDataNPointsText);
+ nPointsText.setSelection(nValue);
+ nPointsText.insert("" + nValue);
+ nPointsText.setVisible(true);
+
+ correlationLabel= new Label(shell, SWT.NULL);
+ correlationLabel.setText("Correlation value: ");
+ GridData gridDataCorrelationLabel= new GridData(GridData.FILL_HORIZONTAL);
+ gridDataCorrelationLabel.horizontalSpan= 1;
+ correlationLabel.setLayoutData(gridDataCorrelationLabel);
+ correlationLabel.setVisible(true);
+
+ correlationValueLabel= new Label(shell, SWT.NULL);
+ double labelValue= (double) ((int) ((rValue-1001) * 100.0))/100;
+ correlationValueLabel.setText("" + labelValue); // TODO remove hard-coded value
+ GridData gridDataCorrelationValueLabel= new GridData(GridData.FILL_HORIZONTAL);
+ gridDataCorrelationValueLabel.horizontalSpan= 1;
+ correlationValueLabel.setLayoutData(gridDataCorrelationValueLabel);
+ correlationValueLabel.setAlignment(SWT.RIGHT);
+ correlationValueLabel.setVisible(true);
+
+ correlationScale= new Scale(shell, SWT.HORIZONTAL);
+ GridData gridDataCorrelationScale= new GridData(GridData.FILL_HORIZONTAL);
+ gridDataCorrelationScale.horizontalSpan= 2;
+ correlationScale.setLayoutData(gridDataCorrelationScale);
+ correlationScale.setMinimum(0);
+ correlationScale.setMaximum(2001);
+ correlationScale.setPageIncrement(10);
+ correlationScale.setSelection((int) rValue); // default value
+ correlationScale.setVisible(true);
+
+ pngLabel= new Label(shell, SWT.IMAGE_PNG);
+ pngLabel.setSize(300, 300);
+ GridData gridDataPngLabel= new GridData(GridData.FILL_BOTH);
+ gridDataPngLabel.horizontalSpan= 2;
+ pngLabel.setLayoutData(gridDataPngLabel);
+ pngLabel.setToolTipText("Click to sample again");
+ pngLabel.setVisible(true);
+
+ messageLabel= new Label(shell, SWT.BORDER);
+ GridData gridDataMessageLabel= new GridData(GridData.FILL_HORIZONTAL);
+ gridDataMessageLabel.horizontalSpan= 2;
+ messageLabel.setLayoutData(gridDataMessageLabel);
+ messageLabel.setVisible(true);
+
+ ModifyListener nPointsListener= new ModifyListener() {
+ @Override
+ public void modifyText(ModifyEvent event) {
+ nPointsChanged();
+ }
+ };
+
+ SelectionListener correlationListener= new SelectionListener() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ correlationValueChanged();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ // nothing is done
+ return;
+ }
+ };
+
+ MouseListener clickListener= new MouseListener() {
+ @Override
+ public void mouseUp(MouseEvent e) {
+ return;
+ }
+ @Override
+ public void mouseDown(MouseEvent e) {
+ try {
+ makePlot();
+ } catch (Exception e2) {
+ e2.printStackTrace();
+ }
+ }
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ return;
+ }
+ };
+
+ nPointsText.addModifyListener(nPointsListener);
+ correlationScale.addSelectionListener(correlationListener);
+ pngLabel.addMouseListener(clickListener);
+
+ String URL= "rmi://127.0.0.1/rservi-pool";
+ try {
+ fRservi= RServiUtil.getRServi(URL, "CorrelationPlotter");
+ } catch (Exception e1) {
+ e1.printStackTrace();
+ }
+ try {
+ FunctionCall massCall= fRservi.createFunctionCall("library");
+ massCall.add("package", "MASS");
+ massCall.evalVoid(null);
+ fRservi.evalVoid("mu <- c(0,0)", null); // does not change
+ fRservi.evalVoid("r <- " + (rValue-1001)/1001, null); // set default value, here: 0
+ fRservi.evalVoid("n <- " + nValue, null); // set default value
+ makePlot(); // initial plot
+ } catch (Exception e){
+ e.printStackTrace();
+ }
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()){
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ try {
+ fRservi.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ display.dispose();
+ }
+
+ public void nPointsChanged(){
+ if (!nPointsText.isFocusControl()) {
+ return;
+ }
+
+ double nPointsValue;
+
+ try {
+ nPointsValue= Double.parseDouble(nPointsText.getText());
+ messageLabel.setText("Valid number of points: " + nPointsText.getText());
+ messageLabel.setForeground(display.getSystemColor(SWT.COLOR_BLACK));
+ try {
+ if (nPointsValue > 1){
+ fRservi.evalVoid("n <- " + nPointsValue, null);
+ makePlot();
+ } else {
+ messageLabel.setText("Invalid number of points: " + nPointsText.getText());
+ messageLabel.setForeground(display.getSystemColor(SWT.COLOR_RED));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ } catch (NumberFormatException nfe) {
+ messageLabel.setText("Invalid number of points: " + nPointsText.getText());
+ messageLabel.setForeground(display.getSystemColor(SWT.COLOR_RED));
+ }
+
+ }
+
+ public void correlationValueChanged(){
+ double rValue= (double) correlationScale.getSelection() - 1001; // TODO replace with maximum of scale
+ if (rValue >= 0) {
+ rValue= rValue/1000;
+ } else {
+ rValue= rValue/1001;
+ }
+ rValue= (double) ((int) (rValue * 100.0))/100;
+ correlationValueLabel.setText("" + rValue);
+ // System.out.println("Correlation: " + rValue);
+ try {
+ fRservi.evalVoid("r <- " + rValue, null);
+ makePlot();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void makePlot(){
+ try {
+ FunctionCall mvrnormCall= fRservi.createFunctionCall("mvrnorm");
+ mvrnormCall.add("n", "n");
+ mvrnormCall.add("mu", "mu");
+
+ fRservi.evalVoid("sigma <- matrix(rep(r, 4), ncol= 2)", null);
+ fRservi.evalVoid("diag(sigma) <- c(1,1)", null);
+ fRservi.evalVoid("xy <- mvrnorm(n= n, mu= mu, Sigma= sigma)", null);
+
+ // plot(x= xy[,1], y= xy[,2], ylab= "", xlab= "")
+
+ final PngGraphic pngGraphic= new PngGraphic();
+ pngGraphic.setSize(300, 300, Graphic.UNIT_PX);
+
+ final FunctionCall plotFun= fRservi.createFunctionCall("eqscplot");
+ plotFun.add("x", "xy[,1]");
+ plotFun.add("y", "xy[,2]");
+ plotFun.addChar("xlab", "");
+ plotFun.addChar("ylab", "");
+
+ final byte[] plot= pngGraphic.create(plotFun, fRservi, null);
+ final Image image= new Image(display, new ByteArrayInputStream(plot));
+ pngLabel.setImage(image);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public static void main(String[] args) {
+ new CorrelationPlotter();
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.classpath b/examples/org.eclipse.statet.rj.servi.rcpdemo/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.gitignore b/examples/org.eclipse.statet.rj.servi.rcpdemo/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.project b/examples/org.eclipse.statet.rj.servi.rcpdemo/.project
new file mode 100644
index 0000000..c2fe9e6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.servi.rcpdemo</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.resources.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.runtime.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.core.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.ui.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/META-INF/MANIFEST.MF b/examples/org.eclipse.statet.rj.servi.rcpdemo/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..13cfc64
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/META-INF/MANIFEST.MF
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi.rcpdemo;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi RCP Demo (1)
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.statet.internal.rj.servi.rcpdemo.Activator
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.statet.ecommons.rmi.core;bundle-version="1.5.0",
+ org.eclipse.statet.rj.data;bundle-version="2.1.0",
+ org.eclipse.statet.rj.server;bundle-version="2.1.0",
+ org.eclipse.statet.rj.client;bundle-version="2.1.0",
+ org.eclipse.statet.rj.servi;bundle-version="2.1.0",
+ org.eclipse.ui,
+ org.eclipse.statet.rj.eclient.graphics;bundle-version="2.1.0"
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/RServi RCP Demo.launch b/examples/org.eclipse.statet.rj.servi.rcpdemo/RServi RCP Demo.launch
new file mode 100644
index 0000000..da45f0a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/RServi RCP Demo.launch
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">
+<setAttribute key="additional_plugins"/>
+<booleanAttribute key="append.args" value="true"/>
+<stringAttribute key="application" value="org.eclipse.statet.rj.servi.rcpdemo.application"/>
+<booleanAttribute key="askclear" value="false"/>
+<booleanAttribute key="automaticAdd" value="false"/>
+<booleanAttribute key="automaticValidate" value="false"/>
+<stringAttribute key="bootstrap" value=""/>
+<stringAttribute key="checked" value="[NONE]"/>
+<booleanAttribute key="clearConfig" value="true"/>
+<booleanAttribute key="clearws" value="true"/>
+<booleanAttribute key="clearwslog" value="true"/>
+<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/RServi RCP Demo"/>
+<booleanAttribute key="default" value="false"/>
+<stringAttribute key="featureDefaultLocation" value="workspace"/>
+<stringAttribute key="featurePluginResolution" value="workspace"/>
+<booleanAttribute key="includeOptional" value="false"/>
+<stringAttribute key="location" value="${workspace_loc}/../runtime-org.eclipse.statet.rj.servi.rcpdemo.product"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m"/>
+<booleanAttribute key="pde.generated.config" value="false"/>
+<stringAttribute key="pde.version" value="3.3"/>
+<stringAttribute key="product" value="org.eclipse.statet.rj.servi.rcpdemo.product"/>
+<stringAttribute key="productFile" value="\org.eclipse.statet.rj.servi.rcpdemo\org.eclipse.statet.rj.servi.rcpdemo.product"/>
+<setAttribute key="selected_features">
+<setEntry value="org.eclipse.e4.rcp:default"/>
+<setEntry value="org.eclipse.emf.common:default"/>
+<setEntry value="org.eclipse.emf.ecore:default"/>
+<setEntry value="org.eclipse.rcp:default"/>
+</setAttribute>
+<booleanAttribute key="show_selected_only" value="false"/>
+<booleanAttribute key="tracing" value="false"/>
+<booleanAttribute key="useCustomFeatures" value="true"/>
+<booleanAttribute key="useDefaultConfig" value="true"/>
+<booleanAttribute key="useDefaultConfigArea" value="true"/>
+<booleanAttribute key="useProduct" value="true"/>
+<booleanAttribute key="usefeatures" value="false"/>
+</launchConfiguration>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/about.html b/examples/org.eclipse.statet.rj.servi.rcpdemo/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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 <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+</p>
+
+<p>
+ 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 <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/build.properties b/examples/org.eclipse.statet.rj.servi.rcpdemo/build.properties
new file mode 100644
index 0000000..8f6690d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/build.properties
@@ -0,0 +1,11 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ plugin.xml,\
+ .,\
+ icons/,\
+ plugin_customization.ini,\
+ splash.bmp
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_about.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_about.gif
new file mode 100644
index 0000000..20d9ad2
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_about.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.icns b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.icns
new file mode 100644
index 0000000..b77a6a6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.icns
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.ico b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.ico
new file mode 100644
index 0000000..d548f71
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.ico
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.xpm b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.xpm
new file mode 100644
index 0000000..d2918c1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_launcher.xpm
@@ -0,0 +1,307 @@
+/* XPM */
+static char * icon48_xpm[]= {
+"48 48 256 2",
+" c #4B4B3B3B9090",
+". c #0D0D0E0E5454",
+"X c #11110E0E5B5B",
+"o c #17170F0F6363",
+"O c #1D1D13136969",
+"+ c #212114146C6C",
+"@ c #252514147171",
+"# c #282811116C6C",
+"$ c #26260D0D6363",
+"% c #22220B0B5E5E",
+"& c #1C1C0B0B5A5A",
+"* c #1C1C0B0B5252",
+"= c #1B1B05055353",
+"- c #161606064D4D",
+"; c #161605054949",
+": c #111104044848",
+"> c #131304044545",
+", c #131305054242",
+"< c #141410105E5E",
+"1 c #2C2C15157373",
+"2 c #2B2B1B1B7575",
+"3 c #343416167272",
+"4 c #313113136E6E",
+"5 c #222209095757",
+"6 c #1B1B06064D4D",
+"7 c #15150B0B4242",
+"8 c #13130C0C5555",
+"9 c #2E2E1B1B7878",
+"0 c #33331F1F7C7C",
+"q c #343418187878",
+"w c #3B3B1C1C7575",
+"e c #2E2E10106767",
+"r c #1B1B07074747",
+"t c #18180B0B4646",
+"y c #151513136262",
+"u c #1A1A15156464",
+"i c #34341F1F7777",
+"p c #40401E1E8080",
+"a c #42421B1B7A7A",
+"s c #3B3B15157474",
+"d c #2B2B0B0B5B5B",
+"f c #222207075252",
+"g c #373727277A7A",
+"h c #474724248484",
+"j c #393915156E6E",
+"k c #373711116A6A",
+"l c #343413136363",
+"z c #232319196E6E",
+"x c #292919197070",
+"c c #3C3C2C2C8282",
+"v c #444431318585",
+"b c #494934348A8A",
+"n c #505026268A8A",
+"m c #3D3D1B1B6E6E",
+"M c #31310E0E5C5C",
+"N c #2B2B0D0D5353",
+"B c #222207074A4A",
+"V c #52523C3C9292",
+"C c #58583C3C9494",
+"Z c #5D5D44449797",
+"A c #5C5C2E2E9292",
+"S c #676733339595",
+"D c #424228287575",
+"F c #29290A0A4F4F",
+"G c #6C6C4A4A9E9E",
+"H c #72725454A7A7",
+"J c #8C8C6D6DB2B2",
+"K c #343424246E6E",
+"L c #3A3A23236A6A",
+"P c #3A3A1C1C6767",
+"I c #24240A0A4B4B",
+"U c #151518186161",
+"Y c #76766F6FA5A5",
+"T c #ADAD9191CCCC",
+"R c #98988989D3D3",
+"E c #45453B3B8686",
+"W c #3C3C35357979",
+"Q c #363631317575",
+"! c #32322D2D6B6B",
+"~ c #323229296363",
+"^ c #30301F1F6262",
+"/ c #323218185E5E",
+"( c #272707074B4B",
+") c #202028286C6C",
+"_ c #1E1E1D1D6868",
+"` c #9A9A8282BBBB",
+"' c #C8C8B3B3D3D3",
+"] c #B3B3AFAFE7E7",
+"[ c #84847272C6C6",
+"{ c #58585757A3A3",
+"} c #3F3F3C3C8A8A",
+"| c #3B3B3A3A8484",
+" . c #414139397D7D",
+".. c #3D3D39397A7A",
+"X. c #37372E2E6E6E",
+"o. c #2C2C21215A5A",
+"O. c #2E2E1B1B5B5B",
+"+. c #F5F5EFEFF5F5",
+"@. c #656566669A9A",
+"#. c #47474B4B8E8E",
+"$. c #3C3C44447B7B",
+"%. c #444442428080",
+"&. c #45453E3E8181",
+"*. c #40403C3C8181",
+"=. c #3D3D33337474",
+"-. c #3B3B30306E6E",
+";. c #38382D2D6969",
+":. c #303026265D5D",
+">. c #2C2C15155A5A",
+",. c #1F1F1C1C7070",
+"<. c #25251E1E7171",
+"1. c #59595C5C9191",
+"2. c #4D4D53538989",
+"3. c #4C4C49498484",
+"4. c #484845458585",
+"5. c #494941418585",
+"6. c #494940408181",
+"7. c #2F2F1C1C5353",
+"8. c #2B2B28287676",
+"9. c #323231317F7F",
+"0. c #545452528B8B",
+"q. c #51514E4E8989",
+"w. c #4E4E4B4B8C8C",
+"e. c #4C4C47478686",
+"r. c #46463D3D7E7E",
+"t. c #434336367A7A",
+"y. c #2B2B13135555",
+"u. c #47473D3D8D8D",
+"i. c #575757578E8E",
+"p. c #48483E3E7F7F",
+"a. c #46463A3A7D7D",
+"s. c #424235357575",
+"d. c #404034347171",
+"f. c #BFBFCBCBFAFA",
+"g. c #B8B8A8A8DDDD",
+"h. c #5E5E60609292",
+"j. c #565655558C8C",
+"k. c #4B4B44448282",
+"l. c #454539397B7B",
+"z. c #434338387878",
+"x. c #3F3F32326D6D",
+"c. c #3D3D30306969",
+"v. c #3A3A2E2E6363",
+"b. c #36362A2A5C5C",
+"n. c #343424245555",
+"m. c #30301E1E4D4D",
+"M. c #49493C3C8282",
+"N. c #5E5E4F4F8C8C",
+"B. c #56563B3B8B8B",
+"V. c #545407078585",
+"C. c #424234347272",
+"Z. c #9797A4A4F7F7",
+"A. c #444436367676",
+"S. c #7D7D7979D5D5",
+"D. c #464640408A8A",
+"F. c #44444B4B8282",
+"G. c #414107077777",
+"H. c #71716161C1C1",
+"J. c #303039397979",
+"K. c #8E8E8E8EE6E6",
+"L. c #404033338B8B",
+"P. c #4A4A45458C8C",
+"I. c #46463A3A8080",
+"U. c #363629295454",
+"Y. c #303022224848",
+"T. c #424237377575",
+"R. c #2E2E1D1D6363",
+"E. c #79798383EAEA",
+"W. c #74747B7BE4E4",
+"Q. c #6D6D7676D6D6",
+"!. c #6A6A7171CECE",
+"~. c #66666969C6C6",
+"^. c #62626565BCBC",
+"/. c #5F5F6060B5B5",
+"(. c #5B5B5B5BACAC",
+"). c #535353539898",
+"_. c #4F4F4F4FA4A4",
+"`. c #54544D4DA4A4",
+"'. c #323204046B6B",
+"]. c #303035357979",
+"[. c #313122224343",
+"{. c #5A5A5B5BB7B7",
+"}. c #484846468080",
+"|. c #454541417575",
+" X c #4B4B31318282",
+".X c #47473C3C8484",
+"XX c #3E3E35356E6E",
+"oX c #2F2F26264040",
+"OX c #2B2B23233A3A",
+"+X c #262619195C5C",
+"@X c #252515155A5A",
+"#X c #55555151B3B3",
+"$X c #3C3C2D2D5D5D",
+"%X c #39392F2F5656",
+"&X c #37372D2D5050",
+"*X c #25251F1F3030",
+"=X c #24241D1D4343",
+"-X c #202013135656",
+";X c #41413B3B6C6C",
+":X c #444442429696",
+">X c #212100005E5E",
+",X c #444436367272",
+"<X c #444436366F6F",
+"1X c #424236366868",
+"2X c #3F3F34346161",
+"3X c #3C3C32325A5A",
+"4X c #34342A2A4A4A",
+"5X c #21211B1B2121",
+"6X c #22221C1C6363",
+"7X c #2D2D01015E5E",
+"8X c #20201B1B2525",
+"9X c #49492F2F7B7B",
+"0X c #434334346C6C",
+"qX c #323229294545",
+"wX c #1C1C10104F4F",
+"eX c #222217176363",
+"rX c #37371E1E6B6B",
+"tX c #424232326E6E",
+"yX c #444433336969",
+"uX c #424233336565",
+"iX c #1E1E1A1A1E1E",
+"pX c #161601014C4C",
+"aX c #1C1C11115454",
+"sX c #252503035B5B",
+"dX c #414131316A6A",
+"fX c #22221F1F7878",
+"gX c #272724246767",
+"hX c #1D1D16165E5E",
+"jX c #131305055151",
+"kX c #40402F2F6464",
+"lX c #111107074E4E",
+"zX c #0C0C05054B4B",
+"xX c #22221E1E5757",
+"cX c #1A1A0D0D4D4D",
+"vX c #16160B0B4D4D",
+"bX c #060604044747",
+"nX c #040403034343",
+"mX c #3B3B27276565",
+"MX c #0E0E03034141",
+"NX c #111106064A4A",
+"BX c #0E0E04044646",
+"VX c #111105053B3B",
+"CX c #0D0D01013A3A",
+"ZX c #030305053F3F",
+"AX c #0F0F0F0F4C4C",
+"SX c #020207073B3B",
+"DX c #0D0D03034646",
+"FX c #0B0B02023F3F",
+"GX c #0D0D02023434",
+"HX c #0A0A0E0E4444",
+"JX c #161614145252",
+"KX c #0B0B04044646",
+"LX c #0A0A03034444",
+"PX c #1D1D21215757",
+"IX c #090910104040",
+"UX c #18181E1E5353",
+" ",
+" . . . . X X o o o o O + + @ @ @ @ @ @ @ # # # # # # $ $ % % & & & & *= - - - ; : > > , , , ",
+" . . X X < < o o O O + @ 1 2 2 1 1 1 1 1 1 1 1 3 4 # # $ $ $ % % % 5= = 6 6 - ; ; > > , , 7 ",
+" . 8 < < < o O O + @ @ 2 9 9 0 0 q q q q q q q w 3 4 4 e e $ $ $ $ % 5= = 6 6 6 ; ; > > r t ",
+" . X < y u O O + @ 1 2 i 0 0 p p p p p p p a a p a s 3 4 4 e e e e d 5 5 f f 6 6 6 ; ; r r t ",
+" X < y u O + + @ 2 9 0 g p p h h h h h h h p h h a a s s j k k j l d d 5 5 f f 6 6 r r r r r ",
+" X < y O z x x 9 0 g c v b n n n n n n n n n n n h a a s s j j m l M d d N f f B B B B r r r ",
+" < y u + z 2 0 c c b V C Z C C A A A A A S S S n h D w w m m m m k l M d d N f F F F B r r r ",
+" < y O z z 9 c b V Z G H H H G S G G J J H V v c g g K K K K L P l l l M M N N N N I B B r r ",
+" U u + z x i v C H Y J J J J H J T R H V E W W Q Q Q Q ! ! ! ~ ^ ^ / / M M M M M N ( B B r r ",
+" ) _ z x 9 g b Z Y ` ' ' ' T T ] [ { } | .........W W Q Q X.! ~ ~ o.O./ / / / N F ( B B B r ",
+" ) ) z x i c V G J ' +.+.+.+.] [ @.#.$.%.%.%.&.*. . .....W =.-.X.;.~ :.o.O.^ >.N F ( B B B B ",
+" ) ,.<.2 g v C H J ' +.+.+.+.T Y 1.2.3.4.4.4.5.6.&.&. . ...W =.=.-.;.~ :.o.7.>.N F F ( B I I ",
+" ) ,.<.8.9.b C H J T +.+.+.' J @.1.0.q.q.w.e.4.5.6.&.r. . .t.W =.=.-.;.~ :.o.7.y.N F ( ( I I ",
+" 8.8.8.9.| u.C G J T +.+.' ` Y @.1.i.0.q.q.e.e.5.6.p.r.a. .t.t.s.d.d.-.;.~ :.7.7.y.F F ( I I ",
+" 9.c c c v b A S H ' f.g.` Y @.h.1.i.j.0.q.q.e.k.6.p.r.a.l.t.z.s.s.d.x.c.v.b.n.m.7.N F F F I ",
+" <.g M.N.B.B.n V.J f.R J @.h.h.1.i.i.j.j.0.q.3.k.6.p.r.a.l.l.z.s.C.d.x.x.c.v.b.n.m.y.N F F F ",
+" + x i v B.Z Z G g.Z.[ @.2.i.i.j.j.j.j.j.0.q.3.k.6.p.p.a.l.l.A.s.C.C.d.x.c.v.b.n.m.7.y.N N y. ",
+" O # 3 w p n Z ` f.S.H D.F.q.0.0.0.0.j.0.q.q.3.k.6.p.r.a.a.l.A.s.s.C.d.x.x.c.v.b.n.m.y.y.y.y. ",
+" O # 4 s a G.V.T Z.H.V J.%.e.w.q.0.0.0.0.q.q.e.k.6.p.r.a.a.l.z.A.s.C.d.d.x.c.v.b.n.m.7.>.y.y. ",
+" O # 4 s w G.A f.K.H L...4.P.w.w.w.q.q.q.q.e.e.5.6.M.I.I.a.a.l.z.A.s.d.d.x.c.v.v.U.Y.7.O.>.y. ",
+" $ # 4 3 s G.G f.S.Z 9.*.D.P.P.w.w.w.w.w.e.e.5.5.M.M.I.I.a.a.l.z.T.s.d.d.x.x.c.v.U.Y.m.R.>.>. ",
+" E.E.W.W.W.W.E.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { )._.`._. ",
+" + # 3 w s '.` f.H.V ].*.D.P.P.P.P.P.P.P.5.5.5.M.M.M.I.I.a.l.z.z.T.T.s.d.d.x.c.v.U.Y.[.^ O.>. ",
+" ~.~.~.~.~.~.K.Z.S.~.{.^.^.^.^.^.^.^.^././././././.(.(.(.(.(.(.{ { { { { ).).).w.w.}.|.P.u.} ",
+" .I.6. X X XT f.H.b ].*.E D.D.D.D.5.5..X.XM.M.I.I.a.a.l.l.z.z.T.T.T.d.XXx.c.v.b.U.oXOXR.+X@X ",
+" E.E.E.W.W.W.K.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { ).).#X_._. ",
+" & % $ e '.= H f.H.b 8.W *.E E E .X.X.XI.I.I.I.a.a.l.l.z.z.T.T.T.C.XXXXc.v.$X%X&XY.*X=X2 @X-X ",
+" {.{.{.{.{.#X~.Z.W.~.{.{./././././././././.(.(.(.(.(.(.(.{ { { { { { ).).).w.w.3.}.;X%.:X} } ",
+" & & % $ e >XV.f.S.C K X.W t. . .l.l.t.t.t.t.A.A.A.,X,X,X,X,X<X;X1X1X2X3X%X&X4XoX*X5Xo.6X-X-X ",
+" & & % $ $ >X7X` Z.Z D ! =.=.s.t.t.t.A.A.s.A.,X,X,X,X<X<X<X<X;X1X2X2X3X%X&X4XoXOX8X5X<.@X-X-X ",
+" 8 & & $ e K 9XJ f.^. XK X.=.=.s.s.s.s.s.C.C.C.C.<X0X0X0X1X1X1X2X2X3X%X&X4XqXOX*X8X=X<.-X-XwX ",
+" 8 & eXK k.@.M. Xg.E.B.rX~ -.d.d.C.C.C.C.C.tX0X0X0XyXyX1X1XuX2X2X3X%X&X4XqXoXOX8XiX6XeX-X-XwX ",
+" 6XQ h.Y N.K e pXB.f./.9Xo.;.-.x.d.tXtXtXtXtX0X0XyXyXyXuXuX2X2X3X%X&X4XqXoXOX*XiX=X_ aX-XaXwX ",
+" Y Y .R.@X% sX= 7XT Z.V P :.;.c.x.x.x.tXdXdXdXyXyXuXuX2X2X3X3X%X&X4XqXoXOX*X8X*XfXaXaXaXwXwX ",
+" gXhX& * & 5 5 sXjXa ] S.9X/ ~ v.c.dXdXdXdXdXuXuXuXkX2X2X3X%X%X&X4XqXoXOX*X8XiX<.hXwXwXaXwXwX ",
+" 8 lXlXjX= * 5 5= zX9X] H.D 7.b.v.v.kXc.kXkXkXkXkX2X$X3X%X&X&X4XqXoXOX*X8XiXxXhXwXcXcXwXwXwX ",
+" zXzXlXlXjX== f f sXD Y ] ~.D 7.n.b.v.v.kXkXkXkX$X$X%X%X&X4XqXoXoXOX*X8X5XgXu cXvXvXcXcXwXwX ",
+" bXbXzXlXlX-= * @XX.h.e D T S.D n.m.b.$X$X$X$X$X%X%X&X&X4XqXoXOX*X8X8X*X<.hXvX; ; vXvXvXcXwX ",
+" nXbXzXzXlXlX- -XX.Y R.pXpXP J K.Z mXm.n.U.U.U.U.U.4X4XY.oXOX*X8X8X8X=X,.aXvX; > > > t t t cX ",
+" nXbXbXzXzXlXaXXXY +Xf= f= 7XtXR R mXn.Y.[.[.[.[.OX*X*X8X5X*X=X,.u vXvX; > > MXMX, 7 t t ",
+" nXnXnXbXzXvX-.Y +XcX6 6= == d L B.G H `.X.:.7.m.=X=X=X=X=X6X,.u cXvXNX: BX> MXVXCXVX7 7 7 ",
+" ZXZXnXbXAXgX@.+XvX; - - - - * @XR.>.sX>.R.i 0 x eXeXeXeXO hXaXcXvXNX: BXMXMXMXVXCXCXCXVX7 7 ",
+" SXZXZXAXgXN.aXNX: : NXNXNX- * +X+X* 6 6 6 * * * * * * * vXvX- NX: DXBXMXMXFXCXCXCXCXGXVXVX7 ",
+" SXSXHXgX0.JXKXLXKXKXDX: : NX* @X-X- - - - - - - - - - - NX: DXDXDXMXMXFXFXCXCXCXCXGXGXGXVXVX ",
+" SXHXPX3.JXnXnXnXnXbXLXKXKXNXaX-XvX: : NX: : : : : : : BXDXDXLXMXMXFXFXCXCXCXCXGXGXGXGXGXGXGX ",
+" IXUX$.AXZXZXZXZXnXnXnXLXLXNXJXvXBXDXBXBXBXBXDXDXDXDXLXDXLXLXFXFXFXFXCXCXCXCXGXGXGXGXGXGXGXGX ",
+" "};
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_16.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_16.gif
new file mode 100644
index 0000000..05626b1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_16.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_32.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_32.gif
new file mode 100644
index 0000000..b432f88
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/icons/alt_window_32.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/org.eclipse.statet.rj.servi.rcpdemo.product b/examples/org.eclipse.statet.rj.servi.rcpdemo/org.eclipse.statet.rj.servi.rcpdemo.product
new file mode 100644
index 0000000..edb4e62
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/org.eclipse.statet.rj.servi.rcpdemo.product
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="RServi RCP Demo" id="org.eclipse.statet.rj.servi.rcpdemo.product" application="org.eclipse.statet.rj.servi.rcpdemo.application" version="0.4.0.qualifier" useFeatures="false" includeLaunchers="true">
+
+ <configIni use="default">
+ </configIni>
+
+ <launcherArgs>
+ <vmArgs>-Xms40m -Xmx512m
+ </vmArgs>
+ <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
+ </vmArgsMac>
+ </launcherArgs>
+
+ <windowImages i16="icons/alt_window_16.gif" i32="icons/alt_window_32.gif"/>
+
+ <splash
+ location="org.eclipse.statet.rj.servi.rcpdemo"
+ startupProgressRect="20,190,415,15"
+ startupMessageRect="20,210,415,20"
+ startupForegroundColor="000000" />
+ <launcher>
+ <solaris/>
+ <win useIco="false">
+ <bmp/>
+ </win>
+ </launcher>
+
+ <vm>
+ </vm>
+
+ <plugins>
+ <plugin id="com.ibm.icu"/>
+ <plugin id="org.eclipse.statet.ecommons.rmi.core"/>
+ <plugin id="org.eclipse.statet.ecommons.coremisc"/>
+ <plugin id="org.eclipse.statet.ecommons.uimisc"/>
+ <plugin id="org.eclipse.statet.rj.data"/>
+ <plugin id="org.eclipse.statet.rj.client"/>
+ <plugin id="org.eclipse.statet.rj.services.core"/>
+ <plugin id="org.eclipse.statet.rj.eclient.core"/>
+ <plugin id="org.eclipse.statet.rj.eclient.graphics"/>
+ <plugin id="org.eclipse.statet.rj.server"/>
+ <plugin id="org.eclipse.statet.rj.servi"/>
+ <plugin id="org.eclipse.statet.rj.servi.rcpdemo"/>
+ <plugin id="javax.annotation"/>
+ <plugin id="javax.inject"/>
+ <plugin id="javax.xml"/>
+ <plugin id="org.apache.batik.css"/>
+ <plugin id="org.apache.batik.util"/>
+ <plugin id="org.apache.batik.util.gui"/>
+ <plugin id="org.apache.commons.jxpath"/>
+ <plugin id="org.eclipse.core.commands"/>
+ <plugin id="org.eclipse.core.contenttype"/>
+ <plugin id="org.eclipse.core.databinding"/>
+ <plugin id="org.eclipse.core.databinding.observable"/>
+ <plugin id="org.eclipse.core.databinding.property"/>
+ <plugin id="org.eclipse.core.expressions"/>
+ <plugin id="org.eclipse.core.jobs"/>
+ <plugin id="org.eclipse.core.runtime"/>
+ <plugin id="org.eclipse.core.runtime.compatibility.registry" fragment="true"/>
+ <plugin id="org.eclipse.e4.core.commands"/>
+ <plugin id="org.eclipse.e4.core.contexts"/>
+ <plugin id="org.eclipse.e4.core.di"/>
+ <plugin id="org.eclipse.e4.core.di.annotations"/>
+ <plugin id="org.eclipse.e4.core.di.extensions"/>
+ <plugin id="org.eclipse.e4.core.services"/>
+ <plugin id="org.eclipse.e4.emf.xpath"/>
+ <plugin id="org.eclipse.e4.ui.bindings"/>
+ <plugin id="org.eclipse.e4.ui.css.core"/>
+ <plugin id="org.eclipse.e4.ui.css.swt"/>
+ <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
+ <plugin id="org.eclipse.e4.ui.di"/>
+ <plugin id="org.eclipse.e4.ui.model.workbench"/>
+ <plugin id="org.eclipse.e4.ui.services"/>
+ <plugin id="org.eclipse.e4.ui.widgets"/>
+ <plugin id="org.eclipse.e4.ui.workbench"/>
+ <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench3"/>
+ <plugin id="org.eclipse.emf.common"/>
+ <plugin id="org.eclipse.emf.ecore"/>
+ <plugin id="org.eclipse.emf.ecore.change"/>
+ <plugin id="org.eclipse.emf.ecore.xmi"/>
+ <plugin id="org.eclipse.equinox.app"/>
+ <plugin id="org.eclipse.equinox.common"/>
+ <plugin id="org.eclipse.equinox.ds"/>
+ <plugin id="org.eclipse.equinox.event"/>
+ <plugin id="org.eclipse.equinox.preferences"/>
+ <plugin id="org.eclipse.equinox.registry"/>
+ <plugin id="org.eclipse.equinox.util"/>
+ <plugin id="org.eclipse.help"/>
+ <plugin id="org.eclipse.jface"/>
+ <plugin id="org.eclipse.jface.databinding"/>
+ <plugin id="org.eclipse.osgi"/>
+ <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
+ <plugin id="org.eclipse.osgi.services"/>
+ <plugin id="org.eclipse.swt"/>
+ <plugin id="org.eclipse.swt.cocoa.macosx" fragment="true"/>
+ <plugin id="org.eclipse.swt.cocoa.macosx.x86_64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.aix.ppc" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.aix.ppc64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.hpux.ia64_32" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.ppc64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.s390" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.s390x" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.x86" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.x86_64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.solaris.sparc" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.solaris.x86" fragment="true"/>
+ <plugin id="org.eclipse.swt.win32.win32.x86" fragment="true"/>
+ <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
+ <plugin id="org.eclipse.ui"/>
+ <plugin id="org.eclipse.ui.workbench"/>
+ <plugin id="org.w3c.css.sac"/>
+ <plugin id="org.w3c.dom.events"/>
+ <plugin id="org.w3c.dom.smil"/>
+ <plugin id="org.w3c.dom.svg"/>
+ </plugins>
+
+ <configurations>
+ <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" />
+ <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />
+ <plugin id="org.eclipse.equinox.ds" autoStart="true" startLevel="1" />
+ <plugin id="org.eclipse.osgi" autoStart="true" startLevel="-1" />
+ </configurations>
+
+</product>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin.xml b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin.xml
new file mode 100644
index 0000000..c002914
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+ <extension
+ id="org.eclipse.statet.rj.servi.rcpdemo.application"
+ point="org.eclipse.core.runtime.applications">
+ <application>
+ <run
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.Application">
+ </run>
+ </application>
+ </extension>
+ <extension
+ id="product"
+ point="org.eclipse.core.runtime.products">
+ <product
+ application="org.eclipse.statet.rj.servi.rcpdemo.application"
+ name="RServi RCP Demo">
+ <property
+ name="windowImages"
+ value="icons/alt_window_16.gif,icons/alt_window_32.gif">
+ </property>
+ <property
+ name="appName"
+ value="RServi RCP Demo">
+ </property>
+ <property
+ name="startupProgressRect"
+ value="20,190,415,15">
+ </property>
+ <property
+ name="startupForegroundColor"
+ value="000000">
+ </property>
+ <property
+ name="startupMessageRect"
+ value="20,210,415,20">
+ </property>
+ <property
+ name="preferenceCustomization"
+ value="plugin_customization.ini">
+ </property>
+ </product>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.perspectives">
+ <perspective
+ name="RCP Perspective"
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.Perspective"
+ id="org.eclipse.statet.rj.servi.rcpdemo.perspective">
+ </perspective>
+ </extension>
+ <extension
+ point="org.eclipse.ui.menus">
+ <menuContribution
+ locationURI="menu:org.eclipse.ui.main.menu">
+ <menu id="file"
+ label="&File">
+ </menu>
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:file">
+ <command
+ commandId="org.eclipse.ui.file.exit"
+ style="push">
+ </command>
+ </menuContribution>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.views">
+ <view
+ allowMultiple="false"
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.RServiConfigView"
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+ name="Config"
+ restorable="true">
+ </view>
+ <view
+ allowMultiple="true"
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.GraphDemoView"
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+ name="Graph"
+ restorable="true">
+ </view>
+ <view
+ id="org.eclipse.ui.views.ProgressView"
+ class="org.eclipse.ui.ExtensionFactory:progressView"
+ name="Progress">
+ </view>
+ </extension>
+ <extension
+ point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension
+ targetID="*">
+ <view
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+ closeable="false"
+ minimized="false"
+ relative="org.eclipse.ui.editorss"
+ relationship="left"
+ visible="true">
+ </view>
+ <view
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+ closeable="false"
+ minimized="false"
+ ratio="0.3f"
+ relative="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+ relationship="left"
+ visible="true">
+ </view>
+ <view
+ id="org.eclipse.ui.views.ProgressView"
+ closeable="true"
+ minimized="false"
+ ratio="0.75"
+ relative="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+ relationship="bottom"
+ visible="false">
+ </view>
+ </perspectiveExtension>
+ </extension>
+
+</plugin>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin_customization.ini b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin_customization.ini
new file mode 100644
index 0000000..61d5abf
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/plugin_customization.ini
@@ -0,0 +1 @@
+org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP= true
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/splash.bmp b/examples/org.eclipse.statet.rj.servi.rcpdemo/splash.bmp
new file mode 100644
index 0000000..fbcd619
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/splash.bmp
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
new file mode 100644
index 0000000..ef8a779
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
@@ -0,0 +1,85 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERGraphicFactory;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+
+ public static final String BUNDLE_ID= "org.eclipse.statet.rj.servi.rcpdemo";
+
+
+ private static Activator instance;
+
+ /**
+ * Returns the shared plug-in instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getInstance() {
+ return instance;
+ }
+
+
+ private RServiManager rserviManager;
+
+ private ERGraphicFactory graphicFactory;
+
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+
+ @Override
+ public void start(final BundleContext context) throws Exception {
+ super.start(context);
+ instance= this;
+ }
+
+ @Override
+ public void stop(final BundleContext context) throws Exception {
+ instance= null;
+ super.stop(context);
+ }
+
+
+ public synchronized RServiManager getRServiManager() {
+ if (this.rserviManager == null) {
+ this.rserviManager= new RServiManager("RCPDemo", getRGraphicFactory());
+ }
+ return this.rserviManager;
+ }
+
+ public synchronized ERGraphicFactory getRGraphicFactory() {
+ if (this.graphicFactory == null) {
+ this.graphicFactory= new ERGraphicFactory();
+ }
+ return this.graphicFactory;
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
new file mode 100644
index 0000000..f599e90
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+
+
+/**
+ * This class controls all aspects of the application's execution
+ */
+public class Application implements IApplication {
+
+
+ public Application() {
+ }
+
+
+ @Override
+ public Object start(final IApplicationContext context) throws Exception {
+ final Display display= PlatformUI.createDisplay();
+ try {
+ final int returnCode= PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
+ if (returnCode == PlatformUI.RETURN_RESTART) {
+ return IApplication.EXIT_RESTART;
+ } else {
+ return IApplication.EXIT_OK;
+ }
+ }
+ finally {
+ display.dispose();
+ }
+ }
+
+ @Override
+ public void stop() {
+ final IWorkbench workbench= PlatformUI.getWorkbench();
+ if (workbench == null) {
+ return;
+ }
+ final Display display= workbench.getDisplay();
+ display.syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!display.isDisposed()) {
+ workbench.close();
+ }
+ }
+ });
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
new file mode 100644
index 0000000..7dc61c3
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
@@ -0,0 +1,34 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+
+
+public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
+
+
+ public ApplicationActionBarAdvisor(final IActionBarConfigurer configurer) {
+ super(configurer);
+ }
+
+
+ @Override
+ protected void makeActions(final IWorkbenchWindow window) {
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
new file mode 100644
index 0000000..a82f86a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
+
+ private static final String PERSPECTIVE_ID= "org.eclipse.statet.rj.servi.rcpdemo.perspective";
+
+
+ @Override
+ public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+ return new ApplicationWorkbenchWindowAdvisor(configurer);
+ }
+
+ @Override
+ public String getInitialWindowPerspectiveId() {
+ return PERSPECTIVE_ID;
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
new file mode 100644
index 0000000..74507c6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
@@ -0,0 +1,46 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+
+public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
+
+
+ public ApplicationWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+ super(configurer);
+ }
+
+
+ @Override
+ public ActionBarAdvisor createActionBarAdvisor(final IActionBarConfigurer configurer) {
+ return new ApplicationActionBarAdvisor(configurer);
+ }
+
+ @Override
+ public void preWindowOpen() {
+ final IWorkbenchWindowConfigurer configurer= getWindowConfigurer();
+ configurer.setInitialSize(new Point(760, 600));
+ configurer.setShowCoolBar(false);
+ configurer.setShowStatusLine(true);
+ configurer.setShowProgressIndicator(true);
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
new file mode 100644
index 0000000..39e2966
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
@@ -0,0 +1,33 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+
+public class Perspective implements IPerspectiveFactory {
+
+
+ public Perspective() {
+ }
+
+
+ @Override
+ public void createInitialLayout(final IPageLayout layout) {
+ layout.setEditorAreaVisible(false);
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
new file mode 100644
index 0000000..d296cfc
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
@@ -0,0 +1,142 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicComposite;
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+import org.eclipse.statet.rj.servi.rcpdemo.RJob;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RService;
+
+
+public class GraphDemoView extends ViewPart {
+
+
+ public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo";
+
+
+ private Text commandControl;
+
+ private RGraphicComposite imageControl;
+
+ private ERGraphic currentPlot;
+
+
+ public GraphDemoView() {
+ }
+
+
+ @Override
+ public void createPartControl(final Composite parent) {
+ final Composite composite= new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(3, false));
+
+ final Label label= new Label(composite, SWT.LEFT);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ label.setText("Graphic &command:");
+
+ this.commandControl= new Text(composite, SWT.BORDER);
+ this.commandControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ final Button button= new Button(composite, SWT.PUSH);
+ button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ button.setText("Run");
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ run();
+ }
+ });
+
+ this.commandControl.setText("hist(rnorm(1e+07))");
+
+ this.imageControl= new RGraphicComposite(composite, null);
+ this.imageControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+ }
+
+ protected void setGraphic(final ERGraphic graphic) {
+ this.imageControl.setGraphic(graphic);
+
+ if (this.currentPlot != null) {
+ this.currentPlot.close();
+ this.currentPlot= null;
+ }
+ this.currentPlot= graphic;
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (this.currentPlot != null) {
+ this.currentPlot.close();
+ this.currentPlot= null;
+ }
+ }
+
+ @Override
+ public void setFocus() {
+ this.commandControl.setFocus();
+ }
+
+ private void run() {
+ final Point size= this.imageControl.getSize();
+ final String command= this.commandControl.getText();
+ final RJob job= new RJob("GraphDemo") {
+ @Override
+ protected void runRTask(final RService r, final IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("Creating graphic in R...", 100);
+
+ final RGraphicCreator rGraphicCreator= r.createRGraphicCreator(0);
+ rGraphicCreator.setSize(size.x, size.y);
+ final RGraphic plot= rGraphicCreator.create(command, monitor);
+
+ monitor.worked(90);
+
+ if (plot instanceof ERGraphic) {
+ final ERGraphic erPlot= (ERGraphic) plot;
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (GraphDemoView.this.imageControl.isDisposed()) {
+ erPlot.close();
+ return;
+ }
+ setGraphic(erPlot);
+ }
+ });
+ }
+ return;
+ }
+ };
+ job.schedule();
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
new file mode 100644
index 0000000..4f61d7d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+public class RServiConfigView extends ViewPart {
+
+
+ public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig";
+
+
+ private Button remoteSelectControl;
+ private Text remoteAddressControl;
+ private Button localSelectControl;
+ private Text localRhomeControl;
+ private Button rsetupSelectControl;
+ private Text rsetupIdControl;
+
+
+ public RServiConfigView() {
+ }
+
+
+ @Override
+ public void createPartControl(final Composite parent) {
+ final Composite composite= new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout());
+
+ this.remoteSelectControl= new Button(composite, SWT.RADIO);
+ this.remoteSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ this.remoteSelectControl.setText("Remote/Pool - RMI pool address:");
+
+ { this.remoteAddressControl= new Text(composite, SWT.BORDER);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd.horizontalIndent= 10;
+ this.remoteAddressControl.setLayoutData(gd);
+ }
+
+ this.localSelectControl= new Button(composite, SWT.RADIO);
+ this.localSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ this.localSelectControl.setText("Local - R_HOME:");
+
+ { this.localRhomeControl= new Text(composite, SWT.BORDER);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd.horizontalIndent= 10;
+ this.localRhomeControl.setLayoutData(gd);
+ }
+
+ { final Button button= new Button(composite, SWT.PUSH);
+ button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ button.setText("Select...");
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final DirectoryDialog dialog= new DirectoryDialog(button.getShell());
+ dialog.setMessage("Select R_HOME directory:");
+ final String path= dialog.open();
+ if (path != null) {
+ RServiConfigView.this.localRhomeControl.setText(path);
+ }
+ }
+ });
+ }
+
+ this.rsetupSelectControl= new Button(composite, SWT.RADIO);
+ this.rsetupSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ this.rsetupSelectControl.setText("Supplied R Setup - Id:");
+
+ { this.rsetupIdControl= new Text(composite, SWT.BORDER);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd.horizontalIndent= 10;
+ this.rsetupIdControl.setLayoutData(gd);
+ }
+
+ final Label label= new Label(composite, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+
+ final Button applyControl= new Button(composite, SWT.PUSH);
+ applyControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ applyControl.setText("Apply");
+ applyControl.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ applyConfig();
+ }
+ });
+
+ this.remoteSelectControl.setSelection(true);
+ this.remoteAddressControl.setText("rmi://localhost/rservi-pool");
+ final String rhome= System.getenv("R_HOME");
+ this.localRhomeControl.setText((rhome != null) ? rhome : "");
+ this.rsetupIdControl.setText("org.rproject.r.DefaultSetup");
+ }
+
+ @Override
+ public void setFocus() {
+ }
+
+ private void applyConfig() {
+ try {
+ final RServiManager manager= Activator.getInstance().getRServiManager();
+ if (this.remoteSelectControl.getSelection()) {
+ manager.setPool(this.remoteAddressControl.getText());
+ return;
+ }
+ if (this.localSelectControl.getSelection()) {
+ manager.setLocalInst(this.localRhomeControl.getText());
+ return;
+ }
+ if (this.rsetupSelectControl.getSelection()) {
+ manager.setRSetup(this.rsetupIdControl.getText());
+ return;
+ }
+ }
+ catch (final CoreException e) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+ "Could not apply RServi configuration.", e),
+ StatusManager.SHOW | StatusManager.LOG);
+ }
+ return;
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RJob.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RJob.java
new file mode 100644
index 0000000..9cb4073
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RJob.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import org.eclipse.core.runtime.CoreException;
+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.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.services.RService;
+
+
+public abstract class RJob extends Job {
+
+
+ private final RServiManager rServiManager;
+
+
+ public RJob(final String name) {
+ super(name);
+ this.rServiManager= Activator.getInstance().getRServiManager();
+ setRule(this.rServiManager.getSchedulingRule());
+ }
+
+
+ @Override
+ protected IStatus run(final IProgressMonitor monitor) {
+ RServi servi= null;
+ try {
+ servi= this.rServiManager.getRServi(getName());
+ runRTask(servi, monitor);
+ }
+ catch (final CoreException e) {
+ return new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+ "An error occurred when running " + getName() + ".", e);
+ }
+ finally {
+ if (servi != null) {
+ try {
+ servi.close();
+ } catch (final CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+ return Status.OK_STATUS;
+ }
+
+ @Override
+ public boolean belongsTo(final Object family) {
+ return this.rServiManager == family;
+ }
+
+ protected abstract void runRTask(RService r, IProgressMonitor monitor) throws CoreException;
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
new file mode 100644
index 0000000..5782843
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
@@ -0,0 +1,216 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import java.io.File;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+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.ISchedulingRule;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistryManager;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERClientGraphicActionsFactory;
+import org.eclipse.statet.rj.rsetups.RSetup;
+import org.eclipse.statet.rj.rsetups.RSetupUtil;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.server.osgi.ERJContext;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.node.RServiImpl;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+
+
+public class RServiManager {
+
+
+ private static final int LOCAL_INST= 1;
+ private static final int LOCAL_RSETUP= 2;
+ private static final int POOL= 3;
+
+ private static class Config {
+
+ private int mode;
+ private String address;
+
+ }
+
+
+ private final String name;
+
+ private Config config= new Config();
+
+ private RServiNodeManager localR;
+
+ private final ISchedulingRule schedulingRule= new ISchedulingRule() {
+ @Override
+ public boolean contains(final ISchedulingRule rule) {
+ return (rule == this);
+ }
+ @Override
+ public boolean isConflicting(final ISchedulingRule rule) {
+ // if concurrent remote instances are desired, return false here
+ return (rule == this);
+ }
+ };
+
+
+ public RServiManager(final String appId, final RClientGraphicFactory graphicFactory) {
+ this.name= appId;
+
+ RjsComConfig.setProperty("rj.servi.graphicFactory", graphicFactory);
+ RjsComConfig.setProperty("rj.servi.comClientGraphicActionsFactory",
+ new ERClientGraphicActionsFactory() );
+ }
+
+
+ public ISchedulingRule getSchedulingRule() {
+ return this.schedulingRule;
+ }
+
+ public void setLocalInst(final String rHome) throws CoreException {
+ final Config config= new Config();
+ config.mode= LOCAL_INST;
+ config.address= rHome;
+ this.config= config;
+
+ final RServiNodeConfig rConfig= new RServiNodeConfig();
+ rConfig.setRHome(rHome);
+ rConfig.setEnableVerbose(true);
+
+ startLocal(rConfig);
+ }
+
+ public void setRSetup(final String setupId) throws CoreException {
+ final Config config= new Config();
+ config.mode= LOCAL_RSETUP;
+ config.address= setupId;
+ this.config= config;
+
+ final RSetup setup= RSetupUtil.loadSetup(setupId, null);
+ if (setup == null) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "No R setup with specified id found."));
+ }
+
+ final RServiNodeConfig rConfig= new RServiNodeConfig();
+ rConfig.setRHome(setup.getRHome());
+ setLibs(setup.getRLibsSite(), rConfig, "R_LIBS_SITE");
+ setLibs(setup.getRLibs(), rConfig, "R_LIBS");
+ setLibs(setup.getRLibsUser(), rConfig, "R_LIBS_USER");
+ rConfig.setEnableVerbose(true);
+
+ startLocal(rConfig);
+ }
+
+ public void setPool(final String poolAddress) {
+ final Config config= new Config();
+ config.mode= POOL;
+ config.address= poolAddress;
+ this.config= config;
+ }
+
+
+ private void setLibs(final List<String> locations, final RServiNodeConfig rConfig, final String varName) {
+ if (locations != null && locations.size() > 0) {
+ final StringBuilder sb= new StringBuilder(locations.get(0));
+ for (int i= 0; i < locations.size(); i++) {
+ sb.append(File.pathSeparatorChar);
+ sb.append(locations.get(i));
+ }
+ rConfig.getEnvironmentVariables().put(varName, sb.toString());
+ }
+ }
+
+ private void startLocal(final RServiNodeConfig rConfig) throws CoreException {
+ startLocal(rConfig, new NullProgressMonitor()); // TODO real monitor, e.g. in a Job
+ }
+
+ private void startLocal(final RServiNodeConfig rConfig,
+ final IProgressMonitor monitor) throws CoreException {
+ if (rConfig == null) {
+ throw new NullPointerException("rConfig");
+ }
+ if (monitor == null) {
+ throw new NullPointerException("monitor");
+ }
+ try {
+ final ERJContext context= new ERJContext();
+ if (System.getSecurityManager() == null) {
+ if (System.getProperty("java.security.policy") == null) {
+ final String policyFile= context.getServerPolicyFilePath();
+ System.setProperty("java.security.policy", policyFile);
+ }
+ System.setSecurityManager(new SecurityManager());
+ }
+
+ final RMIRegistry registry= RMIRegistryManager.INSTANCE.getEmbeddedPrivateRegistry(monitor);
+
+ final RServiNodeFactory nodeFactory= RServiImpl.createLocalNodeFactory(this.name, context);
+ nodeFactory.setRegistry(registry);
+ nodeFactory.setConfig(rConfig);
+
+ final RServiNodeManager newLocalR= RServiImpl.createNodeManager(this.name, registry, nodeFactory);
+ newLocalR.start();
+ if (this.localR != null) {
+ this.localR.stop();
+ this.localR= null;
+ }
+ this.localR= newLocalR;
+ }
+ catch (final RjException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Local R instance could not created.", e));
+ }
+ }
+
+
+ public RServi getRServi(final String task) throws CoreException {
+ final Config config= this.config;
+ final String key= this.name + "-" + task;
+
+ try {
+ switch (config.mode) {
+ case LOCAL_INST:
+ case LOCAL_RSETUP:
+ return RServiUtil.getRServi(this.localR, key);
+ case POOL:
+ return RServiUtil.getRServi(config.address, key);
+ }
+ }
+ catch (final CoreException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+ }
+ catch (final LoginException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+ }
+ catch (final NoSuchElementException e) {
+ throw new CoreException(new Status(IStatus.INFO, Activator.BUNDLE_ID, "R currently not available, please try again later.", e));
+ }
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R is not configured, please check the configuration."));
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.classpath b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.classpath
new file mode 100644
index 0000000..eca7bdb
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.gitignore b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.project b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.project
new file mode 100644
index 0000000..af023be
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.servi.rcpdemo2</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.resources.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.runtime.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.core.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.ui.prefs b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/META-INF/MANIFEST.MF b/examples/org.eclipse.statet.rj.servi.rcpdemo2/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..62dcbf1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi.rcpdemo2;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi RCP Demo (2)
+Bundle-ActivationPolicy: lazy
+Bundle-Activator: org.eclipse.statet.internal.rj.servi.rcpdemo.Activator
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="1.1.0";visibility:=reexport,
+ org.eclipse.core.runtime,
+ org.eclipse.statet.ecommons.rmi.core;bundle-version="1.5.0",
+ org.eclipse.statet.rj.data;bundle-version="2.1.0",
+ org.eclipse.statet.rj.server;bundle-version="2.1.0",
+ org.eclipse.statet.rj.client;bundle-version="2.1.0",
+ org.eclipse.statet.rj.servi;bundle-version="2.1.0",
+ org.eclipse.ui,
+ org.eclipse.statet.rj.eclient.core;bundle-version="2.1.0",
+ org.eclipse.statet.rj.eclient.graphics;bundle-version="2.1.0"
+Import-Package: org.eclipse.statet.jcommons.lang;version="1.0.0"
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/RServi RCP Demo2.launch b/examples/org.eclipse.statet.rj.servi.rcpdemo2/RServi RCP Demo2.launch
new file mode 100644
index 0000000..d38a114
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/RServi RCP Demo2.launch
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.pde.ui.RuntimeWorkbench">
+<setAttribute key="additional_plugins"/>
+<booleanAttribute key="append.args" value="true"/>
+<stringAttribute key="application" value="org.eclipse.statet.rj.servi.rcpdemo.application"/>
+<booleanAttribute key="askclear" value="false"/>
+<booleanAttribute key="automaticAdd" value="false"/>
+<booleanAttribute key="automaticValidate" value="false"/>
+<stringAttribute key="bootstrap" value=""/>
+<stringAttribute key="checked" value="[NONE]"/>
+<booleanAttribute key="clearConfig" value="true"/>
+<booleanAttribute key="clearws" value="true"/>
+<booleanAttribute key="clearwslog" value="true"/>
+<stringAttribute key="configLocation" value="${workspace_loc}/.metadata/.plugins/org.eclipse.pde.core/RServi RCP Demo2"/>
+<booleanAttribute key="default" value="false"/>
+<stringAttribute key="featureDefaultLocation" value="workspace"/>
+<stringAttribute key="featurePluginResolution" value="workspace"/>
+<booleanAttribute key="includeOptional" value="false"/>
+<stringAttribute key="location" value="${workspace_loc}/../runtime-org.eclipse.statet.rj.servi.rcpdemo.product"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog"/>
+<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m"/>
+<booleanAttribute key="pde.generated.config" value="false"/>
+<stringAttribute key="pde.version" value="3.3"/>
+<stringAttribute key="product" value="org.eclipse.statet.rj.servi.rcpdemo2.product"/>
+<stringAttribute key="productFile" value="\org.eclipse.statet.rj.servi.rcpdemo2\org.eclipse.statet.rj.servi.rcpdemo.product"/>
+<setAttribute key="selected_features">
+<setEntry value="org.eclipse.statet.rj.servi.e:default"/>
+<setEntry value="org.eclipse.e4.rcp:default"/>
+<setEntry value="org.eclipse.emf.common:default"/>
+<setEntry value="org.eclipse.emf.ecore:default"/>
+<setEntry value="org.eclipse.rcp:default"/>
+</setAttribute>
+<booleanAttribute key="show_selected_only" value="false"/>
+<booleanAttribute key="tracing" value="false"/>
+<booleanAttribute key="useCustomFeatures" value="true"/>
+<booleanAttribute key="useDefaultConfig" value="true"/>
+<booleanAttribute key="useDefaultConfigArea" value="true"/>
+<booleanAttribute key="useProduct" value="true"/>
+<booleanAttribute key="usefeatures" value="false"/>
+</launchConfiguration>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/about.html b/examples/org.eclipse.statet.rj.servi.rcpdemo2/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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 <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+</p>
+
+<p>
+ 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 <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/build.properties b/examples/org.eclipse.statet.rj.servi.rcpdemo2/build.properties
new file mode 100644
index 0000000..8f6690d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/build.properties
@@ -0,0 +1,11 @@
+source..= src/
+output..= bin/
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ plugin.xml,\
+ .,\
+ icons/,\
+ plugin_customization.ini,\
+ splash.bmp
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_about.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_about.gif
new file mode 100644
index 0000000..20d9ad2
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_about.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.icns b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.icns
new file mode 100644
index 0000000..b77a6a6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.icns
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.ico b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.ico
new file mode 100644
index 0000000..d548f71
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.ico
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.xpm b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.xpm
new file mode 100644
index 0000000..d2918c1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_launcher.xpm
@@ -0,0 +1,307 @@
+/* XPM */
+static char * icon48_xpm[]= {
+"48 48 256 2",
+" c #4B4B3B3B9090",
+". c #0D0D0E0E5454",
+"X c #11110E0E5B5B",
+"o c #17170F0F6363",
+"O c #1D1D13136969",
+"+ c #212114146C6C",
+"@ c #252514147171",
+"# c #282811116C6C",
+"$ c #26260D0D6363",
+"% c #22220B0B5E5E",
+"& c #1C1C0B0B5A5A",
+"* c #1C1C0B0B5252",
+"= c #1B1B05055353",
+"- c #161606064D4D",
+"; c #161605054949",
+": c #111104044848",
+"> c #131304044545",
+", c #131305054242",
+"< c #141410105E5E",
+"1 c #2C2C15157373",
+"2 c #2B2B1B1B7575",
+"3 c #343416167272",
+"4 c #313113136E6E",
+"5 c #222209095757",
+"6 c #1B1B06064D4D",
+"7 c #15150B0B4242",
+"8 c #13130C0C5555",
+"9 c #2E2E1B1B7878",
+"0 c #33331F1F7C7C",
+"q c #343418187878",
+"w c #3B3B1C1C7575",
+"e c #2E2E10106767",
+"r c #1B1B07074747",
+"t c #18180B0B4646",
+"y c #151513136262",
+"u c #1A1A15156464",
+"i c #34341F1F7777",
+"p c #40401E1E8080",
+"a c #42421B1B7A7A",
+"s c #3B3B15157474",
+"d c #2B2B0B0B5B5B",
+"f c #222207075252",
+"g c #373727277A7A",
+"h c #474724248484",
+"j c #393915156E6E",
+"k c #373711116A6A",
+"l c #343413136363",
+"z c #232319196E6E",
+"x c #292919197070",
+"c c #3C3C2C2C8282",
+"v c #444431318585",
+"b c #494934348A8A",
+"n c #505026268A8A",
+"m c #3D3D1B1B6E6E",
+"M c #31310E0E5C5C",
+"N c #2B2B0D0D5353",
+"B c #222207074A4A",
+"V c #52523C3C9292",
+"C c #58583C3C9494",
+"Z c #5D5D44449797",
+"A c #5C5C2E2E9292",
+"S c #676733339595",
+"D c #424228287575",
+"F c #29290A0A4F4F",
+"G c #6C6C4A4A9E9E",
+"H c #72725454A7A7",
+"J c #8C8C6D6DB2B2",
+"K c #343424246E6E",
+"L c #3A3A23236A6A",
+"P c #3A3A1C1C6767",
+"I c #24240A0A4B4B",
+"U c #151518186161",
+"Y c #76766F6FA5A5",
+"T c #ADAD9191CCCC",
+"R c #98988989D3D3",
+"E c #45453B3B8686",
+"W c #3C3C35357979",
+"Q c #363631317575",
+"! c #32322D2D6B6B",
+"~ c #323229296363",
+"^ c #30301F1F6262",
+"/ c #323218185E5E",
+"( c #272707074B4B",
+") c #202028286C6C",
+"_ c #1E1E1D1D6868",
+"` c #9A9A8282BBBB",
+"' c #C8C8B3B3D3D3",
+"] c #B3B3AFAFE7E7",
+"[ c #84847272C6C6",
+"{ c #58585757A3A3",
+"} c #3F3F3C3C8A8A",
+"| c #3B3B3A3A8484",
+" . c #414139397D7D",
+".. c #3D3D39397A7A",
+"X. c #37372E2E6E6E",
+"o. c #2C2C21215A5A",
+"O. c #2E2E1B1B5B5B",
+"+. c #F5F5EFEFF5F5",
+"@. c #656566669A9A",
+"#. c #47474B4B8E8E",
+"$. c #3C3C44447B7B",
+"%. c #444442428080",
+"&. c #45453E3E8181",
+"*. c #40403C3C8181",
+"=. c #3D3D33337474",
+"-. c #3B3B30306E6E",
+";. c #38382D2D6969",
+":. c #303026265D5D",
+">. c #2C2C15155A5A",
+",. c #1F1F1C1C7070",
+"<. c #25251E1E7171",
+"1. c #59595C5C9191",
+"2. c #4D4D53538989",
+"3. c #4C4C49498484",
+"4. c #484845458585",
+"5. c #494941418585",
+"6. c #494940408181",
+"7. c #2F2F1C1C5353",
+"8. c #2B2B28287676",
+"9. c #323231317F7F",
+"0. c #545452528B8B",
+"q. c #51514E4E8989",
+"w. c #4E4E4B4B8C8C",
+"e. c #4C4C47478686",
+"r. c #46463D3D7E7E",
+"t. c #434336367A7A",
+"y. c #2B2B13135555",
+"u. c #47473D3D8D8D",
+"i. c #575757578E8E",
+"p. c #48483E3E7F7F",
+"a. c #46463A3A7D7D",
+"s. c #424235357575",
+"d. c #404034347171",
+"f. c #BFBFCBCBFAFA",
+"g. c #B8B8A8A8DDDD",
+"h. c #5E5E60609292",
+"j. c #565655558C8C",
+"k. c #4B4B44448282",
+"l. c #454539397B7B",
+"z. c #434338387878",
+"x. c #3F3F32326D6D",
+"c. c #3D3D30306969",
+"v. c #3A3A2E2E6363",
+"b. c #36362A2A5C5C",
+"n. c #343424245555",
+"m. c #30301E1E4D4D",
+"M. c #49493C3C8282",
+"N. c #5E5E4F4F8C8C",
+"B. c #56563B3B8B8B",
+"V. c #545407078585",
+"C. c #424234347272",
+"Z. c #9797A4A4F7F7",
+"A. c #444436367676",
+"S. c #7D7D7979D5D5",
+"D. c #464640408A8A",
+"F. c #44444B4B8282",
+"G. c #414107077777",
+"H. c #71716161C1C1",
+"J. c #303039397979",
+"K. c #8E8E8E8EE6E6",
+"L. c #404033338B8B",
+"P. c #4A4A45458C8C",
+"I. c #46463A3A8080",
+"U. c #363629295454",
+"Y. c #303022224848",
+"T. c #424237377575",
+"R. c #2E2E1D1D6363",
+"E. c #79798383EAEA",
+"W. c #74747B7BE4E4",
+"Q. c #6D6D7676D6D6",
+"!. c #6A6A7171CECE",
+"~. c #66666969C6C6",
+"^. c #62626565BCBC",
+"/. c #5F5F6060B5B5",
+"(. c #5B5B5B5BACAC",
+"). c #535353539898",
+"_. c #4F4F4F4FA4A4",
+"`. c #54544D4DA4A4",
+"'. c #323204046B6B",
+"]. c #303035357979",
+"[. c #313122224343",
+"{. c #5A5A5B5BB7B7",
+"}. c #484846468080",
+"|. c #454541417575",
+" X c #4B4B31318282",
+".X c #47473C3C8484",
+"XX c #3E3E35356E6E",
+"oX c #2F2F26264040",
+"OX c #2B2B23233A3A",
+"+X c #262619195C5C",
+"@X c #252515155A5A",
+"#X c #55555151B3B3",
+"$X c #3C3C2D2D5D5D",
+"%X c #39392F2F5656",
+"&X c #37372D2D5050",
+"*X c #25251F1F3030",
+"=X c #24241D1D4343",
+"-X c #202013135656",
+";X c #41413B3B6C6C",
+":X c #444442429696",
+">X c #212100005E5E",
+",X c #444436367272",
+"<X c #444436366F6F",
+"1X c #424236366868",
+"2X c #3F3F34346161",
+"3X c #3C3C32325A5A",
+"4X c #34342A2A4A4A",
+"5X c #21211B1B2121",
+"6X c #22221C1C6363",
+"7X c #2D2D01015E5E",
+"8X c #20201B1B2525",
+"9X c #49492F2F7B7B",
+"0X c #434334346C6C",
+"qX c #323229294545",
+"wX c #1C1C10104F4F",
+"eX c #222217176363",
+"rX c #37371E1E6B6B",
+"tX c #424232326E6E",
+"yX c #444433336969",
+"uX c #424233336565",
+"iX c #1E1E1A1A1E1E",
+"pX c #161601014C4C",
+"aX c #1C1C11115454",
+"sX c #252503035B5B",
+"dX c #414131316A6A",
+"fX c #22221F1F7878",
+"gX c #272724246767",
+"hX c #1D1D16165E5E",
+"jX c #131305055151",
+"kX c #40402F2F6464",
+"lX c #111107074E4E",
+"zX c #0C0C05054B4B",
+"xX c #22221E1E5757",
+"cX c #1A1A0D0D4D4D",
+"vX c #16160B0B4D4D",
+"bX c #060604044747",
+"nX c #040403034343",
+"mX c #3B3B27276565",
+"MX c #0E0E03034141",
+"NX c #111106064A4A",
+"BX c #0E0E04044646",
+"VX c #111105053B3B",
+"CX c #0D0D01013A3A",
+"ZX c #030305053F3F",
+"AX c #0F0F0F0F4C4C",
+"SX c #020207073B3B",
+"DX c #0D0D03034646",
+"FX c #0B0B02023F3F",
+"GX c #0D0D02023434",
+"HX c #0A0A0E0E4444",
+"JX c #161614145252",
+"KX c #0B0B04044646",
+"LX c #0A0A03034444",
+"PX c #1D1D21215757",
+"IX c #090910104040",
+"UX c #18181E1E5353",
+" ",
+" . . . . X X o o o o O + + @ @ @ @ @ @ @ # # # # # # $ $ % % & & & & *= - - - ; : > > , , , ",
+" . . X X < < o o O O + @ 1 2 2 1 1 1 1 1 1 1 1 3 4 # # $ $ $ % % % 5= = 6 6 - ; ; > > , , 7 ",
+" . 8 < < < o O O + @ @ 2 9 9 0 0 q q q q q q q w 3 4 4 e e $ $ $ $ % 5= = 6 6 6 ; ; > > r t ",
+" . X < y u O O + @ 1 2 i 0 0 p p p p p p p a a p a s 3 4 4 e e e e d 5 5 f f 6 6 6 ; ; r r t ",
+" X < y u O + + @ 2 9 0 g p p h h h h h h h p h h a a s s j k k j l d d 5 5 f f 6 6 r r r r r ",
+" X < y O z x x 9 0 g c v b n n n n n n n n n n n h a a s s j j m l M d d N f f B B B B r r r ",
+" < y u + z 2 0 c c b V C Z C C A A A A A S S S n h D w w m m m m k l M d d N f F F F B r r r ",
+" < y O z z 9 c b V Z G H H H G S G G J J H V v c g g K K K K L P l l l M M N N N N I B B r r ",
+" U u + z x i v C H Y J J J J H J T R H V E W W Q Q Q Q ! ! ! ~ ^ ^ / / M M M M M N ( B B r r ",
+" ) _ z x 9 g b Z Y ` ' ' ' T T ] [ { } | .........W W Q Q X.! ~ ~ o.O./ / / / N F ( B B B r ",
+" ) ) z x i c V G J ' +.+.+.+.] [ @.#.$.%.%.%.&.*. . .....W =.-.X.;.~ :.o.O.^ >.N F ( B B B B ",
+" ) ,.<.2 g v C H J ' +.+.+.+.T Y 1.2.3.4.4.4.5.6.&.&. . ...W =.=.-.;.~ :.o.7.>.N F F ( B I I ",
+" ) ,.<.8.9.b C H J T +.+.+.' J @.1.0.q.q.w.e.4.5.6.&.r. . .t.W =.=.-.;.~ :.o.7.y.N F ( ( I I ",
+" 8.8.8.9.| u.C G J T +.+.' ` Y @.1.i.0.q.q.e.e.5.6.p.r.a. .t.t.s.d.d.-.;.~ :.7.7.y.F F ( I I ",
+" 9.c c c v b A S H ' f.g.` Y @.h.1.i.j.0.q.q.e.k.6.p.r.a.l.t.z.s.s.d.x.c.v.b.n.m.7.N F F F I ",
+" <.g M.N.B.B.n V.J f.R J @.h.h.1.i.i.j.j.0.q.3.k.6.p.r.a.l.l.z.s.C.d.x.x.c.v.b.n.m.y.N F F F ",
+" + x i v B.Z Z G g.Z.[ @.2.i.i.j.j.j.j.j.0.q.3.k.6.p.p.a.l.l.A.s.C.C.d.x.c.v.b.n.m.7.y.N N y. ",
+" O # 3 w p n Z ` f.S.H D.F.q.0.0.0.0.j.0.q.q.3.k.6.p.r.a.a.l.A.s.s.C.d.x.x.c.v.b.n.m.y.y.y.y. ",
+" O # 4 s a G.V.T Z.H.V J.%.e.w.q.0.0.0.0.q.q.e.k.6.p.r.a.a.l.z.A.s.C.d.d.x.c.v.b.n.m.7.>.y.y. ",
+" O # 4 s w G.A f.K.H L...4.P.w.w.w.q.q.q.q.e.e.5.6.M.I.I.a.a.l.z.A.s.d.d.x.c.v.v.U.Y.7.O.>.y. ",
+" $ # 4 3 s G.G f.S.Z 9.*.D.P.P.w.w.w.w.w.e.e.5.5.M.M.I.I.a.a.l.z.T.s.d.d.x.x.c.v.U.Y.m.R.>.>. ",
+" E.E.W.W.W.W.E.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { )._.`._. ",
+" + # 3 w s '.` f.H.V ].*.D.P.P.P.P.P.P.P.5.5.5.M.M.M.I.I.a.l.z.z.T.T.s.d.d.x.c.v.U.Y.[.^ O.>. ",
+" ~.~.~.~.~.~.K.Z.S.~.{.^.^.^.^.^.^.^.^././././././.(.(.(.(.(.(.{ { { { { ).).).w.w.}.|.P.u.} ",
+" .I.6. X X XT f.H.b ].*.E D.D.D.D.5.5..X.XM.M.I.I.a.a.l.l.z.z.T.T.T.d.XXx.c.v.b.U.oXOXR.+X@X ",
+" E.E.E.W.W.W.K.Z.E.W.Q.Q.Q.Q.Q.Q.Q.Q.!.!.!.!.!.!.~.~.~.~.~.~.^.^.^.^.^./././.(.{ { ).).#X_._. ",
+" & % $ e '.= H f.H.b 8.W *.E E E .X.X.XI.I.I.I.a.a.l.l.z.z.T.T.T.C.XXXXc.v.$X%X&XY.*X=X2 @X-X ",
+" {.{.{.{.{.#X~.Z.W.~.{.{./././././././././.(.(.(.(.(.(.(.{ { { { { { ).).).w.w.3.}.;X%.:X} } ",
+" & & % $ e >XV.f.S.C K X.W t. . .l.l.t.t.t.t.A.A.A.,X,X,X,X,X<X;X1X1X2X3X%X&X4XoX*X5Xo.6X-X-X ",
+" & & % $ $ >X7X` Z.Z D ! =.=.s.t.t.t.A.A.s.A.,X,X,X,X<X<X<X<X;X1X2X2X3X%X&X4XoXOX8X5X<.@X-X-X ",
+" 8 & & $ e K 9XJ f.^. XK X.=.=.s.s.s.s.s.C.C.C.C.<X0X0X0X1X1X1X2X2X3X%X&X4XqXOX*X8X=X<.-X-XwX ",
+" 8 & eXK k.@.M. Xg.E.B.rX~ -.d.d.C.C.C.C.C.tX0X0X0XyXyX1X1XuX2X2X3X%X&X4XqXoXOX8XiX6XeX-X-XwX ",
+" 6XQ h.Y N.K e pXB.f./.9Xo.;.-.x.d.tXtXtXtXtX0X0XyXyXyXuXuX2X2X3X%X&X4XqXoXOX*XiX=X_ aX-XaXwX ",
+" Y Y .R.@X% sX= 7XT Z.V P :.;.c.x.x.x.tXdXdXdXyXyXuXuX2X2X3X3X%X&X4XqXoXOX*X8X*XfXaXaXaXwXwX ",
+" gXhX& * & 5 5 sXjXa ] S.9X/ ~ v.c.dXdXdXdXdXuXuXuXkX2X2X3X%X%X&X4XqXoXOX*X8XiX<.hXwXwXaXwXwX ",
+" 8 lXlXjX= * 5 5= zX9X] H.D 7.b.v.v.kXc.kXkXkXkXkX2X$X3X%X&X&X4XqXoXOX*X8XiXxXhXwXcXcXwXwXwX ",
+" zXzXlXlXjX== f f sXD Y ] ~.D 7.n.b.v.v.kXkXkXkX$X$X%X%X&X4XqXoXoXOX*X8X5XgXu cXvXvXcXcXwXwX ",
+" bXbXzXlXlX-= * @XX.h.e D T S.D n.m.b.$X$X$X$X$X%X%X&X&X4XqXoXOX*X8X8X*X<.hXvX; ; vXvXvXcXwX ",
+" nXbXzXzXlXlX- -XX.Y R.pXpXP J K.Z mXm.n.U.U.U.U.U.4X4XY.oXOX*X8X8X8X=X,.aXvX; > > > t t t cX ",
+" nXbXbXzXzXlXaXXXY +Xf= f= 7XtXR R mXn.Y.[.[.[.[.OX*X*X8X5X*X=X,.u vXvX; > > MXMX, 7 t t ",
+" nXnXnXbXzXvX-.Y +XcX6 6= == d L B.G H `.X.:.7.m.=X=X=X=X=X6X,.u cXvXNX: BX> MXVXCXVX7 7 7 ",
+" ZXZXnXbXAXgX@.+XvX; - - - - * @XR.>.sX>.R.i 0 x eXeXeXeXO hXaXcXvXNX: BXMXMXMXVXCXCXCXVX7 7 ",
+" SXZXZXAXgXN.aXNX: : NXNXNX- * +X+X* 6 6 6 * * * * * * * vXvX- NX: DXBXMXMXFXCXCXCXCXGXVXVX7 ",
+" SXSXHXgX0.JXKXLXKXKXDX: : NX* @X-X- - - - - - - - - - - NX: DXDXDXMXMXFXFXCXCXCXCXGXGXGXVXVX ",
+" SXHXPX3.JXnXnXnXnXbXLXKXKXNXaX-XvX: : NX: : : : : : : BXDXDXLXMXMXFXFXCXCXCXCXGXGXGXGXGXGXGX ",
+" IXUX$.AXZXZXZXZXnXnXnXLXLXNXJXvXBXDXBXBXBXBXDXDXDXDXLXDXLXLXFXFXFXFXCXCXCXCXGXGXGXGXGXGXGXGX ",
+" "};
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_16.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_16.gif
new file mode 100644
index 0000000..05626b1
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_16.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_32.gif b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_32.gif
new file mode 100644
index 0000000..b432f88
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/icons/alt_window_32.gif
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/org.eclipse.statet.rj.servi.rcpdemo.product b/examples/org.eclipse.statet.rj.servi.rcpdemo2/org.eclipse.statet.rj.servi.rcpdemo.product
new file mode 100644
index 0000000..836d481
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/org.eclipse.statet.rj.servi.rcpdemo.product
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?pde version="3.5"?>
+
+<product name="RServi RCP Demo" id="org.eclipse.statet.rj.servi.rcpdemo2.product" application="org.eclipse.statet.rj.servi.rcpdemo.application" version="0.4.0.qualifier" useFeatures="false" includeLaunchers="true">
+
+ <configIni use="default">
+ </configIni>
+
+ <launcherArgs>
+ <vmArgs>-Xms40m -Xmx512m
+ </vmArgs>
+ <vmArgsMac>-XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts
+ </vmArgsMac>
+ </launcherArgs>
+
+ <windowImages i16="icons/alt_window_16.gif" i32="icons/alt_window_32.gif"/>
+
+ <splash
+ location="org.eclipse.statet.rj.servi.rcpdemo2"
+ startupProgressRect="20,190,415,15"
+ startupMessageRect="20,210,415,20"
+ startupForegroundColor="000000" />
+ <launcher>
+ <solaris/>
+ <win useIco="false">
+ <bmp/>
+ </win>
+ </launcher>
+
+ <vm>
+ </vm>
+
+ <plugins>
+ <plugin id="com.ibm.icu"/>
+ <plugin id="org.eclipse.statet.ecommons.runtime.core"/>
+ <plugin id="org.eclipse.statet.ecommons.rmi.core"/>
+ <plugin id="org.eclipse.statet.ecommons.coremisc"/>
+ <plugin id="org.eclipse.statet.ecommons.uimisc"/>
+ <plugin id="org.eclipse.statet.rj.data"/>
+ <plugin id="org.eclipse.statet.rj.client"/>
+ <plugin id="org.eclipse.statet.rj.services.core"/>
+ <plugin id="org.eclipse.statet.rj.eclient.core"/>
+ <plugin id="org.eclipse.statet.rj.eclient.graphics"/>
+ <plugin id="org.eclipse.statet.rj.server"/>
+ <plugin id="org.eclipse.statet.rj.servi"/>
+ <plugin id="org.eclipse.statet.rj.servi.rcpdemo2"/>
+ <plugin id="javax.annotation"/>
+ <plugin id="javax.inject"/>
+ <plugin id="javax.xml"/>
+ <plugin id="org.apache.batik.css"/>
+ <plugin id="org.apache.batik.util"/>
+ <plugin id="org.apache.batik.util.gui"/>
+ <plugin id="org.apache.commons.jxpath"/>
+ <plugin id="org.eclipse.core.commands"/>
+ <plugin id="org.eclipse.core.contenttype"/>
+ <plugin id="org.eclipse.core.databinding"/>
+ <plugin id="org.eclipse.core.databinding.observable"/>
+ <plugin id="org.eclipse.core.databinding.property"/>
+ <plugin id="org.eclipse.core.expressions"/>
+ <plugin id="org.eclipse.core.jobs"/>
+ <plugin id="org.eclipse.core.runtime"/>
+ <plugin id="org.eclipse.core.runtime.compatibility.registry" fragment="true"/>
+ <plugin id="org.eclipse.e4.core.commands"/>
+ <plugin id="org.eclipse.e4.core.contexts"/>
+ <plugin id="org.eclipse.e4.core.di"/>
+ <plugin id="org.eclipse.e4.core.di.annotations"/>
+ <plugin id="org.eclipse.e4.core.di.extensions"/>
+ <plugin id="org.eclipse.e4.core.services"/>
+ <plugin id="org.eclipse.e4.emf.xpath"/>
+ <plugin id="org.eclipse.e4.ui.bindings"/>
+ <plugin id="org.eclipse.e4.ui.css.core"/>
+ <plugin id="org.eclipse.e4.ui.css.swt"/>
+ <plugin id="org.eclipse.e4.ui.css.swt.theme"/>
+ <plugin id="org.eclipse.e4.ui.di"/>
+ <plugin id="org.eclipse.e4.ui.model.workbench"/>
+ <plugin id="org.eclipse.e4.ui.services"/>
+ <plugin id="org.eclipse.e4.ui.widgets"/>
+ <plugin id="org.eclipse.e4.ui.workbench"/>
+ <plugin id="org.eclipse.e4.ui.workbench.addons.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench.renderers.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench.swt"/>
+ <plugin id="org.eclipse.e4.ui.workbench3"/>
+ <plugin id="org.eclipse.emf.common"/>
+ <plugin id="org.eclipse.emf.ecore"/>
+ <plugin id="org.eclipse.emf.ecore.change"/>
+ <plugin id="org.eclipse.emf.ecore.xmi"/>
+ <plugin id="org.eclipse.equinox.app"/>
+ <plugin id="org.eclipse.equinox.common"/>
+ <plugin id="org.eclipse.equinox.ds"/>
+ <plugin id="org.eclipse.equinox.event"/>
+ <plugin id="org.eclipse.equinox.preferences"/>
+ <plugin id="org.eclipse.equinox.registry"/>
+ <plugin id="org.eclipse.equinox.util"/>
+ <plugin id="org.eclipse.help"/>
+ <plugin id="org.eclipse.jface"/>
+ <plugin id="org.eclipse.jface.databinding"/>
+ <plugin id="org.eclipse.osgi"/>
+ <plugin id="org.eclipse.osgi.compatibility.state" fragment="true"/>
+ <plugin id="org.eclipse.osgi.services"/>
+ <plugin id="org.eclipse.swt"/>
+ <plugin id="org.eclipse.swt.cocoa.macosx" fragment="true"/>
+ <plugin id="org.eclipse.swt.cocoa.macosx.x86_64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.aix.ppc" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.aix.ppc64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.hpux.ia64_32" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.ppc64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.s390" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.s390x" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.x86" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.linux.x86_64" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.solaris.sparc" fragment="true"/>
+ <plugin id="org.eclipse.swt.gtk.solaris.x86" fragment="true"/>
+ <plugin id="org.eclipse.swt.win32.win32.x86" fragment="true"/>
+ <plugin id="org.eclipse.swt.win32.win32.x86_64" fragment="true"/>
+ <plugin id="org.eclipse.ui"/>
+ <plugin id="org.eclipse.ui.workbench"/>
+ <plugin id="org.w3c.css.sac"/>
+ <plugin id="org.w3c.dom.events"/>
+ <plugin id="org.w3c.dom.smil"/>
+ <plugin id="org.w3c.dom.svg"/>
+ </plugins>
+
+ <configurations>
+ <plugin id="org.eclipse.core.runtime" autoStart="true" startLevel="0" />
+ <plugin id="org.eclipse.equinox.common" autoStart="true" startLevel="2" />
+ <plugin id="org.eclipse.equinox.ds" autoStart="true" startLevel="1" />
+ <plugin id="org.eclipse.osgi" autoStart="true" startLevel="-1" />
+ </configurations>
+
+</product>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin.xml b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin.xml
new file mode 100644
index 0000000..c002914
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+ <extension
+ id="org.eclipse.statet.rj.servi.rcpdemo.application"
+ point="org.eclipse.core.runtime.applications">
+ <application>
+ <run
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.Application">
+ </run>
+ </application>
+ </extension>
+ <extension
+ id="product"
+ point="org.eclipse.core.runtime.products">
+ <product
+ application="org.eclipse.statet.rj.servi.rcpdemo.application"
+ name="RServi RCP Demo">
+ <property
+ name="windowImages"
+ value="icons/alt_window_16.gif,icons/alt_window_32.gif">
+ </property>
+ <property
+ name="appName"
+ value="RServi RCP Demo">
+ </property>
+ <property
+ name="startupProgressRect"
+ value="20,190,415,15">
+ </property>
+ <property
+ name="startupForegroundColor"
+ value="000000">
+ </property>
+ <property
+ name="startupMessageRect"
+ value="20,210,415,20">
+ </property>
+ <property
+ name="preferenceCustomization"
+ value="plugin_customization.ini">
+ </property>
+ </product>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.perspectives">
+ <perspective
+ name="RCP Perspective"
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.Perspective"
+ id="org.eclipse.statet.rj.servi.rcpdemo.perspective">
+ </perspective>
+ </extension>
+ <extension
+ point="org.eclipse.ui.menus">
+ <menuContribution
+ locationURI="menu:org.eclipse.ui.main.menu">
+ <menu id="file"
+ label="&File">
+ </menu>
+ </menuContribution>
+ <menuContribution
+ locationURI="menu:file">
+ <command
+ commandId="org.eclipse.ui.file.exit"
+ style="push">
+ </command>
+ </menuContribution>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.views">
+ <view
+ allowMultiple="false"
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.RServiConfigView"
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+ name="Config"
+ restorable="true">
+ </view>
+ <view
+ allowMultiple="true"
+ class="org.eclipse.statet.internal.rj.servi.rcpdemo.views.GraphDemoView"
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+ name="Graph"
+ restorable="true">
+ </view>
+ <view
+ id="org.eclipse.ui.views.ProgressView"
+ class="org.eclipse.ui.ExtensionFactory:progressView"
+ name="Progress">
+ </view>
+ </extension>
+ <extension
+ point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension
+ targetID="*">
+ <view
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+ closeable="false"
+ minimized="false"
+ relative="org.eclipse.ui.editorss"
+ relationship="left"
+ visible="true">
+ </view>
+ <view
+ id="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+ closeable="false"
+ minimized="false"
+ ratio="0.3f"
+ relative="org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo"
+ relationship="left"
+ visible="true">
+ </view>
+ <view
+ id="org.eclipse.ui.views.ProgressView"
+ closeable="true"
+ minimized="false"
+ ratio="0.75"
+ relative="org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig"
+ relationship="bottom"
+ visible="false">
+ </view>
+ </perspectiveExtension>
+ </extension>
+
+</plugin>
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin_customization.ini b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin_customization.ini
new file mode 100644
index 0000000..61d5abf
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/plugin_customization.ini
@@ -0,0 +1 @@
+org.eclipse.ui/SHOW_PROGRESS_ON_STARTUP= true
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/splash.bmp b/examples/org.eclipse.statet.rj.servi.rcpdemo2/splash.bmp
new file mode 100644
index 0000000..fbcd619
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/splash.bmp
Binary files differ
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
new file mode 100644
index 0000000..941c0b4
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Activator.java
@@ -0,0 +1,96 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.osgi.framework.BundleContext;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERGraphicFactory;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+
+ public static final String BUNDLE_ID= "org.eclipse.statet.rj.servi.rcpdemo2";
+
+
+ private static Activator instance;
+
+ /**
+ * Returns the shared plug-in instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getInstance() {
+ return instance;
+ }
+
+
+ private RServiManager rserviManager;
+
+ private ERGraphicFactory graphicFactory;
+
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+
+ @Override
+ public void start(final BundleContext context) throws Exception {
+ super.start(context);
+ instance= this;
+ }
+
+ @Override
+ public void stop(final BundleContext context) throws Exception {
+ Disposable disposable;
+ synchronized (this) {
+ disposable= this.rserviManager;
+ this.rserviManager= null;
+ }
+ if (disposable != null) {
+ disposable.dispose();
+ }
+
+ instance= null;
+ super.stop(context);
+ }
+
+
+ public synchronized RServiManager getRServiManager() {
+ if (this.rserviManager == null) {
+ this.rserviManager= new RServiManager("RCPDemo", getRGraphicFactory());
+ }
+ return this.rserviManager;
+ }
+
+ public synchronized ERGraphicFactory getRGraphicFactory() {
+ if (this.graphicFactory == null) {
+ this.graphicFactory= new ERGraphicFactory();
+ }
+ return this.graphicFactory;
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
new file mode 100644
index 0000000..f599e90
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Application.java
@@ -0,0 +1,67 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.equinox.app.IApplication;
+import org.eclipse.equinox.app.IApplicationContext;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.PlatformUI;
+
+
+/**
+ * This class controls all aspects of the application's execution
+ */
+public class Application implements IApplication {
+
+
+ public Application() {
+ }
+
+
+ @Override
+ public Object start(final IApplicationContext context) throws Exception {
+ final Display display= PlatformUI.createDisplay();
+ try {
+ final int returnCode= PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
+ if (returnCode == PlatformUI.RETURN_RESTART) {
+ return IApplication.EXIT_RESTART;
+ } else {
+ return IApplication.EXIT_OK;
+ }
+ }
+ finally {
+ display.dispose();
+ }
+ }
+
+ @Override
+ public void stop() {
+ final IWorkbench workbench= PlatformUI.getWorkbench();
+ if (workbench == null) {
+ return;
+ }
+ final Display display= workbench.getDisplay();
+ display.syncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (!display.isDisposed()) {
+ workbench.close();
+ }
+ }
+ });
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
new file mode 100644
index 0000000..7dc61c3
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationActionBarAdvisor.java
@@ -0,0 +1,34 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+
+
+public class ApplicationActionBarAdvisor extends ActionBarAdvisor {
+
+
+ public ApplicationActionBarAdvisor(final IActionBarConfigurer configurer) {
+ super(configurer);
+ }
+
+
+ @Override
+ protected void makeActions(final IWorkbenchWindow window) {
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
new file mode 100644
index 0000000..a82f86a
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchAdvisor.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchAdvisor;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor {
+
+ private static final String PERSPECTIVE_ID= "org.eclipse.statet.rj.servi.rcpdemo.perspective";
+
+
+ @Override
+ public WorkbenchWindowAdvisor createWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+ return new ApplicationWorkbenchWindowAdvisor(configurer);
+ }
+
+ @Override
+ public String getInitialWindowPerspectiveId() {
+ return PERSPECTIVE_ID;
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
new file mode 100644
index 0000000..74507c6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/ApplicationWorkbenchWindowAdvisor.java
@@ -0,0 +1,46 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.application.ActionBarAdvisor;
+import org.eclipse.ui.application.IActionBarConfigurer;
+import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
+import org.eclipse.ui.application.WorkbenchWindowAdvisor;
+
+
+public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
+
+
+ public ApplicationWorkbenchWindowAdvisor(final IWorkbenchWindowConfigurer configurer) {
+ super(configurer);
+ }
+
+
+ @Override
+ public ActionBarAdvisor createActionBarAdvisor(final IActionBarConfigurer configurer) {
+ return new ApplicationActionBarAdvisor(configurer);
+ }
+
+ @Override
+ public void preWindowOpen() {
+ final IWorkbenchWindowConfigurer configurer= getWindowConfigurer();
+ configurer.setInitialSize(new Point(760, 600));
+ configurer.setShowCoolBar(false);
+ configurer.setShowStatusLine(true);
+ configurer.setShowProgressIndicator(true);
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
new file mode 100644
index 0000000..39e2966
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/Perspective.java
@@ -0,0 +1,33 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo;
+
+import org.eclipse.ui.IPageLayout;
+import org.eclipse.ui.IPerspectiveFactory;
+
+
+public class Perspective implements IPerspectiveFactory {
+
+
+ public Perspective() {
+ }
+
+
+ @Override
+ public void createInitialLayout(final IPageLayout layout) {
+ layout.setEditorAreaVisible(false);
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
new file mode 100644
index 0000000..e268ed6
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/GraphDemoView.java
@@ -0,0 +1,188 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import static org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet.CONTEXT_MENU_GROUP_ID;
+import static org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet.SIZE_MENU_GROUP_ID;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.action.IToolBarManager;
+import org.eclipse.jface.action.Separator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.services.IServiceLocator;
+
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.eclient.core.AbstractRToolRunnable;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.eclient.graphics.ERGraphic;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicComposite;
+import org.eclipse.statet.rj.eclient.graphics.RGraphicCompositeActionSet;
+import org.eclipse.statet.rj.graphic.core.RGraphic;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+
+
+/**
+ * View for R plots using RJ graphic device (rj.gd) and SWT rendering.
+ *
+ * Note: All field access occur in display thread.
+ */
+public class GraphDemoView extends ViewPart {
+
+
+ public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.GraphDemo";
+
+
+ private Text commandControl;
+
+ private RGraphicComposite imageControl;
+
+ private ERGraphic currentPlot;
+
+ private RGraphicCompositeActionSet actionSet;
+
+
+ public GraphDemoView() {
+ }
+
+
+ @Override
+ public void createPartControl(final Composite parent) {
+ final Composite composite= new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout(3, false));
+
+ final Label label= new Label(composite, SWT.LEFT);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ label.setText("Graphic &command:");
+
+ this.commandControl= new Text(composite, SWT.BORDER);
+ this.commandControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+
+ final Button button= new Button(composite, SWT.PUSH);
+ button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));
+ button.setText("Run");
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ run();
+ }
+ });
+
+ this.commandControl.setText("hist(rnorm(1e+07))");
+
+ this.imageControl= new RGraphicComposite(composite, null);
+ this.imageControl.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
+
+ initActions(getViewSite());
+ contributeToActionsBars(getViewSite(), getViewSite().getActionBars());
+ }
+
+ protected void initActions(final IServiceLocator serviceLocator) {
+ this.actionSet= new RGraphicCompositeActionSet(this.imageControl) {
+ @Override
+ public void contributeToActionsBars(final IServiceLocator serviceLocator, final IActionBars actionBars) {
+ super.contributeToActionsBars(serviceLocator, actionBars);
+
+ addSizeActions(serviceLocator, actionBars);
+ addTestLocator(serviceLocator, actionBars);
+ }
+ };
+ this.actionSet.initActions(serviceLocator);
+ }
+
+ protected void contributeToActionsBars(final IServiceLocator serviceLocator,
+ final IActionBars actionBars) {
+ final IToolBarManager toolBar= actionBars.getToolBarManager();
+ toolBar.add(new Separator("additions"));
+ toolBar.insertBefore("additions", new Separator(CONTEXT_MENU_GROUP_ID));
+ toolBar.insertBefore("additions", new Separator(SIZE_MENU_GROUP_ID));
+
+ this.actionSet.contributeToActionsBars(serviceLocator, actionBars);
+ }
+
+ protected void setGraphic(final ERGraphic graphic) {
+ this.imageControl.setGraphic(graphic);
+ this.actionSet.setGraphic(graphic);
+
+ if (this.currentPlot != null) {
+ this.currentPlot.close();
+ this.currentPlot= null;
+ }
+ this.currentPlot= graphic;
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (this.currentPlot != null) {
+ this.currentPlot.close();
+ this.currentPlot= null;
+ }
+ }
+
+ @Override
+ public void setFocus() {
+ this.commandControl.setFocus();
+ }
+
+ private void run() {
+ final Point size= this.imageControl.getSize();
+ final String command= this.commandControl.getText();
+ final ToolRunnable job= new AbstractRToolRunnable("r/demo/graphic", "Graphic Demo") {
+ @Override
+ protected void run(final RToolService r,
+ final IProgressMonitor monitor) throws CoreException {
+ monitor.beginTask("Creating graphic in R...", 100);
+
+ final RGraphicCreator rGraphicCreator= r.createRGraphicCreator(0);
+ rGraphicCreator.setSize(size.x, size.y);
+ final RGraphic plot= rGraphicCreator.create(command, monitor);
+
+ monitor.worked(90);
+
+ if (plot instanceof ERGraphic) {
+ final ERGraphic erPlot= (ERGraphic) plot;
+ PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ if (GraphDemoView.this.imageControl.isDisposed()) {
+ erPlot.close();
+ return;
+ }
+ setGraphic(erPlot);
+ }
+ });
+ }
+ return;
+ }
+ };
+ Activator.getInstance().getRServiManager().scheduleDemo(job);
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
new file mode 100644
index 0000000..4f61d7d
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/internal/rj/servi/rcpdemo/views/RServiConfigView.java
@@ -0,0 +1,154 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.rcpdemo.views;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.DirectoryDialog;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.part.ViewPart;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.servi.rcpdemo.RServiManager;
+
+
+public class RServiConfigView extends ViewPart {
+
+
+ public static final String VIEW_ID= "org.eclipse.statet.rj.servi.rcpdemo.views.RServiConfig";
+
+
+ private Button remoteSelectControl;
+ private Text remoteAddressControl;
+ private Button localSelectControl;
+ private Text localRhomeControl;
+ private Button rsetupSelectControl;
+ private Text rsetupIdControl;
+
+
+ public RServiConfigView() {
+ }
+
+
+ @Override
+ public void createPartControl(final Composite parent) {
+ final Composite composite= new Composite(parent, SWT.NONE);
+ composite.setLayout(new GridLayout());
+
+ this.remoteSelectControl= new Button(composite, SWT.RADIO);
+ this.remoteSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ this.remoteSelectControl.setText("Remote/Pool - RMI pool address:");
+
+ { this.remoteAddressControl= new Text(composite, SWT.BORDER);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd.horizontalIndent= 10;
+ this.remoteAddressControl.setLayoutData(gd);
+ }
+
+ this.localSelectControl= new Button(composite, SWT.RADIO);
+ this.localSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ this.localSelectControl.setText("Local - R_HOME:");
+
+ { this.localRhomeControl= new Text(composite, SWT.BORDER);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd.horizontalIndent= 10;
+ this.localRhomeControl.setLayoutData(gd);
+ }
+
+ { final Button button= new Button(composite, SWT.PUSH);
+ button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ button.setText("Select...");
+ button.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ final DirectoryDialog dialog= new DirectoryDialog(button.getShell());
+ dialog.setMessage("Select R_HOME directory:");
+ final String path= dialog.open();
+ if (path != null) {
+ RServiConfigView.this.localRhomeControl.setText(path);
+ }
+ }
+ });
+ }
+
+ this.rsetupSelectControl= new Button(composite, SWT.RADIO);
+ this.rsetupSelectControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ this.rsetupSelectControl.setText("Supplied R Setup - Id:");
+
+ { this.rsetupIdControl= new Text(composite, SWT.BORDER);
+ final GridData gd= new GridData(SWT.FILL, SWT.CENTER, true, false);
+ gd.horizontalIndent= 10;
+ this.rsetupIdControl.setLayoutData(gd);
+ }
+
+ final Label label= new Label(composite, SWT.NONE);
+ label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
+
+ final Button applyControl= new Button(composite, SWT.PUSH);
+ applyControl.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
+ applyControl.setText("Apply");
+ applyControl.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(final SelectionEvent e) {
+ applyConfig();
+ }
+ });
+
+ this.remoteSelectControl.setSelection(true);
+ this.remoteAddressControl.setText("rmi://localhost/rservi-pool");
+ final String rhome= System.getenv("R_HOME");
+ this.localRhomeControl.setText((rhome != null) ? rhome : "");
+ this.rsetupIdControl.setText("org.rproject.r.DefaultSetup");
+ }
+
+ @Override
+ public void setFocus() {
+ }
+
+ private void applyConfig() {
+ try {
+ final RServiManager manager= Activator.getInstance().getRServiManager();
+ if (this.remoteSelectControl.getSelection()) {
+ manager.setPool(this.remoteAddressControl.getText());
+ return;
+ }
+ if (this.localSelectControl.getSelection()) {
+ manager.setLocalInst(this.localRhomeControl.getText());
+ return;
+ }
+ if (this.rsetupSelectControl.getSelection()) {
+ manager.setRSetup(this.rsetupIdControl.getText());
+ return;
+ }
+ }
+ catch (final CoreException e) {
+ StatusManager.getManager().handle(new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+ "Could not apply RServi configuration.", e),
+ StatusManager.SHOW | StatusManager.LOG);
+ }
+ return;
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
new file mode 100644
index 0000000..f8635ed
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiManager.java
@@ -0,0 +1,278 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+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.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistryManager;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.eclient.graphics.comclient.ERClientGraphicActionsFactory;
+import org.eclipse.statet.rj.rsetups.RSetup;
+import org.eclipse.statet.rj.rsetups.RSetupUtil;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.server.osgi.ERJContext;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.node.RServiImpl;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+
+
+public class RServiManager implements Disposable {
+
+
+ private static final int LOCAL_INST= 1;
+ private static final int LOCAL_RSETUP= 2;
+ private static final int POOL= 3;
+
+ private static class Config {
+
+ private int mode;
+ private String address;
+
+ }
+
+
+ private final String name;
+
+ private Config config= new Config();
+
+ private RServiNodeManager localR;
+
+ private RServiSession currentSession;
+ private final List<RServiSession> runningSessions= new ArrayList<>();
+
+
+ public RServiManager(final String appId, final RClientGraphicFactory graphicFactory) {
+ this.name= appId;
+
+ RjsComConfig.setProperty("rj.servi.graphicFactory", graphicFactory);
+ RjsComConfig.setProperty("rj.servi.comClientGraphicActionsFactory",
+ new ERClientGraphicActionsFactory() );
+ }
+
+
+ public void setLocalInst(final String rHome) throws CoreException {
+ closeRServiSession();
+
+ final Config config= new Config();
+ config.mode= LOCAL_INST;
+ config.address= rHome;
+ this.config= config;
+
+ final RServiNodeConfig rConfig= new RServiNodeConfig();
+ rConfig.setRHome(rHome);
+ rConfig.setEnableVerbose(true);
+
+ startLocal(rConfig);
+ }
+
+ public void setRSetup(final String setupId) throws CoreException {
+ closeRServiSession();
+
+ final Config config= new Config();
+ config.mode= LOCAL_RSETUP;
+ config.address= setupId;
+ this.config= config;
+
+ final RSetup setup= RSetupUtil.loadSetup(setupId, null);
+ if (setup == null) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "No R setup with specified id found."));
+ }
+
+ final RServiNodeConfig rConfig= new RServiNodeConfig();
+ rConfig.setRHome(setup.getRHome());
+ setLibs(setup.getRLibsSite(), rConfig, "R_LIBS_SITE");
+ setLibs(setup.getRLibs(), rConfig, "R_LIBS");
+ setLibs(setup.getRLibsUser(), rConfig, "R_LIBS_USER");
+ rConfig.setEnableVerbose(true);
+
+ startLocal(rConfig);
+ }
+
+ public void setPool(final String poolAddress) {
+ closeRServiSession();
+
+ final Config config= new Config();
+ config.mode= POOL;
+ config.address= poolAddress;
+ this.config= config;
+ }
+
+
+ private void setLibs(final List<String> locations, final RServiNodeConfig rConfig, final String varName) {
+ if (locations != null && locations.size() > 0) {
+ final StringBuilder sb= new StringBuilder(locations.get(0));
+ for (int i= 0; i < locations.size(); i++) {
+ sb.append(File.pathSeparatorChar);
+ sb.append(locations.get(i));
+ }
+ rConfig.getEnvironmentVariables().put(varName, sb.toString());
+ }
+ }
+
+ private void startLocal(final RServiNodeConfig rConfig) throws CoreException {
+ startLocal(rConfig, new NullProgressMonitor()); // TODO real monitor, e.g. in a Job
+ }
+
+ private void startLocal(final RServiNodeConfig rConfig,
+ final IProgressMonitor monitor) throws CoreException {
+ if (rConfig == null) {
+ throw new NullPointerException("rConfig");
+ }
+ if (monitor == null) {
+ throw new NullPointerException("monitor");
+ }
+ try {
+ final ERJContext context= new ERJContext();
+ if (System.getSecurityManager() == null) {
+ if (System.getProperty("java.security.policy") == null) {
+ final String policyFile= context.getServerPolicyFilePath();
+ System.setProperty("java.security.policy", policyFile);
+ }
+ System.setSecurityManager(new SecurityManager());
+ }
+
+ final RMIRegistry registry= RMIRegistryManager.INSTANCE.getEmbeddedPrivateRegistry(monitor);
+
+ final RServiNodeFactory nodeFactory= RServiImpl.createLocalNodeFactory(this.name, context);
+ nodeFactory.setRegistry(registry);
+ nodeFactory.setConfig(rConfig);
+
+ final RServiNodeManager newLocalR= RServiImpl.createNodeManager(this.name, registry, nodeFactory);
+ newLocalR.start();
+ if (this.localR != null) {
+ this.localR.stop();
+ this.localR= null;
+ }
+ this.localR= newLocalR;
+ }
+ catch (final RjException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "Local R instance could not created.", e));
+ }
+ }
+
+
+ public synchronized Tool getRServiSession() throws CoreException {
+ if (this.currentSession == null) {
+ final RServi servi= getRServi("session");
+ this.currentSession= new RServiSession(servi) {
+ @Override
+ protected void terminated() {
+ synchronized (RServiManager.this.runningSessions) {
+ RServiManager.this.runningSessions.remove(this);
+ }
+ }
+ };
+ synchronized (this.runningSessions) {
+ this.runningSessions.add(this.currentSession);
+ }
+ }
+ return this.currentSession;
+ }
+
+ private void closeRServiSession() {
+ if (this.currentSession != null) {
+ this.currentSession.close(false);
+ this.currentSession= null;
+ }
+ }
+
+
+ public void schedule(final ToolRunnable runnable) throws CoreException {
+ final Tool session= getRServiSession();
+ final IStatus status;
+ if (session != null) {
+ status= session.getQueue().add(runnable);
+ }
+ else {
+ status= new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+ "R engine not available.");
+ }
+ if (!status.isOK()) {
+ throw new CoreException(status);
+ }
+ }
+
+ public void scheduleDemo(final ToolRunnable runnable) {
+ try {
+ schedule(runnable);
+ }
+ catch (final CoreException e) {
+ final Status status= new Status(e.getStatus().getSeverity(), Activator.BUNDLE_ID,
+ "Cannot schedule '" + runnable.getLabel() + "'", e);
+ StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
+ }
+ }
+
+ @Override
+ public void dispose() {
+ this.config= new Config();
+ final RServiSession[] sessions;
+ synchronized (this.runningSessions) {
+ sessions= this.runningSessions.toArray(new RServiSession[this.runningSessions.size()]);
+ }
+ for (final RServiSession session : sessions) {
+ session.close(true);
+ }
+ }
+
+ private RServi getRServi(final String task) throws CoreException {
+ final Config config= this.config;
+ final String key= this.name + "-" + task;
+
+ try {
+ switch (config.mode) {
+ case LOCAL_INST:
+ case LOCAL_RSETUP:
+ return RServiUtil.getRServi(this.localR, key);
+ case POOL:
+ return RServiUtil.getRServi(config.address, key);
+ }
+ }
+ catch (final CoreException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+ }
+ catch (final LoginException e) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R not available, please check the configuration.", e));
+ }
+ catch (final NoSuchElementException e) {
+ throw new CoreException(new Status(IStatus.INFO, Activator.BUNDLE_ID, "R currently not available, please try again later.", e));
+ }
+ throw new CoreException(new Status(IStatus.ERROR, Activator.BUNDLE_ID, "R is not configured, please check the configuration."));
+ }
+
+}
diff --git a/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiSession.java b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiSession.java
new file mode 100644
index 0000000..f964e2b
--- /dev/null
+++ b/examples/org.eclipse.statet.rj.servi.rcpdemo2/src/org/eclipse/statet/rj/servi/rcpdemo/RServiSession.java
@@ -0,0 +1,421 @@
+/*=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.rcpdemo;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+import org.eclipse.statet.ecommons.ts.core.SystemRunnable;
+import org.eclipse.statet.ecommons.ts.core.Tool;
+import org.eclipse.statet.ecommons.ts.core.ToolQueue;
+import org.eclipse.statet.ecommons.ts.core.ToolRunnable;
+import org.eclipse.statet.ecommons.ts.core.ToolService;
+
+import org.eclipse.statet.internal.rj.servi.RServiImpl;
+import org.eclipse.statet.internal.rj.servi.rcpdemo.Activator;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.eclient.core.RToolService;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Implementations of ECommons Tool Service and Scheduling interfaces (org.eclipse.statet.ecommons.ts.core) for
+ * RServi using Eclipse jobs.
+ */
+public class RServiSession extends PlatformObject implements Tool {
+
+
+ private class Queue implements ToolQueue {
+
+ @Override
+ public IStatus add(final ToolRunnable runnable) {
+ synchronized (RServiSession.this.jobs) {
+ if (isTerminated()) {
+ return new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+ "The R session is terminated.");
+ }
+ if (!runnable.changed(ToolRunnable.ADDING_TO, RServiSession.this)) {
+ return Status.CANCEL_STATUS;
+ }
+ final RunnableJob job= new RunnableJob(runnable);
+ RServiSession.this.jobs.add(job);
+ job.addJobChangeListener(RServiSession.this.jobListener);
+ job.schedule();
+ return Status.OK_STATUS;
+ }
+ }
+
+ @Override
+ public void remove(final ToolRunnable runnable) {
+ RunnableJob removed= null;
+ synchronized (RServiSession.this.jobs) {
+ for (int i= 0; i < RServiSession.this.jobs.size(); i++) {
+ final RunnableJob job= RServiSession.this.jobs.get(i);
+ if (job.runnable == runnable) {
+ if (job.runnable.changed(ToolRunnable.REMOVING_FROM, RServiSession.this)) {
+ removed= job;
+ RServiSession.this.jobs.remove(i);
+ break;
+ }
+ return;
+ }
+ }
+ }
+ if (removed != null) {
+ removed.cancel();
+ }
+ }
+
+ @Override
+ public boolean isHotSupported() {
+ return false;
+ }
+
+ @Override
+ public IStatus addHot(final ToolRunnable runnable) {
+ return add(runnable);
+ }
+
+ @Override
+ public void removeHot(final ToolRunnable runnable) {
+ remove(runnable);
+ }
+
+ }
+
+ private class RServiService implements RToolService, RService, ToolService {
+
+ @Override
+ public Tool getTool() {
+ return RServiSession.this;
+ }
+
+ @Override
+ public RPlatform getPlatform() {
+ return RServiSession.this.servi.getPlatform();
+ }
+
+ @Override
+ public void evalVoid(final String expression,
+ final IProgressMonitor monitor) throws CoreException {
+ RServiSession.this.servi.evalVoid(expression, monitor);
+ }
+
+ @Override
+ public void evalVoid(final String expression, final RObject envir,
+ final IProgressMonitor monitor) throws CoreException {
+ RServiSession.this.servi.evalVoid(expression, envir, monitor);
+ }
+
+ @Override
+ public RObject evalData(final String expression,
+ final IProgressMonitor monitor) throws CoreException {
+ return RServiSession.this.servi.evalData(expression, monitor);
+ }
+
+ @Override
+ public RObject evalData(final String expression,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ return RServiSession.this.servi.evalData(expression, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public RObject evalData(final String expression, final RObject envir,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ return RServiSession.this.servi.evalData(expression, envir, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public RObject evalData(final RReference reference,
+ final IProgressMonitor monitor) throws CoreException {
+ return RServiSession.this.servi.evalData(reference, monitor);
+ }
+
+ @Override
+ public RObject evalData(final RReference reference,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ return RServiSession.this.servi.evalData(reference, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public void assignData(final String expression, final RObject data,
+ final IProgressMonitor monitor) throws CoreException {
+ RServiSession.this.servi.assignData(expression, data, monitor);
+ }
+
+ @Override
+ public void uploadFile(final InputStream in, final long length, final String fileName,
+ final int options, final IProgressMonitor monitor) throws CoreException {
+ RServiSession.this.servi.uploadFile(in, length, fileName, options, monitor);
+ }
+
+ @Override
+ public void downloadFile(final OutputStream out, final String fileName, final int options,
+ final IProgressMonitor monitor) throws CoreException {
+ RServiSession.this.servi.downloadFile(fileName, options, monitor);
+ }
+
+ @Override
+ public byte[] downloadFile(final String fileName, final int options,
+ final IProgressMonitor monitor) throws CoreException {
+ return RServiSession.this.servi.downloadFile(fileName, options, monitor);
+ }
+
+ @Override
+ public FunctionCall createFunctionCall(final String name) throws CoreException {
+ return RServiSession.this.servi.createFunctionCall(name);
+ }
+
+ @Override
+ public RGraphicCreator createRGraphicCreator(final int options) throws CoreException {
+ return RServiSession.this.servi.createRGraphicCreator(options);
+ }
+
+ }
+
+ private class RunnableJob extends Job {
+
+ private final ToolRunnable runnable;
+
+ public RunnableJob(final ToolRunnable runnable) {
+ super(runnable.getLabel());
+ this.runnable= runnable;
+ setRule(RServiSession.this.schedulingRule);
+ if (runnable instanceof SystemRunnable) {
+ setSystem(true);
+ }
+ }
+
+ @Override
+ public boolean belongsTo(final Object family) {
+ return (family == RServiSession.this);
+ }
+
+ @Override
+ public boolean shouldRun() {
+ synchronized (RServiSession.this.jobs) {
+ return RServiSession.this.jobs.remove(this);
+ }
+ }
+
+ @Override
+ protected IStatus run(final IProgressMonitor monitor) {
+ try {
+ this.runnable.run(RServiSession.this.service, monitor);
+ this.runnable.changed(ToolRunnable.FINISHING_OK, RServiSession.this);
+ return Status.OK_STATUS;
+ }
+ catch (final CoreException e) {
+ if (e.getStatus() != null && e.getStatus().getSeverity() == IStatus.CANCEL) {
+ this.runnable.changed(ToolRunnable.FINISHING_CANCEL, RServiSession.this);
+ return e.getStatus();
+ }
+ final Status status= new Status(IStatus.ERROR, Activator.BUNDLE_ID,
+ "An error occurred when running " + getName() + ".", e);
+ StatusManager.getManager().handle(status, StatusManager.SHOW | StatusManager.LOG);
+ this.runnable.changed(ToolRunnable.FINISHING_ERROR, RServiSession.this);
+ return status;
+ }
+ }
+
+ }
+
+ private class JobListener implements IJobChangeListener {
+
+ @Override
+ public void aboutToRun(final IJobChangeEvent event) {
+ }
+
+ @Override
+ public void awake(final IJobChangeEvent event) {
+ }
+
+ @Override
+ public void done(final IJobChangeEvent event) {
+ if (event.getResult() == Status.CANCEL_STATUS) {
+ synchronized (RServiSession.this.jobs) {
+ if (RServiSession.this.jobs.remove(event.getJob())) {
+ ((RunnableJob) event.getJob()).runnable.changed(ToolRunnable.BEING_ABANDONED, RServiSession.this);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void running(final IJobChangeEvent event) {
+ }
+
+ @Override
+ public void scheduled(final IJobChangeEvent event) {
+ }
+
+ @Override
+ public void sleeping(final IJobChangeEvent event) {
+ }
+
+ }
+
+
+ private final Queue queue= new Queue();
+ private final RServiService service= new RServiService();
+ private final String label;
+
+ private final ISchedulingRule schedulingRule;
+ private int state;
+ private RServi servi;
+
+ private final List<RunnableJob> jobs= new ArrayList<>();
+ private final IJobChangeListener jobListener= new JobListener();
+
+
+ public RServiSession(final RServi servi) {
+ this("R engine", servi, new ISchedulingRule() {
+ @Override
+ public boolean contains(final ISchedulingRule rule) {
+ return (rule == this);
+ }
+ @Override
+ public boolean isConflicting(final ISchedulingRule rule) {
+ return (rule == this);
+ }
+ });
+ }
+
+ public RServiSession(final String label,
+ final RServi servi, final ISchedulingRule schedulingRule) {
+ this.label= label;
+ this.servi= servi;
+ this.schedulingRule= schedulingRule;
+
+ doStart();
+ }
+
+
+ @Override
+ public String getMainType() {
+ return "R";
+ }
+
+ @Override
+ public boolean isProvidingFeatureSet(final String featureSetId) {
+ return "org.eclipse.statet.rj.services.RService".equals(featureSetId); //$NON-NLS-1$
+ }
+
+ @Override
+ public ToolQueue getQueue() {
+ return this.queue;
+ }
+
+ @Override
+ public boolean isTerminated() {
+ return (this.state < 0);
+ }
+
+ private void doStart() {
+ if (this.servi != null) {
+ ((RServiImpl) this.servi).setRHandle(this);
+ this.state= 1;
+ }
+ else {
+ doTerminate();
+ }
+ }
+
+ private void doTerminate() {
+ if (this.servi != null) {
+ try {
+ this.servi.close();
+ }
+ catch (final CoreException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ this.servi= null;
+ }
+ if (this.state != -2) {
+ this.state= -2;
+ terminated();
+ }
+ }
+
+ protected void terminated() {
+ }
+
+ @Override
+ public String getLabel(final int config) {
+ return this.label;
+ }
+
+ public void close(final boolean immediately) {
+ synchronized (this.jobs) {
+ if (this.state < 0) {
+ return;
+ }
+ if (immediately) {
+ Job.getJobManager().cancel(this);
+ for (int i= 0; i < this.jobs.size(); i++) {
+ this.jobs.get(i).runnable.changed(ToolRunnable.BEING_ABANDONED, RServiSession.this);
+ }
+ this.jobs.clear();
+ }
+ this.queue.add(new SystemRunnable() {
+ @Override
+ public String getTypeId() {
+ return "r/session/close";
+ }
+ @Override
+ public String getLabel() {
+ return "Close R Session";
+ }
+ @Override
+ public boolean canRunIn(final Tool tool) {
+ return (tool == RServiSession.this);
+ }
+ @Override
+ public boolean changed(final int event, final Tool tool) {
+ return true;
+ }
+ @Override
+ public void run(final ToolService service,
+ final IProgressMonitor monitor) throws CoreException {
+ doTerminate();
+ }
+ });
+ this.state= -1;
+ }
+ }
+
+}
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/democlient/startup.bat b/servi/_build/org.eclipse.statet.rj.servi-devbundle/democlient/startup.bat
new file mode 100644
index 0000000..d4fcf7d
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/democlient/startup.bat
@@ -0,0 +1 @@
+java -cp "*" org.eclipse.statet.rj.servi.demo.DemoApp
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/devbundle.xml b/servi/_build/org.eclipse.statet.rj.servi-devbundle/devbundle.xml
new file mode 100644
index 0000000..45ad5b0
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/devbundle.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+ <id>distr</id>
+
+ <formats>
+ <format>zip</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <files>
+ <file>
+ <source>info.txt</source>
+ </file>
+ </files>
+ <fileSets>
+ <fileSet>
+ <directory>/</directory>
+ <includes>
+ <include>info.txt</include>
+ <include>democlient/**</include>
+ <include>sprojects/**</include>
+ <include>eprojects/**</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+
+ <dependencySets>
+
+ <dependencySet>
+ <outputDirectory>rservi</outputDirectory>
+ <useTransitiveDependencies>false</useTransitiveDependencies>
+ <includes>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.servi.webapp</include>
+ </includes>
+ <unpack>true</unpack>
+ </dependencySet>
+
+ <dependencySet>
+ <outputDirectory>democlient</outputDirectory>
+ <useTransitiveDependencies>false</useTransitiveDependencies>
+ <includes>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.data</include>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.server</include>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.client</include>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.services.eruntime</include>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.servi</include>
+ <include>org.eclipse.statet.rj:org.eclipse.statet.rj.servi.demo</include>
+ <!-- +SWT ? -->
+ </includes>
+ <outputFileNameMapping>${artifact.artifactId}_${artifact.version}.${artifact.extension}</outputFileNameMapping>
+ </dependencySet>
+
+ <dependencySet>
+ <outputDirectory>sprojects</outputDirectory>
+ <useTransitiveDependencies>false</useTransitiveDependencies>
+ <includes>
+ <include>org.eclipse.statet.rj:rj-core</include>
+ <include>org.eclipse.statet.rj:rj-client</include>
+ <include>org.eclipse.statet.rj:rj-servi</include>
+ <!-- +SWT ? -->
+ </includes>
+ <unpack>true</unpack>
+ <unpackOptions>
+ <includes>
+ <include>org.eclipse.statet.rj.data/**</include>
+ <include>org.eclipse.statet.rj.server/**</include>
+ <include>org.eclipse.statet.rj.client/**</include>
+ <include>org.eclipse.statet.rj.services.eruntime/**</include>
+ <include>org.eclipse.statet.rj.servi/**</include>
+ <include>org.eclipse.statet.rj.servi.webapp/**</include>
+ <include>org.eclipse.statet.rj.servi.demo/**</include>
+ </includes>
+ </unpackOptions>
+ </dependencySet>
+
+ <dependencySet>
+ <outputDirectory>eprojects</outputDirectory>
+ <useTransitiveDependencies>false</useTransitiveDependencies>
+ <includes>
+ <include>org.eclipse.statet.rj:rj-servi</include>
+ </includes>
+ <unpack>true</unpack>
+ <unpackOptions>
+ <includes>
+ <include>org.eclipse.statet.rj.servi.rcpdemo/**</include>
+ <include>org.eclipse.statet.rj.servi.rcpdemo2/**</include>
+ </includes>
+ </unpackOptions>
+ </dependencySet>
+ <dependencySet>
+ <outputDirectory>eprojects/org.eclipse.statet.rj.devbundle/libs</outputDirectory>
+ <useTransitiveDependencies>false</useTransitiveDependencies>
+ <includes>
+ <include>org.eclipse.statet.rj-packaging:org.eclipse.statet.rj.servi-repo</include>
+ </includes>
+ <unpack>true</unpack>
+ </dependencySet>
+
+ </dependencySets>
+
+</assembly>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/.project b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/.project
new file mode 100644
index 0000000..00cd555
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.devbundle</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.source.target b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.source.target
new file mode 100644
index 0000000..184170f
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.source.target
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde version="3.6"?>
+
+<target name="Base RCP with RServices (with Sources)">
+ <locations>
+ <location id="org.eclipse.rcp" path="${eclipse_home}" type="Feature"/>
+ <location includeAllPlatforms="false" includeMode="planner" includeConfigurePhase="false"
+ type="InstallableUnit">
+ <repository location="platform:/resource/org.eclipse.statet.rj.devbundle/libs/"/>
+ <unit id="org.eclipse.statet.rj.servi.e.sdk.feature.group" version="0.0.0"/>
+ </location>
+ </locations>
+</target>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.target b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.target
new file mode 100644
index 0000000..28e6db5
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/eprojects/org.eclipse.statet.rj.devbundle/rcp-rj.target
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde version="3.6"?>
+
+<target name="Base RCP with RServices (Binary only)">
+ <locations>
+ <location id="org.eclipse.rcp" path="${eclipse_home}" type="Feature"/>
+ <location includeAllPlatforms="false" includeMode="planner" includeConfigurePhase="false"
+ type="InstallableUnit">
+ <repository location="platform:/resource/org.eclipse.statet.rj.devbundle/libs/"/>
+ <unit id="org.eclipse.statet.rj.servi.e.feature.group" version="0.0.0"/>
+ </location>
+ </locations>
+</target>
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/info.txt b/servi/_build/org.eclipse.statet.rj.servi-devbundle/info.txt
new file mode 100644
index 0000000..84b367f
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/info.txt
@@ -0,0 +1,55 @@
+(RJ) RServi Development Bundle
+
+== Requirement for all RJ setups ==
+
+The R packages 'rj' and 'rj.gd' (for graphics) must be installed in an R library.
+
+
+== Content ==
+
+rservi/
+ (rservi web application)
+ Web application providing an RServi pool configurable via web and or JMX.
+ The pool id is the web context name (so by default rservi).
+
+ To start the pool using Tomcat:
+ 1. Put it into the 'webapps' directory of Tomcat
+ 2. Start Tomcat
+ 3. Open the configuration interface in a browser:
+ http://localhost:8080/rservi
+
+ The WEB-INF/lib folder can be used also for the standalone server
+ providing an RServi pool configurable via JMX:
+ java -cp "*" org.eclipse.statet.rj.servi.pool.StandalonePoolServer <id>
+ See also the JavaDoc of org.eclipse.statet.rj.servi.pool.StandalonePoolServer.
+
+democlient/
+ (demo client)
+ Binaries of a small demo client to connect to an RServi pool
+
+ 1. Copy the SWT bundles for your platform into the directory.
+ 2. To start the client run:
+ java -cp "*" org.eclipse.statet.rj.servi.demo.DemoApp
+
+sprojects/
+ (source snapshot / webapp+democlient projects)
+ Eclipse projects with all sources of the web application and demo client
+ above
+
+ 1. Import the projects using the import wizard 'Existing projects into
+ Workspace'
+ 2. The rj.server project depends on the JRI API. Add the JRI library to the
+ build path, if required.
+
+ To absolutely exclude all Eclipse dependencies, remove the source folders
+ named 'srcEExtensions' from the build-/class-path.
+
+eprojects/
+ (eclipse rcp projects)
+ Eclipse plug-ins (Osgi bundles) relevant for Eclipse RCP client development
+ and the Eclipse project of the RCP demo application
+
+ 1. Import the projects using the import wizard 'Existing projects into
+ Workspace'
+ 2. Load the plug-in target definition 'rcp-rj.source.target' located in the project
+ 'org.eclipse.statet.rj' project
diff --git a/servi/_build/org.eclipse.statet.rj.servi-devbundle/pom.xml b/servi/_build/org.eclipse.statet.rj.servi-devbundle/pom.xml
new file mode 100644
index 0000000..7907c9f
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi-devbundle/pom.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>rj-servi</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.eclipse.statet.rj-packaging</groupId>
+ <artifactId>org.eclipse.statet.rj.servi-devbundle</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>rj-core</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <classifier>module-snapshot</classifier>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>rj-client</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <classifier>module-snapshot</classifier>
+ <type>zip</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>rj-servi</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <classifier>module-snapshot</classifier>
+ <type>zip</type>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.data</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>eclipse-plugin</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.server</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>eclipse-plugin</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.client</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>eclipse-plugin</type>
+ </dependency>
+
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.services.eruntime</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.servi</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.servi.webapp</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>war</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj-packaging</groupId>
+ <artifactId>org.eclipse.statet.rj.servi-repo</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <type>eclipse-repository</type>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.servi.demo</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.servi.rcpdemo</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.servi.rcpdemo2</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>2.4</version>
+ <executions>
+ <execution>
+ <id>pack-bundle</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ <configuration>
+ <descriptors>
+ <descriptor>devbundle.xml</descriptor>
+ </descriptors>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/.project b/servi/_build/org.eclipse.statet.rj.servi.e-feature/.project
new file mode 100644
index 0000000..a2dff0c
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.servi.e-feature</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.pde.FeatureBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.FeatureNature</nature>
+ </natures>
+</projectDescription>
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/build.properties b/servi/_build/org.eclipse.statet.rj.servi.e-feature/build.properties
new file mode 100644
index 0000000..7f1f3e9
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/build.properties
@@ -0,0 +1,2 @@
+bin.includes= feature.xml,\
+ feature.properties
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.properties b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.properties
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.properties
diff --git a/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.xml b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.xml
new file mode 100644
index 0000000..830e991
--- /dev/null
+++ b/servi/_build/org.eclipse.statet.rj.servi.e-feature/feature.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<feature
+ id="org.eclipse.statet.rj.servi.e"
+ version="2.1.0.qualifier"
+ label="StatET RJ - RServi E-Compilation"
+ provider-name="Eclipse.org"
+ license-feature="org.eclipse.license"
+ license-feature-version="1.0.1">
+
+ <description url="https://www.eclipse.org/statet">
+ Compilation for RServi for projects based on the Eclipse Workbench
+ </description>
+
+ <copyright>
+ Copyright (c) 2003, 2017 Stephan Wahlbrink and others. All rights reserved.
+ </copyright>
+
+ <license url="%license_url">
+ %license_text
+ </license>
+
+ <includes
+ id="org.eclipse.statet.rj.core"
+ version="0.0.0"/>
+
+ <includes
+ id="org.eclipse.statet.rj.eclient.core"
+ version="0.0.0"/>
+
+ <plugin
+ id="org.eclipse.statet.rj.servi"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+</feature>
diff --git a/servi/_build/repo/category.xml b/servi/_build/repo/category.xml
new file mode 100644
index 0000000..8f4ba9f
--- /dev/null
+++ b/servi/_build/repo/category.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<site>
+ <category-def name="org.eclipse.statet.libs" label="StatET - Libraries"/>
+ <category-def name="org.eclipse.statet.sources" label="StatET - Sources"/>
+
+ <feature id="org.eclipse.statet.ecommons.e" version="0.0.0">
+ <category name="org.eclipse.statet.libs"/>
+ </feature>
+ <feature id="org.eclipse.statet.ecommons.e.source" version="0.0.0">
+ <category name="org.eclipse.statet.sources"/>
+ </feature>
+
+ <feature id="org.eclipse.statet.rj.core" version="0.0.0">
+ <category name="org.eclipse.statet.libs"/>
+ </feature>
+ <feature id="org.eclipse.statet.rj.core.source" version="0.0.0">
+ <category name="org.eclipse.statet.sources"/>
+ </feature>
+ <feature id="org.eclipse.statet.rj.eclient.core" version="0.0.0">
+ <category name="org.eclipse.statet.libs"/>
+ </feature>
+ <feature id="org.eclipse.statet.rj.eclient.core.source" version="0.0.0">
+ <category name="org.eclipse.statet.sources"/>
+ </feature>
+
+ <feature id="org.eclipse.statet.rj.servi.e" version="0.0.0">
+ <category name="org.eclipse.statet.libs"/>
+ </feature>
+ <feature id="org.eclipse.statet.rj.servi.e.source" version="0.0.0">
+ <category name="org.eclipse.statet.sources"/>
+ </feature>
+
+</site>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.classpath b/servi/org.eclipse.statet.rj.servi.webapp/.classpath
new file mode 100644
index 0000000..168a660
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.classpath
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+ <attributes>
+ <attribute name="owner.project.facets" value="java"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
+ <classpathentry kind="con" path="org.eclipse.jst.server.core.container/org.eclipse.jst.server.tomcat.runtimeTarget/tomcat-6">
+ <attributes>
+ <attribute name="owner.project.facets" value="jst.web"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/jsf-1.2">
+ <attributes>
+ <attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
+ <attribute name="owner.project.facets" value="jst.jsf"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/jstl-1.2">
+ <attributes>
+ <attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
+ <attribute name="owner.project.facets" value="jst.jsf"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.equinox.common"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.gitignore b/servi/org.eclipse.statet.rj.servi.webapp/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.metadata/web/WEB-INF/faces-config.pageflow b/servi/org.eclipse.statet.rj.servi.webapp/.metadata/web/WEB-INF/faces-config.pageflow
new file mode 100644
index 0000000..bee5685
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.metadata/web/WEB-INF/faces-config.pageflow
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<pageflow:Pageflow xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pageflow="http://www.sybase.com/suade/pageflow" id="pf12465916868870" configfile="/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml">
+ <nodes xsi:type="pageflow:PFPage" name="conf-pool" x="122" y="178" id="pf12482896383170" referenceLink="//@navigationRule.1/@navigationCase.0/@toViewId|" path="/m/conf-pool.jsp"/>
+ <nodes xsi:type="pageflow:PFPage" name="conf-r" x="122" y="562" id="pf12482896383172" referenceLink="//@navigationRule.2/@navigationCase.0/@toViewId|" path="/m/conf-r.jsp"/>
+ <nodes xsi:type="pageflow:PFPage" name="m/*" x="122" y="946" id="pf12482896383174" referenceLink="//@navigationRule.3/@fromViewId|" path="/m/*"/>
+ <nodes xsi:type="pageflow:PFPage" name="m/status-poolnodes" x="122" y="1330" id="pf12482896383176" referenceLink="//@navigationRule.3/@navigationCase.0/@toViewId|" path="/m/status-poolnodes.jsp"/>
+ <nodes xsi:type="pageflow:PFPage" name="conf-pool" x="122" y="2098" id="pf13632771976130" referenceLink="//@navigationRule.1/@navigationCase.0/@toViewId|" outlinks="pf13632771976131" inlinks="pf13632771976131" path="/resources/conf-pool.jsp"/>
+ <nodes xsi:type="pageflow:PFPage" name="conf-r" x="122" y="2482" id="pf13632771976132" referenceLink="//@navigationRule.2/@navigationCase.0/@toViewId|" outlinks="pf13632771976133" inlinks="pf13632771976133" path="/resources/conf-r.jsp"/>
+ <nodes xsi:type="pageflow:PFPage" name="resources/*" x="122" y="1714" id="pf13632771976134" referenceLink="//@navigationRule.3/@fromViewId|" outlinks="pf13632771976135" path="/resources/*"/>
+ <nodes xsi:type="pageflow:PFPage" name="resources/status-poolnodes" x="338" y="1714" id="pf13632771976136" referenceLink="//@navigationRule.3/@navigationCase.0/@toViewId|" inlinks="pf13632771976135" path="/resources/status-poolnodes.jsp"/>
+ <links id="pf13632771976135" target="pf13632771976136" source="pf13632771976134" outcome="status-pool"/>
+ <links id="pf13632771976131" target="pf13632771976130" source="pf13632771976130" outcome="conf-pool">
+ <bendPoints d1Height="-36" d2Height="-36"/>
+ <bendPoints d1Width="-64" d1Height="-36" d2Width="-64" d2Height="-36"/>
+ <bendPoints d1Width="-64" d2Width="-64"/>
+ </links>
+ <links id="pf13632771976133" target="pf13632771976132" source="pf13632771976132" outcome="conf-r">
+ <bendPoints d1Height="-36" d2Height="-36"/>
+ <bendPoints d1Width="-64" d1Height="-36" d2Width="-64" d2Height="-36"/>
+ <bendPoints d1Width="-64" d2Width="-64"/>
+ </links>
+</pageflow:Pageflow>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.project b/servi/org.eclipse.statet.rj.servi.webapp/.project
new file mode 100644
index 0000000..25d9c38
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.project
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.servi.webapp</name>
+ <comment></comment>
+ <projects>
+ <project>org.eclipse.statet.jcommons.util</project>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.wst.jsdt.core.jsNature</nature>
+ </natures>
+</projectDescription>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/.jsdtscope b/servi/org.eclipse.statet.rj.servi.webapp/.settings/.jsdtscope
new file mode 100644
index 0000000..bbb8e68
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/.jsdtscope
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
+ <attributes>
+ <attribute name="hide" value="true"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
+ <classpathentry kind="output" path=""/>
+</classpath>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/oracle.eclipse.tools.webtier.ui.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/oracle.eclipse.tools.webtier.ui.prefs
new file mode 100644
index 0000000..9b1426c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/oracle.eclipse.tools.webtier.ui.prefs
@@ -0,0 +1,20 @@
+#Fri Jul 08 00:02:58 CEST 2011
+//_hiddenCategory_\:http\://java.sun.com/jsf/core=false
+//_hiddenCategory_\:http\://java.sun.com/jsf/html=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/core=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/fmt=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/sql=false
+//_hiddenCategory_\:http\://java.sun.com/jsp/jstl/xml=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/core=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/core_rt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/fmt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/fmt_rt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/sql=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/sql_rt=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/xml=false
+//_hiddenCategory_\:http\://java.sun.com/jstl/xml_rt=false
+//_hiddenCategory_\:http\://mojarra.dev.java.net/mojarra_ext=true
+_hiddenCategory_\:DataPalette=false
+_hiddenCategory_\:HTML=false
+_hiddenCategory_\:JSP11=false
+eclipse.preferences.version=1
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.resources.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.runtime.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.core.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.ui.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jst.jsp.core.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jst.jsp.core.prefs
new file mode 100644
index 0000000..69b0fc5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.jst.jsp.core.prefs
@@ -0,0 +1,27 @@
+#Sat Jun 13 18:01:19 CEST 2009
+eclipse.preferences.version=1
+validation.actions-missing-required-attribute=1
+validation.actions-non-empty-inline-tag=2
+validation.actions-unknown-attribute=2
+validation.directive-include-fragment-file-not-found=1
+validation.directive-include-fragment-file-not-specified=1
+validation.directive-taglib-duplicate-prefixes-different-uris=1
+validation.directive-taglib-duplicate-prefixes-same-uris=-1
+validation.directive-taglib-missing-prefix=1
+validation.directive-taglib-missing-uri-or-tagdir=1
+validation.directive-taglib-unresolvable-uri-or-tagdir=1
+validation.el-general-syntax=1
+validation.el-lexical-failure=-1
+validation.java-=-1
+validation.java-local-variable-is-never-used=-1
+validation.java-null-local-variable-reference=-1
+validation.java-potential-null-local-variable-reference=-1
+validation.java-unused-import=-1
+validation.translation-tag-class-not-found=2
+validation.translation-tei-class-not-found=2
+validation.translation-tei-class-not-instantiated=2
+validation.translation-tei-class-runtime-exception=2
+validation.translation-tei-message=1
+validation.translation-usebean-ambiguous-type-info=2
+validation.translation-usebean-invalid-id=1
+validation.translation-usebean-missing-type-info=1
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.ltk.core.refactoring.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..cc50da5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,3 @@
+#Mon Jun 15 10:42:38 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.component b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..ea03122
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="org.eclipse.statet.rj.servi.webapp">
+ <wb-resource deploy-path="/" source-path="/web"/>
+ <wb-resource deploy-path="/WEB-INF/classes" source-path="/src"/>
+ <dependent-module archiveName="org.eclipse.statet.ecommons.runtime.core.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.ecommons.runtime.core/org.eclipse.statet.ecommons.runtime.core">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="org.eclipse.statet.ecommons.rmi.core.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.ecommons.rmi.core/org.eclipse.statet.ecommons.rmi.core">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="org.eclipse.statet.rj.servi.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.servi/org.eclipse.statet.rj.servi">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="org.eclipse.statet.rj.client.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.client/org.eclipse.statet.rj.client">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="org.eclipse.statet.rj.services.core.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.services.core/org.eclipse.statet.rj.services.core">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="org.eclipse.statet.rj.data.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.data/org.eclipse.statet.rj.data">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="org.eclipse.statet.rj.server.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.rj.server/org.eclipse.statet.rj.server">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <dependent-module archiveName="org.eclipse.statet.jcommons.util.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/org.eclipse.statet.jcommons.util/org.eclipse.statet.jcommons.util">
+ <dependency-type>uses</dependency-type>
+ </dependent-module>
+ <property name="java-output-path"/>
+ <property name="context-root" value="rservi"/>
+ </wb-module>
+</project-modules>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..9b4b9fc
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,7 @@
+<root>
+ <facet id="jst.jsf">
+ <node name="libprov">
+ <attribute name="provider-id" value="jsf-user-library-provider"/>
+ </node>
+ </facet>
+</root>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.xml b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f1a2542
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <runtime name="tomcat-6"/>
+ <fixed facet="java"/>
+ <fixed facet="jst.web"/>
+ <installed facet="java" version="1.8"/>
+ <installed facet="jst.web" version="2.5"/>
+ <installed facet="jst.jsf" version="1.2"/>
+</faceted-project>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.container b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.name b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 0000000..05bd71b
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.ws.service.policy.prefs b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.ws.service.policy.prefs
new file mode 100644
index 0000000..e812326
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/.settings/org.eclipse.wst.ws.service.policy.prefs
@@ -0,0 +1,3 @@
+#Fri Jun 12 11:04:53 CEST 2009
+eclipse.preferences.version=1
+org.eclipse.wst.ws.service.policy.projectEnabled=false
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/about.html b/servi/org.eclipse.statet.rj.servi.webapp/about.html
new file mode 100644
index 0000000..7206cec
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/about.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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 <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+</p>
+
+<p>
+ 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 <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/pom.xml b/servi/org.eclipse.statet.rj.servi.webapp/pom.xml
new file mode 100644
index 0000000..e981f77
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/pom.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>rj-servi</artifactId>
+ <version>2.1-SNAPSHOT</version>
+ <relativePath>../_build</relativePath>
+ </parent>
+
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.servi.webapp</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <packaging>war</packaging>
+
+ <dependencies>
+ <!-- RJ Servi -->
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.servi</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.client</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.services.eruntime</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </dependency>
+ <!-- RJ Core -->
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.data</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.statet.rj</groupId>
+ <artifactId>org.eclipse.statet.rj.server</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ </dependency>
+ <!-- JSF -->
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-api</artifactId>
+ <version>1.2_15</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.faces</groupId>
+ <artifactId>jsf-impl</artifactId>
+ <version>1.2_15</version>
+ <scope>runtime</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>jstl</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <!-- Java Web (EE 5) -->
+ <dependency>
+ <groupId>javax.el</groupId>
+ <artifactId>el-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.annotation</groupId>
+ <artifactId>jsr250-api</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <sourceDirectory>src</sourceDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>2.1.1</version>
+ <configuration>
+ <warSourceDirectory>${basedir}/web</warSourceDirectory>
+ <outputFileNameMapping>@{artifactId}@_@{version}@.@{extension}@</outputFileNameMapping>
+ <warName>rservi</warName>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/CheckingFilter.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/CheckingFilter.java
new file mode 100644
index 0000000..550f81c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/CheckingFilter.java
@@ -0,0 +1,65 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+
+/**
+ * Checks http request:
+ * - session timeout (to avoid JSF message)
+ */
+public class CheckingFilter implements Filter {
+
+
+ public CheckingFilter() {
+ }
+
+
+ @Override
+ public void init(final FilterConfig fConfig) throws ServletException {
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ @Override
+ public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
+ final HttpServletRequest httpRequest= (HttpServletRequest) request;
+ final HttpServletResponse httpResponse= (HttpServletResponse) response;
+ final HttpSession session= httpRequest.getSession(false);
+ if (!httpRequest.getParameterMap().isEmpty()
+ && httpRequest.getRequestedSessionId() != null
+ && ((session == null) || session.isNew() || !session.getId().equals(httpRequest.getRequestedSessionId()))
+ ) {
+ httpResponse.sendRedirect(httpRequest.getContextPath()+"/faces/resources/sessionexpired.jsp");
+ return;
+ }
+ chain.doFilter(request, response);
+ return;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DebugBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DebugBean.java
new file mode 100644
index 0000000..a7f44a5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DebugBean.java
@@ -0,0 +1,100 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.annotation.PreDestroy;
+import javax.el.ELContext;
+import javax.faces.context.FacesContext;
+
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.node.RServiPool;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+public class DebugBean {
+
+
+ private final List<RServi> nodes= new ArrayList<RServi>();
+
+
+ public DebugBean() {
+ }
+
+
+ @PreDestroy
+ public void destroy() {
+ actionCloseAllNodes();
+ }
+
+
+ public String actionNewNode() {
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+ final RServiPoolManager poolManager= poolServer.getManager();
+
+ if (poolManager == null) {
+ FacesUtils.addErrorMessage(null, "The pool is currently not available.");
+ return null;
+ }
+ try {
+ final RServi rservi= ((RServiPool) poolManager).getRServi("control-web-app", null);
+ synchronized(this) {
+ this.nodes.add(rservi);
+ }
+ }
+ catch (final Exception e) {
+ FacesUtils.addErrorMessage(null, "An error occurred getting a node: " + e.getMessage());
+ }
+ refreshPoolStatus();
+ return null;
+ }
+
+ public String actionCloseAllNodes() {
+ synchronized (this) {
+ for (final Iterator<RServi> iter= this.nodes.iterator(); iter.hasNext(); ) {
+ final RServi rservi= iter.next();
+ iter.remove();
+ try {
+ rservi.close();
+ }
+ catch (final Exception e) {
+ FacesUtils.addErrorMessage(null, "An error occurred closing a node: " +e.getMessage());
+ }
+ }
+ }
+
+ refreshPoolStatus();
+ return RJWeb.POOLSTATUS_NAV;
+ }
+
+ private void refreshPoolStatus() {
+ final FacesContext context= FacesContext.getCurrentInstance();
+ if (context != null) {
+ try {
+ final ELContext elContext= context.getELContext();
+ final PoolStatusBean poolStatus= (PoolStatusBean) elContext.getELResolver().getValue(elContext, null, "poolStatus");
+ if (poolStatus != null) {
+ poolStatus.forceRefresh();
+ }
+ }
+ catch (final Exception exception) {}
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DurationConverter.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DurationConverter.java
new file mode 100644
index 0000000..d2dabff
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/DurationConverter.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+
+
+public class DurationConverter implements Converter {
+
+
+ public DurationConverter() {
+ }
+
+
+ @Override
+ public Object getAsObject(final FacesContext context, final UIComponent component, final String value) {
+ return null;
+ }
+
+ @Override
+ public String getAsString(final FacesContext context, final UIComponent component, final Object value) {
+ if (value instanceof Long) {
+ long time1= ((Long)value).longValue();
+ if (time1 < 0L) {
+ time1= -time1;
+ }
+ time1 /= 1000L;
+ final long sec= time1 % 60L;
+ time1 /= 60L;
+ final long min= time1 % 60L;
+ time1 /= 60L;
+ final long hour= time1 % 24L;
+ time1 /= 24L;
+ final StringBuilder sb= new StringBuilder();
+ if (time1 > 0L) {
+ sb.append(time1);
+ sb.append(time1 != 1L ? " days " : " day ");
+ }
+ if (hour < 10L) {
+ sb.append('0');
+ }
+ sb.append(Long.toString(hour));
+ sb.append(':');
+ if (min < 10L) {
+ sb.append('0');
+ }
+ sb.append(Long.toString(min));
+ sb.append(':');
+ if (sec < 10L) {
+ sb.append('0');
+ }
+ sb.append(Long.toString(sec));
+ return sb.toString();
+ }
+ return null;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/EAppEnvDummy.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/EAppEnvDummy.java
new file mode 100644
index 0000000..6f04bf1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/EAppEnvDummy.java
@@ -0,0 +1,144 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+import org.eclipse.core.runtime.IStatus;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+
+public class EAppEnvDummy implements ServletContextListener, ECommonsRuntime.AppEnvironment {
+
+
+ private final CopyOnWriteArraySet<Disposable> stopListeners= new CopyOnWriteArraySet<>();
+
+ private ServletContext context;
+
+ private Logger logger;
+
+
+ public EAppEnvDummy() {
+ }
+
+
+ @Override
+ public void contextInitialized(final ServletContextEvent sce) {
+ this.context= sce.getServletContext();
+ ECommons.init("org.eclipse.statet.rj.services.eruntime", this);
+
+ this.logger= Logger.getLogger("org.eclipse.statet.rj.servi.pool");
+ }
+
+ @Override
+ public void contextDestroyed(final ServletContextEvent sce) {
+ try {
+ for (final Disposable listener : this.stopListeners) {
+ listener.dispose();
+ }
+ }
+ finally {
+ this.stopListeners.clear();
+ this.context= null;
+ }
+ }
+
+ @Override
+ public void addStoppingListener(final Disposable listener) {
+ this.stopListeners.add(listener);
+ }
+
+ @Override
+ public void removeStoppingListener(final Disposable listener) {
+ this.stopListeners.remove(listener);
+ }
+
+// public void log(final IStatus status) {
+// final StringBuilder sb= new StringBuilder();
+// switch (status.getSeverity()) {
+// case IStatus.OK:
+// sb.append("[OK] ");
+// break;
+// case IStatus.ERROR:
+// sb.append("[ERROR] ");
+// break;
+// case IStatus.WARNING:
+// sb.append("[WARNING] ");
+// break;
+// case IStatus.INFO:
+// sb.append("[INFO] ");
+// break;
+// case IStatus.CANCEL:
+// sb.append("[CANCEL] ");
+// break;
+// default:
+// sb.append("[severity=");
+// sb.append(status.getSeverity());
+// sb.append(']');
+// break;
+// }
+// sb.append(status.getMessage());
+//
+// this.context.log(sb.toString(), status.getException());
+// }
+
+ @Override
+ public void log(final IStatus status) {
+ final Level level;
+ switch (status.getSeverity()) {
+ case IStatus.INFO:
+ level= Level.INFO;
+ break;
+ case IStatus.WARNING:
+ level= Level.WARNING;
+ break;
+ case IStatus.ERROR:
+ level= Level.SEVERE;
+ break;
+ default:
+ level= Level.FINE;
+ }
+ final LogRecord record= new LogRecord(level, status.getMessage());
+ if (status.getException() != null) {
+ record.setThrown(status.getException());
+ }
+
+ // set correct caller
+ try {
+ final StackTraceElement[] stackTrace= new Exception().getStackTrace();
+ for (int i= 1; i < stackTrace.length; i++) {
+ if (!stackTrace[i].getMethodName().startsWith("log")) {
+ record.setSourceClassName(stackTrace[i].getClassName());
+ record.setSourceMethodName(stackTrace[i].getMethodName());
+ break;
+ }
+ }
+ }
+ catch (final Exception ignore) {}
+
+ this.logger.log(record);
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/FacesUtils.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/FacesUtils.java
new file mode 100644
index 0000000..007d258
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/FacesUtils.java
@@ -0,0 +1,200 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.servlet.ServletContext;
+
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.PropertiesBean.ValidationMessage;
+import org.eclipse.statet.rj.servi.pool.NetConfig;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class FacesUtils {
+
+
+ public static String toUI(final String formId, final String propertyId) {
+ if (formId == null || propertyId == null) {
+ return null;
+ }
+ final StringBuilder sb= new StringBuilder(formId.length() + propertyId.length() + 1);
+ sb.append(formId);
+ sb.append(':');
+ for (int i= 0; i < propertyId.length(); i++) {
+ final char c= propertyId.charAt(i);
+ if (c == '.') {
+ sb.append('_');
+ }
+ else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ public static String toFormId(final String beanId) {
+ if (beanId == NetConfig.BEAN_ID) {
+ return "net_config";
+ }
+ if (beanId == RServiNodeConfig.BEAN_ID) {
+ return "r_config";
+ }
+ if (beanId == PoolConfig.BEAN_ID) {
+ return "pool_config";
+ }
+ return null;
+ }
+
+ public static boolean validate(final PropertiesBean bean) {
+ final List<ValidationMessage> messages= new ArrayList<ValidationMessage>();
+ if (bean.validate(messages)) {
+ return true;
+ }
+ final String formId= toFormId(bean.getBeanId()) + "_config";
+ for (final ValidationMessage message : messages) {
+ addErrorMessage(toUI(formId, message.getPropertyId()), message.getMessage());
+ }
+ return false;
+ }
+
+ public static void addErrorMessage(final String ui, String message) {
+ { int end= -1;
+ while (true) {
+ final int begin= message.indexOf('{', end + 1);
+ if (begin < 0) {
+ break;
+ }
+ end= message.indexOf('}', begin + 1);
+ if (end >= 0) {
+ final String label= getLabel(message.substring(begin + 1, end));
+ if (label != null && !label.isEmpty()) {
+ message= message.substring(0, begin) + label + message.substring(end + 1);
+ }
+ }
+ else {
+ end= begin;
+ }
+ }
+ }
+
+ final String label= getLabel(ui);
+ if (label != null) {
+ message= label + ": " + message;
+ }
+
+ FacesContext.getCurrentInstance().addMessage(ui, new FacesMessage(FacesMessage.SEVERITY_ERROR, message, message));
+ }
+
+ public static String getLabel(final String componentId) {
+ if (componentId != null) {
+ final UIComponent component= FacesContext.getCurrentInstance().getViewRoot().findComponent(componentId);
+ if (component != null) {
+ return (String) component.getAttributes().get("label");
+ }
+ }
+ return null;
+ }
+
+ public static PoolServer getPoolServer() {
+ final Object externalContext= FacesContext.getCurrentInstance().getExternalContext().getContext();
+ if (externalContext instanceof ServletContext) {
+ return (PoolServer) ((ServletContext) externalContext).getAttribute(RJWeb.RJ_POOLSERVER_KEY);
+ }
+ throw new IllegalStateException();
+ }
+
+ private static RJContext getRJContext() {
+ final Object externalContext= FacesContext.getCurrentInstance().getExternalContext().getContext();
+ if (externalContext instanceof ServletContext) {
+ return (RJContext) ((ServletContext) externalContext).getAttribute(RJWeb.RJCONTEXT_KEY);
+ }
+ throw new IllegalStateException();
+ }
+
+ public static String getPoolId() {
+ final Object externalContext= FacesContext.getCurrentInstance().getExternalContext().getContext();
+ if (externalContext instanceof ServletContext) {
+ return (String) ((ServletContext) externalContext).getAttribute(RJWeb.POOLID_KEY);
+ }
+ throw new IllegalStateException();
+ }
+
+
+ public static boolean saveToFile(final PropertiesBean bean) {
+ try {
+ final Properties properties= new Properties();
+
+ synchronized (bean) {
+ if (!validate(bean)) {
+ return false;
+ }
+ bean.save(properties);
+ }
+
+ getRJContext().saveProperties(bean.getBeanId(), properties);
+
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration saved.", null));
+ return true;
+ }
+ catch (final Exception e) {
+ FacesContext.getCurrentInstance().getExternalContext().log(
+ MessageFormat.format("Failed to save to the configuration file ''{0}''.", new Object[] { bean.getBeanId() }), e);
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Failed to save the configuration: " + e.getMessage(), null));
+ return false;
+ }
+ }
+
+ public static boolean loadFromFile(final PropertiesBean bean, final boolean report) {
+ try {
+ final Properties properties= getRJContext().loadProperties(bean.getBeanId());
+ if (properties == null) {
+ if (report) {
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,
+ MessageFormat.format("The configuration file ''{0}'' could not be found. Default values are used.", new Object[] { bean.getBeanId() }), null));
+ }
+ return false;
+ }
+
+ synchronized(bean) {
+ bean.load(properties);
+
+ validate(bean);
+ }
+ return true;
+ }
+ catch (final Exception e) {
+ if (report) {
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR,
+ MessageFormat.format("Failed to load the configuration from file ''{0}''.", new Object[] { bean.getBeanId() }), null));
+ }
+ return false;
+ }
+ }
+
+
+ private FacesUtils() {}
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NetConfigBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NetConfigBean.java
new file mode 100644
index 0000000..efdab4a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NetConfigBean.java
@@ -0,0 +1,88 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+import javax.management.OperationsException;
+import javax.naming.directory.InvalidAttributeValueException;
+
+import org.eclipse.statet.rj.servi.pool.NetConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class NetConfigBean extends NetConfig {
+
+
+ public NetConfigBean() {
+ }
+
+
+ @PostConstruct
+ public void init() {
+ FacesUtils.loadFromFile(this, false);
+ }
+
+
+ public String getEffectivePoolAddress() {
+ final String address= getPoolAddress(this, FacesUtils.getPoolId());
+ return (address != null) ? address : "";
+ }
+
+
+ public String actionLoadCurrent() {
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ synchronized (this) {
+ poolServer.getNetConfig(this);
+ FacesUtils.validate(this);
+ }
+
+ return RJWeb.NETCONFIG_NAV;
+ }
+
+ public String actionLoadDefaults() throws InvalidAttributeValueException {
+ synchronized (this) {
+ load(new NetConfigBean());
+ FacesUtils.validate(this);
+ }
+
+ return RJWeb.NETCONFIG_NAV;
+ }
+
+ public String actionRestart() {
+ final NetConfig config= new NetConfig(this);
+
+ if (!FacesUtils.validate(config)) {
+ return null;
+ }
+
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ poolServer.setNetConfig(config);
+ try {
+ poolServer.restart();
+ }
+ catch (final OperationsException e) {
+ FacesUtils.addErrorMessage(null, e.getMessage());
+ }
+ return null;
+ }
+
+ public String actionSave() {
+ FacesUtils.saveToFile(this);
+ return null;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NodeConfigBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NodeConfigBean.java
new file mode 100644
index 0000000..235ff83
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/NodeConfigBean.java
@@ -0,0 +1,111 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class NodeConfigBean extends RServiNodeConfig {
+
+
+ public NodeConfigBean() {
+ }
+
+
+ @PostConstruct
+ public void init() {
+ actionLoadCurrent();
+ }
+
+
+ public synchronized String getRLibsVariable() {
+ return getEnvironmentVariables().get("R_LIBS");
+ }
+
+ public synchronized void setRLibsVariable(final String value) {
+ if (value != null && value.length() > 0) {
+ getEnvironmentVariables().put("R_LIBS", value);
+ }
+ else {
+ getEnvironmentVariables().remove("R_LIBS");
+ }
+ }
+
+
+ public String actionLoadCurrent() {
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ synchronized (this) {
+ poolServer.getNodeConfig(this);
+ FacesUtils.validate(this);
+ }
+
+ return RJWeb.RCONFIG_NAV;
+ }
+
+ public String actionLoadDefaults() {
+ synchronized (this) {
+ load(new RServiNodeConfig());
+ FacesUtils.validate(this);
+ }
+
+ return RJWeb.RCONFIG_NAV;
+ }
+
+ public String actionApply() {
+ final RServiNodeConfig config= new RServiNodeConfig(this);
+
+ if (!FacesUtils.validate(config)) {
+ return null;
+ }
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ try {
+ poolServer.setNodeConfig(config);
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+ }
+ catch (final RjException e) {
+ FacesUtils.addErrorMessage(null, e.getMessage());
+ }
+ return null;
+ }
+
+ public synchronized String actionSaveAndApply() {
+ final RServiNodeConfig config= new RServiNodeConfig(this);
+
+ if (!FacesUtils.validate(config)) {
+ return null;
+ }
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ try {
+ poolServer.setNodeConfig(config);
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+ }
+ catch (final RjException e) {
+ FacesUtils.addErrorMessage(null, e.getMessage());
+ return null;
+ }
+ FacesUtils.saveToFile(config);
+ return null;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolConfigBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolConfigBean.java
new file mode 100644
index 0000000..a72f8c5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolConfigBean.java
@@ -0,0 +1,88 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class PoolConfigBean extends PoolConfig {
+
+
+ public PoolConfigBean() {
+ }
+
+
+ @PostConstruct
+ public void init() {
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ poolServer.getPoolConfig(this);
+ }
+
+
+ public String actionLoadCurrent() {
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ synchronized (this) {
+ poolServer.getPoolConfig(this);
+ FacesUtils.validate(this);
+ }
+
+ return RJWeb.POOLCONFIG_NAV;
+ }
+
+ public String actionLoadDefaults() {
+ synchronized (this) {
+ load(new PoolConfig());
+ FacesUtils.validate(this);
+ }
+
+ return RJWeb.POOLCONFIG_NAV;
+ }
+
+ public String actionApply() {
+ final PoolConfig config= new PoolConfig(this);
+
+ if (!FacesUtils.validate(config)) {
+ return null;
+ }
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ poolServer.setPoolConfig(config);
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+ return null;
+ }
+
+ public String actionSaveAndApply() {
+ final PoolConfig config= new PoolConfig(this);
+
+ if (!FacesUtils.validate(config)) {
+ return null;
+ }
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ poolServer.setPoolConfig(config);
+ FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Configuration applied.", null));
+
+ FacesUtils.saveToFile(config);
+ return null;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolItemBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolItemBean.java
new file mode 100644
index 0000000..96b430e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolItemBean.java
@@ -0,0 +1,73 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class PoolItemBean extends PoolNodeItem {
+
+
+ public PoolItemBean(final PoolNodeObject poolObj, final long stamp) {
+ super(poolObj, stamp);
+ }
+
+
+ public String getRMIAddress() {
+ final RMIAddress address= getAddress();
+ return (address != null) ? address.getAddress() : null;
+ }
+
+
+ public String actionEnableConsole() {
+ try {
+ super.enableConsole("none");
+ }
+ catch (final RjException e) {
+ FacesUtils.addErrorMessage(null, e.getMessage());
+ }
+ return null;
+ }
+
+ public String actionDisableConsole() {
+ try {
+ super.disableConsole();
+ }
+ catch (final RjException e) {
+ FacesUtils.addErrorMessage(null, e.getMessage());
+ }
+ return null;
+ }
+
+ public void actionStop() {
+ final PoolServer poolServer= FacesUtils.getPoolServer();
+
+ final PoolConfig config= new PoolConfig();
+ poolServer.getPoolConfig(config);
+
+ evict(config.getEvictionTimeout());
+ }
+
+ public void actionKill() {
+ evict(0);
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolStatusBean.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolStatusBean.java
new file mode 100644
index 0000000..92fdc0c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/PoolStatusBean.java
@@ -0,0 +1,100 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import javax.annotation.PostConstruct;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolStatus;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+public class PoolStatusBean extends PoolStatus<PoolItemBean> {
+
+
+ private boolean forceRefresh;
+ private boolean autoRefresh;
+
+
+ public PoolStatusBean() {
+ super(FacesUtils.getPoolServer());
+ }
+
+
+ @PostConstruct
+ public void init() {
+ load();
+ }
+
+ private void load() {
+ final long stamp= System.currentTimeMillis();
+ final RServiPoolManager poolManager= this.server.getManager();
+ if (poolManager == null) {
+ FacesUtils.addErrorMessage(null, "The pool is currently not available.");
+ }
+ refresh(poolManager, stamp);
+ }
+
+ @Override
+ protected PoolNodeItem createPoolItem(final Object itemData, final long stamp) {
+ return new PoolItemBean(itemData, stamp);
+ }
+
+ @Override
+ protected PoolItemBean createNodeState(final PoolNodeItem item) {
+ return (PoolItemBean) item;
+ }
+
+
+ public synchronized long getStamp() {
+ check();
+ return super.getStatusStamp();
+ }
+
+ @Override
+ protected void check() {
+ if (this.forceRefresh) {
+ load();
+ }
+ }
+
+ public synchronized void forceRefresh() {
+ this.forceRefresh= true;
+ }
+
+
+ public String actionRefresh() {
+ return null;
+ }
+
+ public synchronized String actionEnableAutoRefresh() {
+ this.autoRefresh= true;
+ return null;
+ }
+
+ public synchronized String actionDisableAutoRefresh() {
+ this.autoRefresh= false;
+ return null;
+ }
+
+ public synchronized void setAutoRefreshEnabled(final boolean enabled) {
+ this.autoRefresh= enabled;
+ }
+
+ public synchronized boolean isAutoRefreshEnabled() {
+ return this.autoRefresh;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJServlet.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJServlet.java
new file mode 100644
index 0000000..e12f221
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJServlet.java
@@ -0,0 +1,84 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.io.IOException;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.statet.rj.servi.pool.JMPoolServer;
+
+
+public class RJServlet extends HttpServlet {
+
+
+ private JMPoolServer server;
+
+
+ public RJServlet(){
+ }
+
+
+ @Override
+ public void init(final ServletConfig config) throws ServletException {
+ super.init(config);
+ try {
+ String id= getServletContext().getContextPath();
+ if (id.startsWith("/")) {
+ id= id.substring(1);
+ }
+ getServletContext().setAttribute(RJWeb.POOLID_KEY, id);
+
+ final ServletRJContext rjContext= new ServletRJContext(getServletContext());
+ getServletContext().setAttribute(RJWeb.RJCONTEXT_KEY, rjContext);
+
+ this.server= new JMPoolServer(id, rjContext);
+ this.server.start();
+
+ getServletContext().setAttribute(RJWeb.RJ_POOLSERVER_KEY, this.server);
+ }
+ catch (final Exception e) {
+ if (this.server != null) {
+ this.server.shutdown();
+ this.server= null;
+ }
+ throw new ServletException("Failed to initialized RServi Server.", e);
+ }
+ }
+
+ @Override
+ public void destroy() {
+ if (this.server != null) {
+ getServletContext().removeAttribute(RJWeb.RJ_POOLSERVER_KEY);
+
+ this.server.shutdown();
+ }
+ }
+
+ @Override
+ protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
+ if (this.server != null) {
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+ else {
+ response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJWeb.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJWeb.java
new file mode 100644
index 0000000..aba7837
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/RJWeb.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+
+public class RJWeb {
+
+
+ public static final String BUNDLE_ID= "org.eclipse.statet.rj.servi.webapp";
+
+ public static final String RJ_POOLSERVER_KEY= "rj.pool.server";
+ public static final String POOLID_KEY= "pool.id";
+ public static final String RJCONTEXT_KEY= "rj.context";
+
+ public static final String POOLCONFIG_NAV= "conf-pool";
+ public static final String POOLSTATUS_NAV= "status-pool";
+ public static final String RCONFIG_NAV= "conf-r";
+ public static final String NETCONFIG_NAV= "conf-net";
+
+
+ private RJWeb() {}
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/ServletRJContext.java b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/ServletRJContext.java
new file mode 100644
index 0000000..8223543
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/src/org/eclipse/statet/rj/servi/webapp/ServletRJContext.java
@@ -0,0 +1,80 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.webapp;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.servlet.ServletContext;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+
+
+public class ServletRJContext extends RJContext {
+
+
+ private final ServletContext servletContext;
+
+
+ public ServletRJContext(final ServletContext context) {
+ this.servletContext= context;
+ }
+
+
+ @Override
+ protected String[] getLibDirPaths() throws RjInvalidConfigurationException {
+ return new String[] { this.servletContext.getRealPath("WEB-INF/lib") };
+ }
+
+
+ @Override
+ public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+ String path= this.servletContext.getRealPath("WEB-INF/lib");
+ final int length= path.length();
+ if (length == 0 || (path.charAt(length-1) != '/' && path.charAt(length-1) != File.separatorChar)) {
+ path+= File.separatorChar;
+ }
+ return path + "security.policy";
+ }
+
+
+ @Override
+ protected String getPropertiesDirPath() {
+ return "/WEB-INF/";
+ }
+
+ @Override
+ protected InputStream getInputStream(final String path) throws IOException {
+ return this.servletContext.getResourceAsStream(path);
+ }
+
+ @Override
+ protected OutputStream getOutputStream(final String path) throws IOException {
+ final String realPath= this.servletContext.getRealPath(path);
+ if (realPath == null) {
+ throw new IOException("Writing to '" + path + "' not supported.");
+ }
+ final File file= new File(realPath);
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+ return new FileOutputStream(file, false);
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/META-INF/MANIFEST.MF b/servi/org.eclipse.statet.rj.servi.webapp/web/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..254272e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path:
+
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml
new file mode 100644
index 0000000..82d14df
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/faces-config.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
+ version="1.2">
+
+ <converter>
+ <converter-id>convertDuration</converter-id>
+ <converter-class>org.eclipse.statet.rj.servi.webapp.DurationConverter</converter-class>
+ </converter>
+
+ <managed-bean>
+ <managed-bean-name>netConfig</managed-bean-name>
+ <managed-bean-class>org.eclipse.statet.rj.servi.webapp.NetConfigBean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
+ <managed-bean>
+ <managed-bean-name>poolConfig</managed-bean-name>
+ <managed-bean-class>org.eclipse.statet.rj.servi.webapp.PoolConfigBean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
+ <managed-bean>
+ <managed-bean-name>rConfig</managed-bean-name>
+ <managed-bean-class>org.eclipse.statet.rj.servi.webapp.NodeConfigBean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
+ <managed-bean>
+ <managed-bean-name>poolStatus</managed-bean-name>
+ <managed-bean-class>org.eclipse.statet.rj.servi.webapp.PoolStatusBean</managed-bean-class>
+ <managed-bean-scope>request</managed-bean-scope>
+ </managed-bean>
+
+ <managed-bean>
+ <managed-bean-name>debug</managed-bean-name>
+ <managed-bean-class>org.eclipse.statet.rj.servi.webapp.DebugBean</managed-bean-class>
+ <managed-bean-scope>session</managed-bean-scope>
+ </managed-bean>
+
+ <navigation-rule>
+ <display-name>welcome</display-name>
+ <from-view-id>/resources/welcome.jsp</from-view-id>
+ </navigation-rule>
+ <navigation-rule>
+ <display-name>conf-pool</display-name>
+ <from-view-id>/resources/conf-pool.jsp</from-view-id>
+ <navigation-case>
+ <from-outcome>conf-pool</from-outcome>
+ <to-view-id>/resources/conf-pool.jsp</to-view-id>
+ </navigation-case>
+ </navigation-rule>
+ <navigation-rule>
+ <display-name>conf-r</display-name>
+ <from-view-id>/resources/conf-r.jsp</from-view-id>
+ <navigation-case>
+ <from-outcome>conf-r</from-outcome>
+ <to-view-id>/resources/conf-r.jsp</to-view-id>
+ </navigation-case>
+ </navigation-rule>
+
+ <navigation-rule>
+ <from-view-id>/resources/*</from-view-id>
+ <navigation-case>
+ <from-outcome>status-pool</from-outcome>
+ <to-view-id>/resources/status-poolnodes.jsp</to-view-id>
+ </navigation-case>
+ </navigation-rule>
+
+</faces-config>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/keystore b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/keystore
new file mode 100644
index 0000000..64d2dd3
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/keystore
Binary files differ
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/lib/security.policy b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/lib/security.policy
new file mode 100644
index 0000000..6e902c1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/lib/security.policy
@@ -0,0 +1,7 @@
+grant codeBase "file:${{java.ext.dirs}}/*" {
+ permission java.security.AllPermission;
+};
+
+grant {
+ permission java.security.AllPermission;
+};
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/netconfig.properties b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/netconfig.properties
new file mode 100644
index 0000000..c454063
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/netconfig.properties
@@ -0,0 +1,3 @@
+#Mon May 06 14:22:42 CEST 2013
+ssl.enabled=false
+rmi_registry.embed.enabled=true
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/rconfig.properties b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/rconfig.properties
new file mode 100644
index 0000000..6eb18af
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/rconfig.properties
@@ -0,0 +1,9 @@
+#Mon May 06 13:55:51 CEST 2013
+r_home.path=D\:\\R\\R-3.0-org
+java_cmd.args=
+r_startup.snippet=
+debug_verbose.enabled=false
+base_wd.path=D\:\\OrcaForge\\temp
+debug_console.enabled=false
+node_cmd.args=
+startstop_timeout.millis=30000
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/server.cer b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/server.cer
new file mode 100644
index 0000000..e9cb25c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/server.cer
Binary files differ
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/truststore b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/truststore
new file mode 100644
index 0000000..0df9807
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/truststore
Binary files differ
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/web.xml b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/web.xml
new file mode 100644
index 0000000..8cf7223
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/WEB-INF/web.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
+
+ <display-name>org.eclipse.statet.rj.servi.webapp</display-name>
+
+ <welcome-file-list>
+ <welcome-file>index.jsp</welcome-file>
+ </welcome-file-list>
+
+ <servlet>
+ <servlet-name>RJServlet</servlet-name>
+ <servlet-class>org.eclipse.statet.rj.servi.webapp.RJServlet</servlet-class>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>RJServlet</servlet-name>
+ <url-pattern>/status</url-pattern>
+ </servlet-mapping>
+
+ <servlet>
+ <servlet-name>FacesServlet</servlet-name>
+ <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
+ <load-on-startup>2</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>FacesServlet</servlet-name>
+ <url-pattern>/faces/*</url-pattern>
+ </servlet-mapping>
+
+ <filter>
+ <display-name>CheckingFilter</display-name>
+ <filter-name>CheckingFilter</filter-name>
+ <filter-class>org.eclipse.statet.rj.servi.webapp.CheckingFilter</filter-class>
+ </filter>
+ <filter-mapping>
+ <filter-name>CheckingFilter</filter-name>
+ <url-pattern>/faces/resources/*</url-pattern>
+ <dispatcher>REQUEST</dispatcher>
+ </filter-mapping>
+
+ <listener>
+ <display-name>AppEnv for ECommons</display-name>
+ <listener-class>org.eclipse.statet.rj.servi.webapp.EAppEnvDummy</listener-class>
+ </listener>
+
+ <session-config>
+ <session-timeout>30</session-timeout>
+ </session-config>
+
+<!--
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>admin</web-resource-name>
+ <url-pattern>/resources/*</url-pattern>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>admin</role-name>
+ </auth-constraint>
+ </security-constraint>
+-->
+
+</web-app>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/index.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/index.jsp
new file mode 100644
index 0000000..d80cf54
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/index.jsp
@@ -0,0 +1 @@
+<% response.sendRedirect(request.getContextPath()+"/faces/resources/"); %>
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-footer.jspf b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-footer.jspf
new file mode 100644
index 0000000..7f5eaa3
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-footer.jspf
@@ -0,0 +1 @@
+</div>
\ No newline at end of file
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-header.jspf b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-header.jspf
new file mode 100644
index 0000000..6d50907
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/body-header.jspf
@@ -0,0 +1,17 @@
+<div class="menu">
+
+<h:outputLink value="."><h3>(RJ) <i>RServi</i><small> - Server</small></h3></h:outputLink>
+
+<h4>Configuration</h4>
+<ul>
+<li><h:outputLink value="conf-net.jsp"><h:outputText value="Net (RMI)"/></h:outputLink></li>
+<li><h:outputLink value="conf-pool.jsp"><h:outputText value="Pool"/></h:outputLink></li>
+<li><h:outputLink value="conf-r.jsp"><h:outputText value="R/RServi Nodes"/></h:outputLink></li>
+</ul>
+<h4>Status</h4>
+<ul>
+<li><h:outputLink value="status-poolnodes.jsp"><h:outputText value="Pool Nodes"/></h:outputLink></li>
+</ul>
+
+</div>
+<div class="content"><%-- content --%>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-net.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-net.jsp
new file mode 100644
index 0000000..669e1ac
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-net.jsp
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Configuration: General</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Configuration: General</h2>
+
+<h:form id="net_config">
+ <h:messages errorClass="error" />
+
+<h:panelGrid columns="3" styleClass="grid" columnClasses="label,input,info">
+ <f:facet name="header"><h:outputText value="RMI Parameters" /></f:facet>
+
+ <h:outputLabel for="host_address" value="(1) Host address (IP/name):" accesskey="1" />
+ <h:inputText id="host_address" label="Host address (1)" value="#{netConfig.hostAddress}" required="false" size="40" />
+ <h:outputText>This setting is synchronized with the global Java property 'java.rmi.server.hostname'</h:outputText>
+
+ <h:outputLabel for="eff_host_address" value="--> Resolved IP:" />
+ <h:inputText id="eff_host_address" label="Host address (1)" value="#{netConfig.effectiveHostaddress}" required="false" readonly="true" size="40" />
+ <h:outputText />
+
+ <h:outputLabel for="rmi_registry_address_port" value="(2) RMI registry port:" accesskey="2" />
+ <h:inputText id="rmi_registry_address_port" label="RMI registry port (2)" value="#{netConfig.registryPort}" required="false" size="6" />
+ <h:outputText>(-1 ⇒ default)</h:outputText>
+
+ <h:outputLabel for="rmi_registry_embed_enabled" value="(3) Start embedded registry:" accesskey="3" />
+ <h:selectBooleanCheckbox id="rmi_registry_embed_enabled" label="Start embedded registry (3)" value="#{netConfig.registryEmbed}" required="true" />
+ <h:outputText></h:outputText>
+
+ <h:outputLabel for="ssl_enabled" value="(4) Enable SSL:" accesskey="4" />
+ <h:selectBooleanCheckbox id="ssl_enabled" label="Start embedded registry (4)" value="#{netConfig.SSLEnabled}" required="true" />
+ <h:outputText></h:outputText>
+
+</h:panelGrid>
+
+ <h:commandButton id="loadDefaults" value="Load Defaults" action="#{netConfig.actionLoadDefaults}" type="button" immediate="true" accesskey="L" />
+ <h:commandButton id="loadCurrent" value="Load Current" action="#{netConfig.actionLoadCurrent}" type="button" immediate="true" accesskey="C" />
+ <br/>
+ <h:commandButton id="restart" value="Apply and Restart" action="#{netConfig.actionRestart}" accesskey="R" />
+ <h:commandButton id="save" value="Save" action="#{netConfig.actionSave}" accesskey="S" />
+ <b>Changes require restart!</b>
+</h:form>
+
+<h:panelGrid columns="2" styleClass="grid" columnClasses=",,">
+ <f:facet name="header"><h:outputText value="Info" /></f:facet>
+
+ <h:outputLabel for="eff_pool_address" value="RMI pool address:" />
+ <h:inputText id="eff_pool_address" value="#{netConfig.effectivePoolAddress}" required="false" size="40" />
+</h:panelGrid>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-pool.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-pool.jsp
new file mode 100644
index 0000000..70fa7f1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-pool.jsp
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Configuration: Pool</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Configuration: Pool</h2>
+
+<h:form id="pool_config">
+ <h:messages errorClass="error" />
+
+<h:panelGrid columns="3" styleClass="grid" columnClasses="label,value,info special1">
+ <f:facet name="header"><h:outputText value="Parameters for dynamic pool" /></f:facet>
+
+ <h:outputText/>
+ <h:outputText/>
+ <h:outputText>Startup new nodes if...</h:outputText>
+
+ <h:outputLabel for="max_total_count" value="(1) Max total nodes (count):" accesskey="1" />
+ <h:inputText id="max_total_count" label="Max total nodes (1)" value="#{poolConfig.maxTotalCount}" required="true" />
+ <h:outputText>... total count smaller than (1) ...</h:outputText>
+
+ <h:outputLabel for="min_idle_count" value="(2) Min idle nodes (count):" accesskey="2" />
+ <h:inputText id="min_idle_count" label="Min idle nodes (2)" value="#{poolConfig.minIdleCount}" required="true" />
+ <h:outputText>... and idle count smaller than (2).</h:outputText>
+
+ <h:outputText/>
+ <h:outputText/>
+ <h:outputText>Evict idling nodes if...</h:outputText>
+
+ <h:outputLabel for="max_idle_count" value="(3) Max idle nodes (count):" accesskey="3" />
+ <h:inputText id="max_idle_count" label="Max idle nodes (3)" value="#{poolConfig.maxIdleCount}" required="true" />
+ <h:outputText>... idle count greater than (3) ...</h:outputText>
+
+ <h:outputLabel for="min_idle_millis" value="(4) Min node idle time (millisec):" accesskey="4" />
+ <h:inputText id="min_idle_millis" label="Min node idle time (4)" value="#{poolConfig.minIdleTime}" required="true" />
+ <h:outputText>... or idle count greater than (2) count and idle time greater than (4).</h:outputText>
+
+ <h:outputText/>
+ <h:outputText/>
+ <h:outputText>When node is requested and max count nodes (1) is in use ...</h:outputText>
+
+ <h:outputLabel for="max_wait_millis" value="(5) Max wait time (millisec):" accesskey="5" />
+ <h:inputText id="max_wait_millis" label="Max wait time (5)" value="#{poolConfig.maxWaitTime}" required="true"/>
+ <h:outputText>... wait for a free node until timeout (5).</h:outputText>
+
+ <h:outputText/>
+ <h:outputText/>
+ <h:outputText>To keep healthy ...</h:outputText>
+
+ <h:outputLabel for="max_usage_count" value="(6) Max node reuse (count):" accesskey="6" />
+ <h:inputText id="max_usage_count" label="Max node reuse (6)" value="#{poolConfig.maxUsageCount}" required="true" />
+ <h:outputText>... recycle a node maximal (6) times.</h:outputText>
+
+ <h:outputText/>
+ <h:outputText/>
+ <h:outputText>When stopping the pool or single nodes:</h:outputText>
+
+ <h:outputLabel for="eviction_timeout_millis" value="(7) Timeout when evicting node in use (millisec):" accesskey="7" />
+ <h:inputText id="eviction_timeout_millis" label="Timeout when evicting node (7)" value="#{poolConfig.evictionTimeout}" required="true" />
+ <h:outputText></h:outputText>
+</h:panelGrid>
+
+ <h:commandButton id="loadDefaults" value="Load Defaults" action="#{poolConfig.actionLoadDefaults}" type="button" immediate="true" accesskey="L" />
+ <h:commandButton id="loadCurrent" value="Load Current" action="#{poolConfig.actionLoadCurrent}" type="button" immediate="true" accesskey="C" />
+ <br/>
+ <h:commandButton id="apply" value="Apply" action="#{poolConfig.actionApply}" accesskey="A" />
+ <h:commandButton id="saveAndApply" value="Save and Apply" action="#{poolConfig.actionSaveAndApply}" accesskey="S" />
+</h:form>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-r.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-r.jsp
new file mode 100644
index 0000000..5628941
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/conf-r.jsp
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Configuration: R/RJ Nodes</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Configuration: R/RJ Nodes</h2>
+
+<h:form id="r_config">
+ <h:messages errorClass="error" />
+
+<h:panelGrid columns="3" styleClass="grid" columnClasses="label,value,info">
+ <f:facet name="header"><h:outputText value="Parameters to start R" /></f:facet>
+
+ <h:outputLabel for="java_home_path" value="(1) Java home (path):" accesskey="1" />
+ <h:inputText id="java_home_path" label="Java home (1)" value="#{rConfig.javaHome}" required="false" size="80" />
+ <h:outputText>(empty ⇒ same as the server)</h:outputText>
+
+ <h:outputLabel for="java_cmd_args" value="(2) Java arguments:" accesskey="2" />
+ <h:inputTextarea id="java_cmd_args" label="Java arguments (2)" value="#{rConfig.javaArgs}" required="false" cols="76" rows="4" />
+ <h:outputText></h:outputText>
+
+ <h:outputLabel for="r_home_path" value="(3) R home / R_HOME (path):" accesskey="3" />
+ <h:inputText id="r_home_path" label="R home / R_HOME (3)" value="#{rConfig.RHome}" required="true" size="80" />
+ <h:outputText></h:outputText>
+
+ <h:outputLabel for="r_arch_code" value="(4) Architecture of binaries / R_ARCH:" accesskey="4" />
+ <h:inputText id="r_arch_code" label="Architecture / R_ARCH (4)" value="#{rConfig.RArch}" required="false" size="10" />
+ <h:outputText>(empty ⇒ autodetection)</h:outputText>
+
+ <h:outputLabel for="r_libs_path" value="(5) R libraries / R_LIBS (path):" accesskey="5" />
+ <h:inputText id="r_libs_path" label="R libraries / R_LIBS (5)" value="#{rConfig.RLibsVariable}" required="false" size="80" />
+ <h:outputText>(optional)</h:outputText>
+
+ <h:outputLabel for="base_wd_path" value="(6) Working directory (path):" accesskey="6" />
+ <h:inputText id="base_wd_path" label="Working directory (6)" value="#{rConfig.baseWorkingDirectory}" required="false" size="80" />
+ <h:outputText>(empty ⇒ default temp dir)</h:outputText>
+
+ <h:outputLabel for="r_startup_snippet" value="(7) R startup snippet (complete R command per line):" accesskey="7" />
+ <h:inputTextarea id="r_startup_snippet" label="R startup snippet (7)" value="#{rConfig.RStartupSnippet}" required="false" cols="76" rows="4" />
+ <h:outputText />
+
+ <h:outputLabel for="debug_console_enabled" value="(8) Enable debug console:" accesskey="8" />
+ <h:selectBooleanCheckbox id="debug_console_enabled" label="Enable debug console by default (8)" value="#{rConfig.enableConsole}" required="true" />
+ <h:outputText>Enables debug console automatically at startup (use only for development!)</h:outputText>
+
+ <h:outputLabel for="verbose_console_enabled" value="(9) Enable verbose logging:" accesskey="9" />
+ <h:selectBooleanCheckbox id="verbose_console_enabled" label="Enable verbose logging (9)" value="#{rConfig.enableVerbose}" required="true" />
+ <h:outputText>Enables verbose logging and prevents deletion of the node directory</h:outputText>
+
+</h:panelGrid>
+
+ <h:commandButton id="loadDefaults" value="Load Defaults" action="#{rConfig.actionLoadDefaults}" type="button" immediate="true" accesskey="L" />
+ <h:commandButton id="loadCurrent" value="Load Current" action="#{rConfig.actionLoadCurrent}" type="button" immediate="true" accesskey="C" />
+ <br/>
+ <h:commandButton id="apply" value="Apply" action="#{rConfig.actionApply}" accesskey="A" />
+ <h:commandButton id="saveAndApply" value="Save and Apply" action="#{rConfig.actionSaveAndApply}" accesskey="S" />
+</h:form>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/css/style.css b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/css/style.css
new file mode 100644
index 0000000..bad8973
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/css/style.css
@@ -0,0 +1,79 @@
+@CHARSET "ISO-8859-1";
+
+div.menu {
+ border: 1px solid #000033;
+ background-color: #ddddee;
+ padding: 0.5em 0.5em 1em 0.5em;
+ margin: 0 1.0em 0 0;
+ float: left;
+ width: 180px;
+}
+div.menu h3 {
+ margin: 0 0 0.5em 0;
+}
+ div.menu h4, div.menu ul {
+ margin: 0;
+}
+div.content {
+ margin-left: 240px;
+}
+
+.error {
+ color: #ff0000;
+}
+
+table.table1 {
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+table.table1 th, table.grid th {
+ border-bottom: 2px solid black;
+ padding: 0.25em 0.5em;
+ text-align: left;
+ white-space: nowrap;
+}
+table.table1 td {
+ border-top: 1px solid black;
+ border-bottom: 1px solid black;
+ padding: 0.25em 0.5em;
+ vertical-align: top;
+ white-space: nowrap;
+}
+table.table1 th.spanleft, table.table1 td.spanleft {
+ padding-left: 0;
+ border-left: 0;
+}
+th.alignright, td.alignright {
+ text-align: right;
+}
+
+table.grid {
+ border-bottom: 1px solid black;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+table.grid td {
+ vertical-align: top;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+}
+
+input[type="text"], textarea {
+ font-family: sans-serif;
+ font-size: 90%;
+}
+input[type="submit"] {
+ margin: 0.25em 0.5em;
+}
+.label {
+ white-space: nowrap;
+}
+td.label {
+ padding-right: 0;
+}
+td.info {
+ padding-left: 1em;
+}
+td.special1 {
+ font-style: italic;
+}
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/index.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/index.jsp
new file mode 100644
index 0000000..8585eaf
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/index.jsp
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Welcome</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+<h2>Welcome</h2>
+
+<table class="grid">
+<tr><th colspan="2" scope="colgroup">Links</th></tr>
+<tr><td>StatET Project</td><td><a href="https://www.eclipse.org/statet">www.eclipse.org/statet</a></td></tr>
+<tr><td>R Project</td><td><a href="http://www.r-project.org">www.r-project.org</a></td></tr>
+</table>
+
+<table class="grid">
+<tr><th colspan="2" scope="colgroup">Sources</th></tr>
+<tr><td>RJ</td><td><a href="http://git.eclipse.org/c/statet/org.eclipse.statet-rj.git">git.eclipse.org/c/statet/org.eclipse.statet-rj.git</a></td></tr>
+</table>
+
+<hr/>
+
+<p>
+Copyright (c) 2007, 2017 Stephan Wahlbrink and others.</p>
+<p>
+This product includes software developed by The Apache Software Foundation
+(<a href="http://www.apache.org">www.apache.org</a>).</p>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/sessionexpired.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/sessionexpired.jsp
new file mode 100644
index 0000000..d74f2b9
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/sessionexpired.jsp
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Error</title>
+</head>
+<body>
+<%@include file="body-header.jspf" %>
+
+Sorry, your session expired.
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi.webapp/web/resources/status-poolnodes.jsp b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/status-poolnodes.jsp
new file mode 100644
index 0000000..90e92f8
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi.webapp/web/resources/status-poolnodes.jsp
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
+<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
+<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<%--
+ #=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+--%>
+<f:view>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<meta http-equiv="Content-Style-Type" content="text/css" />
+<link rel="stylesheet" type="text/css" href="css/style.css" />
+
+<title>(RJ) Status: Overview Pool Nodes</title>
+</head>
+
+<body onload="<c:if test="${poolStatus.autoRefreshEnabled}">window.setTimeout('javascript:document.getElementById(\'pool_nodes:refresh\').click()', 5000)</c:if>">
+
+<%@include file="body-header.jspf" %>
+
+<h2>Status: Current Pool Nodes</h2>
+
+<h:panelGrid columns="2" styleClass="grid" columnClasses=",," style="border-bottom: 2px solid black">
+ <h:outputLabel for="eff_pool_address" value="RMI pool address:" />
+ <h:inputText id="eff_pool_address" value="#{netConfig.effectivePoolAddress}" readonly="true" size="40" />
+</h:panelGrid>
+
+<h:form id="pool_nodes">
+ <h:messages errorClass="error" />
+
+<h:inputHidden value="#{poolStatus.autoRefreshEnabled}" immediate="true" />
+<h:commandButton id="refresh" value="Refresh" action="#{poolStatus.actionRefresh}" />
+<c:if test="${!poolStatus.autoRefreshEnabled}">
+<h:commandButton id="enableAutoRefresh" value="Enable Auto Refresh" action="#{poolStatus.actionEnableAutoRefresh}" />
+</c:if>
+<c:if test="${poolStatus.autoRefreshEnabled}">
+<h:commandButton id="disableAutoRefresh" value="Disable Auto Refresh" action="#{poolStatus.actionDisableAutoRefresh}" immediate="true" />
+</c:if>
+
+<br/>
+
+<h:panelGrid columns="3" styleClass="table1" columnClasses=",alignright,alignright">
+ <f:facet name="header"><h:outputText value="Summary" /></f:facet>
+
+ <h:outputText />
+ <h:outputText value="Current" />
+ <h:outputText value="Max" />
+
+ <h:outputText value="Idling:" />
+ <h:outputText value="#{poolStatus.numIdling}" />
+ <h:outputText value="#{poolStatus.maxIdling}" />
+
+ <h:outputText value="In use:" />
+ <h:outputText value="#{poolStatus.numInUse}" />
+ <h:outputText value="#{poolStatus.maxInUse}" />
+
+ <h:outputText value="Total:" />
+ <h:outputText value="#{poolStatus.numTotal}" />
+ <h:outputText value="#{poolStatus.maxTotal}" />
+</h:panelGrid>
+
+<br/>
+
+<h:dataTable value="#{poolStatus.nodeStates}" var="dataItem" styleClass="table1" columnClasses=",,spanleft,,alignright">
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Created" />
+ </f:facet>
+ <h:outputText value="#{dataItem.creationTime}" >
+ <f:convertDateTime pattern="yyyy-MM-dd HH:mm:ss"/>
+ </h:outputText>
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="State" />
+ </f:facet>
+ <h:outputText value="#{dataItem.state}" />
+ </h:column>
+
+ <h:column headerClass="spanleft">
+ <f:facet name="header">
+ <h:outputText value="" />
+ </f:facet>
+ (<h:outputText value="#{dataItem.stateTime - poolStatus.stamp}" >
+ <f:converter converterId="convertDuration" />
+ </h:outputText>)
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Client" />
+ </f:facet>
+ <h:outputText value="#{dataItem.currentClientId}" />
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Usage" />
+ </f:facet>
+ <h:outputText value="#{dataItem.usageCount}" />
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Debug Console" />
+ </f:facet>
+ <h:selectBooleanCheckbox value="#{dataItem.consoleEnabled}" readonly="true" disabled="true" />
+ <h:inputText value="#{dataItem.RMIAddress}" readonly="true" size="40" />
+ <h:outputText value=" " />
+ <h:commandLink value="On" action="#{dataItem.actionEnableConsole}" rendered="#{!dataItem.consoleEnabled}" />
+ <h:commandLink value="Off" action="#{dataItem.actionDisableConsole}" rendered="#{dataItem.consoleEnabled}" />
+ </h:column>
+
+ <h:column>
+ <f:facet name="header">
+ <h:outputText value="Evict" />
+ </f:facet>
+ <h:commandLink value="Stop" action="#{dataItem.actionStop}" />
+ <h:outputText value=" " />
+ <h:commandLink value="Kill" action="#{dataItem.actionKill}" />
+ </h:column>
+
+</h:dataTable>
+
+<h:panelGrid columns="2" styleClass="grid" columnClasses=",info">
+ <f:facet name="header"><h:outputText value="Test Actions" /></f:facet>
+
+ <h:commandLink action="#{debug.actionNewNode}" immediate="true">Get node (<code>RServiPool#getRServi</code>)</h:commandLink>
+ <h:outputText value="acquire node from pool" />
+
+ <h:commandLink action="#{debug.actionCloseAllNodes}" immediate="true">Close all nodes (<code>RServi#close</code>)</h:commandLink>
+ <h:outputText value="return acquired nodes to pool" />
+</h:panelGrid>
+
+</h:form>
+
+<%@include file="body-footer.jspf" %>
+</body>
+</html>
+</f:view>
diff --git a/servi/org.eclipse.statet.rj.servi/.classpath b/servi/org.eclipse.statet.rj.servi/.classpath
new file mode 100644
index 0000000..b323920
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.classpath
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+ <attributes>
+ <attribute name="owner.project.facets" value="java"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="srcServer"/>
+ <classpathentry kind="src" path="srcServiPool"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/servi/org.eclipse.statet.rj.servi/.gitignore b/servi/org.eclipse.statet.rj.servi/.gitignore
new file mode 100644
index 0000000..5e56e04
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.gitignore
@@ -0,0 +1 @@
+/bin
diff --git a/servi/org.eclipse.statet.rj.servi/.project b/servi/org.eclipse.statet.rj.servi/.project
new file mode 100644
index 0000000..3ce8a73
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.project
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.statet.rj.servi</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ </natures>
+</projectDescription>
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.resources.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..99f26c0
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.runtime.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000..5a0ad22
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.core.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..ccb1eaa
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,325 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.codeComplete.argumentPrefixes=
+org.eclipse.jdt.core.codeComplete.argumentSuffixes=
+org.eclipse.jdt.core.codeComplete.fieldPrefixes=
+org.eclipse.jdt.core.codeComplete.fieldSuffixes=
+org.eclipse.jdt.core.codeComplete.localPrefixes=
+org.eclipse.jdt.core.codeComplete.localSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
+org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
+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=1.8
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.8
+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.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
+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.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_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=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_resources_in_try=85
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=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=2
+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=1
+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=2
+org.eclipse.jdt.core.formatter.blank_lines_before_package=1
+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.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.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=true
+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=100
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=false
+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=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=true
+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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=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=insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=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=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_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=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_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_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_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_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
+org.eclipse.jdt.core.formatter.insert_space_before_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_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_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_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_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=100
+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_assignment_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=false
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
+org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.ui.prefs b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000..e62a4f5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,131 @@
+cleanup.add_default_serial_version_id=true
+cleanup.add_generated_serial_version_id=false
+cleanup.add_missing_annotations=true
+cleanup.add_missing_deprecated_annotations=true
+cleanup.add_missing_methods=false
+cleanup.add_missing_nls_tags=false
+cleanup.add_missing_override_annotations=true
+cleanup.add_missing_override_annotations_interface_methods=true
+cleanup.add_serial_version_id=false
+cleanup.always_use_blocks=true
+cleanup.always_use_parentheses_in_expressions=true
+cleanup.always_use_this_for_non_static_field_access=true
+cleanup.always_use_this_for_non_static_method_access=false
+cleanup.convert_functional_interfaces=false
+cleanup.convert_to_enhanced_for_loop=false
+cleanup.correct_indentation=false
+cleanup.format_source_code=false
+cleanup.format_source_code_changes_only=false
+cleanup.insert_inferred_type_arguments=false
+cleanup.make_local_variable_final=true
+cleanup.make_parameters_final=true
+cleanup.make_private_fields_final=true
+cleanup.make_type_abstract_if_missing_method=false
+cleanup.make_variable_declarations_final=true
+cleanup.never_use_blocks=false
+cleanup.never_use_parentheses_in_expressions=false
+cleanup.organize_imports=true
+cleanup.qualify_static_field_accesses_with_declaring_class=false
+cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=false
+cleanup.qualify_static_member_accesses_with_declaring_class=true
+cleanup.qualify_static_method_accesses_with_declaring_class=false
+cleanup.remove_private_constructors=true
+cleanup.remove_redundant_type_arguments=true
+cleanup.remove_trailing_whitespaces=false
+cleanup.remove_trailing_whitespaces_all=true
+cleanup.remove_trailing_whitespaces_ignore_empty=false
+cleanup.remove_unnecessary_casts=true
+cleanup.remove_unnecessary_nls_tags=true
+cleanup.remove_unused_imports=true
+cleanup.remove_unused_local_variables=false
+cleanup.remove_unused_private_fields=true
+cleanup.remove_unused_private_members=false
+cleanup.remove_unused_private_methods=true
+cleanup.remove_unused_private_types=true
+cleanup.sort_members=false
+cleanup.sort_members_all=false
+cleanup.use_anonymous_class_creation=false
+cleanup.use_blocks=true
+cleanup.use_blocks_only_for_return_and_throw=false
+cleanup.use_lambda=true
+cleanup.use_parentheses_in_expressions=false
+cleanup.use_this_for_non_static_field_access=true
+cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+cleanup.use_this_for_non_static_method_access=true
+cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+cleanup.use_type_arguments=false
+cleanup_profile=_StatET
+cleanup_settings_version=2
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_StatET
+formatter_settings_version=12
+org.eclipse.jdt.ui.exception.name=e
+org.eclipse.jdt.ui.gettersetter.use.is=true
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=\#;java;javax;com.ibm.icu;org.osgi;org.eclipse;;org.eclipse.statet.jcommons;org.eclipse.statet.ecommons;org.eclipse.statet;
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.keywordthis=true
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.overrideannotation=true
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/*\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\#\n \# Copyright (c) ${year} ${user} and others.\n # \n # This program and the accompanying materials are made available under the\n # terms of the Eclipse Public License 2.0 which is available at\n # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0\n # which is available at https://www.apache.org/licenses/LICENSE-2.0.\n # \n # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0\n # \n \# Contributors\:\n \# ${user} - initial API and implementation\n \#\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=*/</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="true" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment"/><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">${filecomment}\n\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+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=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=true
+sp_cleanup.always_use_this_for_non_static_field_access=true
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=false
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=true
+sp_cleanup.make_parameters_final=true
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=false
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+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=false
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=true
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=true
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=false
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=true
+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_private_fields=false
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=false
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.component b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..1cb3c70
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project-modules id="moduleCoreId" project-version="1.5.0">
+ <wb-module deploy-name="org.eclipse.statet.rj.servi">
+ <wb-resource deploy-path="/" source-path="/src"/>
+ <wb-resource deploy-path="/" source-path="/srcServer"/>
+ <wb-resource deploy-path="/" source-path="/srcServiPool"/>
+ </wb-module>
+</project-modules>
diff --git a/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.project.facet.core.xml b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..f4ef8aa
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<faceted-project>
+ <installed facet="java" version="1.8"/>
+</faceted-project>
diff --git a/servi/org.eclipse.statet.rj.servi/META-INF/MANIFEST.MF b/servi/org.eclipse.statet.rj.servi/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..1cb545f
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/META-INF/MANIFEST.MF
@@ -0,0 +1,21 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: org.eclipse.statet.rj.servi;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Vendor: Eclipse.org
+Bundle-Name: StatET RJ - RServi
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.statet.ecommons.runtime.core;bundle-version="1.1.0",
+ org.eclipse.statet.ecommons.rmi.core;bundle-version="1.4.0",
+ org.eclipse.statet.rj.data;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.server;bundle-version="[2.1.0,2.2.0)",
+ org.eclipse.statet.rj.services.core;bundle-version="[2.1.0,2.2.0)";visibility:=reexport,
+ org.eclipse.statet.rj.client;bundle-version="[2.1.0,2.2.0)",
+ org.apache.commons.pool
+Import-Package: org.eclipse.statet.jcommons.collections;version="1.0.0",
+ org.eclipse.statet.jcommons.lang;version="1.0.0"
+Export-Package: org.eclipse.statet.internal.rj.servi;x-friends:="org.eclipse.statet.rj.tests",
+ org.eclipse.statet.rj.servi;version="1.2.0",
+ org.eclipse.statet.rj.servi.node,
+ org.eclipse.statet.rj.servi.pool
diff --git a/servi/org.eclipse.statet.rj.servi/about.html b/servi/org.eclipse.statet.rj.servi/about.html
new file mode 100644
index 0000000..e71ae66
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/about.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>December 1, 2017</p>
+<h3>License</h3>
+
+<p>
+ 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"), or the Apache License,
+ Version 2.0 (AL). A copy of the EPL is available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
+ For purposes of the EPL, "Program" will mean the Content.
+ A copy of the AL is available at <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>.
+</p>
+
+<p>
+ 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 or AL still apply to any
+ source code in the Content and such source code may be obtained at <a
+ href="https://www.eclipse.org/">https://www.eclipse.org</a>.
+</p>
+
+</body>
+</html>
diff --git a/servi/org.eclipse.statet.rj.servi/build.properties b/servi/org.eclipse.statet.rj.servi/build.properties
new file mode 100644
index 0000000..625de79
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/build.properties
@@ -0,0 +1,16 @@
+source..= src/,\
+ srcServer/,\
+ srcServiPool/
+output..= bin/
+extra..= platform:/plugin/org.eclipse.osgi,\
+ platform:/plugin/org.eclipse.equinox.common,\
+ platform:/plugin/org.eclipse.core.runtime
+javacDefaultEncoding..= UTF-8
+
+bin.includes= META-INF/,\
+ .,\
+ plugin.xml,\
+ about.html,\
+ asl-v20.txt,\
+ NOTICE.txt
+src.includes= .settings/org.eclipse.core.resources.prefs
diff --git a/servi/org.eclipse.statet.rj.servi/plugin.xml b/servi/org.eclipse.statet.rj.servi/plugin.xml
new file mode 100644
index 0000000..4ec0dab
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/plugin.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<!--
+ #=============================================================================#
+ # Copyright (c) 2011, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================#
+-->
+
+<plugin>
+
+ <extension
+ point="org.eclipse.statet.ecommons.rmi.ERegistry">
+ <codebaseEntry
+ pluginId="org.eclipse.statet.rj.server"/>
+ </extension>
+
+</plugin>
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeFactory.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeFactory.java
new file mode 100644
index 0000000..b1aa907
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeFactory.java
@@ -0,0 +1,639 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.rmi.NotBoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.statet.jcommons.collections.CollectionUtils;
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.server.util.LocalREnv;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+import org.eclipse.statet.rj.servi.node.RServiNode;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+
+
+public class LocalNodeFactory implements NodeFactory {
+
+
+ public static final ImList<String> CODEBASE_LIBS= ImCollections.newList(
+ ServerUtils.RJ_SERVER_ID );
+
+ private static final Set<String> EXCLUDE_ENV_VAR_NAMES= ImCollections.newSet(
+ "CLASSPATH", "R_HOME");
+
+ private static void copySystemProperty(final String key, final List<String> command) {
+ final String property= System.getProperty(key);
+ if (property != null) {
+ command.add("-D" + key + "=" + property);
+ }
+ }
+
+ private static void copySystemPropertyPath(final String key, final List<String> command) {
+ String property= System.getProperty(key);
+ if (property != null) {
+ if (!new File(property).isAbsolute()) {
+ property= new File(System.getProperty("user.dir"), property).getPath();
+ }
+ command.add("-D" + key + "=" + property);
+ }
+ }
+
+ private static List<String> createSSLPropertyArgs() {
+ final List<String> args= new ArrayList<>();
+ copySystemPropertyPath("javax.net.ssl.keyStore", args);
+ copySystemProperty("javax.net.ssl.keyStorePassword", args);
+ copySystemPropertyPath("javax.net.ssl.trustStore", args);
+ copySystemProperty("javax.net.ssl.trustStorePassword", args);
+ return args;
+ }
+
+ private static class ProcessConfig {
+ final Map<String, String> addEnv= new HashMap<>();
+ final List<String> command= new ArrayList<>();
+ int nameCommandIdx= -1;
+ String baseWd;
+ String authConfig;
+ String rStartupSnippet;
+ }
+
+
+ private final String poolId;
+ private RServiNodeConfig baseConfig;
+ private final RJContext context;
+ private final ImList<String> libIds;
+
+ private ProcessConfig processConfig;
+
+ private String errorMessage= null;
+
+ private RMIRegistry nodeRegistry;
+
+ private boolean verbose;
+
+ private long timeoutNanos= TimeUnit.SECONDS.toNanos(30);
+
+ private final List<String> sslPropertyArgs;
+
+
+ public LocalNodeFactory(final String poolId,
+ final RJContext context, final List<String> libIds) {
+ if (poolId == null) {
+ throw new NullPointerException("poolId");
+ }
+ if (context == null) {
+ throw new NullPointerException("context");
+ }
+ this.poolId= poolId;
+ this.context= context;
+ this.libIds= ImCollections.toList(libIds);
+
+ this.sslPropertyArgs= createSSLPropertyArgs();
+ }
+
+
+ @Override
+ public void setRegistry(final RMIRegistry registry) {
+ this.nodeRegistry= registry;
+ }
+
+ @Override
+ public void setConfig(final RServiNodeConfig config) throws RjInvalidConfigurationException {
+ final ProcessConfig p= new ProcessConfig();
+ final StringBuilder sb= new StringBuilder();
+
+ // R home
+ final String rHome;
+ { String value= config.getRHome();
+ if (value == null || value.length() == 0) {
+ value= config.getEnvironmentVariables().get("R_HOME");
+ if (value == null || value.length() == 0) {
+ this.errorMessage= "Missing value for R_HOME.";
+ throw new RjInvalidConfigurationException(this.errorMessage);
+ }
+ }
+ rHome= value;
+ }
+ final File rHomeFile= new File(rHome);
+ if (!rHomeFile.exists() || !rHomeFile.isDirectory()) {
+ this.errorMessage= "Invalid value for R_HOME (directory does not exists).";
+ throw new RjInvalidConfigurationException(this.errorMessage);
+ }
+ p.addEnv.put("R_HOME", rHome);
+
+ // R lib path
+ final LocalREnv serverREnv= new LocalREnv((final String name) -> {
+ if (name.equals("R_HOME")) {
+ return rHome;
+ }
+ return config.getEnvironmentVariables().get(name);
+ });
+ final Path rjPkgPath= serverREnv.searchRPkg("rj");
+ if (rjPkgPath == null) {
+ this.errorMessage= "Could not find the R package 'rj' in the R library path:" +
+ CollectionUtils.toString(serverREnv.getRLibPaths(), "\n\t");
+ throw new RjInvalidConfigurationException(this.errorMessage);
+ }
+
+ // Java
+ String javaHome= config.getJavaHome();
+ if (javaHome == null || javaHome.length() == 0) {
+ javaHome= System.getProperty("java.home");
+ }
+ p.addEnv.put("JAVA_HOME", javaHome);
+
+ p.command.add(javaHome + File.separatorChar + "bin" + File.separatorChar + "java");
+
+ { p.command.add("-classpath");
+ final LinkedHashSet<String> classpath= new LinkedHashSet<>();
+ try {
+ classpath.add(rjPkgPath.resolve(Paths.get("server/rj-boot.jar")).toString());
+ classpath.addAll(this.context.searchRJLibs(this.libIds));
+ }
+ catch (final RjInvalidConfigurationException e) {
+ this.errorMessage= e.getMessage();
+ throw e;
+ }
+ String s= ServerUtils.concatPathVar(classpath);
+ final String env= config.getEnvironmentVariables().get("CLASSPATH");
+ if (env != null) {
+ s+= File.pathSeparatorChar + env;
+ }
+ p.command.add(s);
+ }
+
+ String javaArgs= config.getJavaArgs();
+ if (javaArgs != null && (javaArgs= javaArgs.trim()).length() > 0) {
+ p.command.addAll(Utils.parseArguments(javaArgs));
+ }
+ else {
+ javaArgs= "";
+ }
+
+ // RMI
+ final String hostname= System.getProperty("java.rmi.server.hostname");
+ if (hostname != null && hostname.length() > 0) {
+ p.command.add("-Djava.rmi.server.hostname=" + hostname);
+ }
+ if (javaArgs.indexOf("-Djava.security.policy=") < 0) {
+ sb.setLength(0);
+ sb.append("-Djava.security.policy=");
+ sb.append(this.context.getServerPolicyFilePath());
+ p.command.add(sb.toString());
+ }
+ if (javaArgs.indexOf("-Djava.rmi.server.codebase=") < 0) {
+ final List<String> libs;
+ try {
+ libs= this.context.searchRJLibs(CODEBASE_LIBS);
+ }
+ catch (final RjInvalidConfigurationException e) {
+ this.errorMessage= e.getMessage();
+ throw e;
+ }
+ sb.setLength(0);
+ sb.append("-Djava.rmi.server.codebase=");
+ sb.append(ServerUtils.concatCodebase(libs));
+ p.command.add(sb.toString());
+ }
+
+ // Main
+ p.command.add("RJSrv");
+ p.command.add("start");
+
+ p.nameCommandIdx= p.command.size();
+ p.command.add("");
+
+ p.command.add("-server=org.eclipse.statet.internal.rj.servi.server.NodeServer");
+ p.command.add("-log");
+
+ // ...
+ String nodeArgs= config.getNodeArgs();
+ if (nodeArgs != null && (nodeArgs= nodeArgs.trim()).length() > 0) {
+ p.command.addAll(Utils.parseArguments(nodeArgs));
+ }
+
+ String rArch= config.getRArch();
+ if (rArch != null && rArch.length() == 0) {
+ rArch= null;
+ }
+ boolean rArchAuto= false;
+ if (rArch == null && javaHome.equals(System.getProperty("java.home"))) {
+ rArch= System.getProperty("os.arch");
+ if (rArch.equals("amd64")) {
+ rArch= "x86_64";
+ }
+ else if (rArch.equals("x86")) {
+ rArch= "i386";
+ }
+ rArchAuto= true;
+ }
+ if (rArch != null) {
+ // validate R_ARCH
+ if (Utils.IS_WINDOWS) {
+ if (rArch.equals("x86_64")) {
+ rArch= "x64";
+ }
+ if (!new File(new File(rHomeFile, "bin"), rArch).exists()) {
+ rArch= null;
+ }
+ }
+ else {
+ final File execDir= new File(new File(rHomeFile, "bin"), "exec");
+ if (!new File(execDir, rArch).exists()) {
+ if (execDir.exists() &&
+ (rArch.equals("i386") || rArch.equals("i586") || rArch.equals("i686")) ) {
+ if (new File(execDir, "i686").exists()) {
+ rArch= "i686";
+ }
+ else if (new File(execDir, "i586").exists()) {
+ rArch= "i586";
+ }
+ else if (new File(execDir, "i386").exists()) {
+ rArch= "i386";
+ }
+ else {
+ rArch= null;
+ }
+ }
+ else {
+ rArch= null;
+ }
+ }
+ }
+ if (rArch != null) {
+ p.addEnv.put("R_ARCH", '/'+rArch);
+ }
+ else if (!rArchAuto) {
+ Utils.logInfo("Failed to validate specified architecture, value is not used.");
+ }
+ }
+
+ if (Utils.IS_WINDOWS) {
+ final String rBinDir;
+ if (rArch != null) {
+ rBinDir= rHome + File.separatorChar + "bin" + File.separatorChar + rArch;
+ }
+ else {
+ rBinDir= rHome + File.separatorChar + "bin";
+ }
+ final String pathEnv= System.getenv("PATH");
+ p.addEnv.put("PATH", (pathEnv != null) ? (rBinDir + File.pathSeparatorChar + pathEnv) : rBinDir);
+ }
+ else if (Utils.IS_MAC) {
+ final String rBinDir= rHome + File.separatorChar + "bin";
+ final String pathEnv= System.getenv("PATH");
+ p.addEnv.put("PATH", (pathEnv != null) ? (rBinDir + File.pathSeparatorChar + pathEnv) : rBinDir);
+
+ final String rLibDir= rHome + File.separatorChar + "lib";
+ final String libPathEnv= System.getenv("DYLD_LIBRARY_PATH");
+ p.addEnv.put("DYLD_LIBRARY_PATH", (libPathEnv != null) ? (rLibDir + File.pathSeparatorChar + libPathEnv) : rLibDir);
+ }
+ else {
+ final String rBinDir= rHome + File.separatorChar + "bin";
+ final String pathEnv= System.getenv("PATH");
+ p.addEnv.put("PATH", (pathEnv != null) ? (rBinDir + File.pathSeparatorChar + pathEnv) : rBinDir);
+
+ final String rLibDir;
+ if (rArch != null) {
+ rLibDir= rHome + File.separatorChar + "lib" + File.separatorChar + rArch;
+ }
+ else {
+ rLibDir= rHome + File.separatorChar + "lib";
+ }
+ final String libPathEnv= System.getenv("LD_LIBRARY_PATH");
+ p.addEnv.put("LD_LIBRARY_PATH", (libPathEnv != null) ? (rLibDir + File.pathSeparatorChar + libPathEnv) : rLibDir);
+ }
+
+ p.baseWd= config.getBaseWorkingDirectory();
+ if (p.baseWd == null || p.baseWd.length() == 0) {
+ p.baseWd= System.getProperty("java.io.tmpdir");
+ }
+ if (!testBaseDir(p.baseWd)) {
+ this.errorMessage= "Invalid working directory base path.";
+ throw new RjInvalidConfigurationException(this.errorMessage);
+ }
+
+ for (final Entry<String, String> var : config.getEnvironmentVariables().entrySet()) {
+ if (!EXCLUDE_ENV_VAR_NAMES.contains(var.getKey())) {
+ p.addEnv.put(var.getKey(), var.getValue());
+ }
+ }
+
+ p.authConfig= config.getEnableConsole() ? "none" : null;
+
+ p.rStartupSnippet= config.getRStartupSnippet();
+
+ long timeout= config.getStartStopTimeout();
+ if (timeout > 0) {
+ timeout= TimeUnit.MILLISECONDS.toNanos(timeout);
+ }
+ synchronized (this) {
+ this.verbose= config.getEnableVerbose();
+ this.baseConfig= config;
+ this.processConfig= p;
+ this.timeoutNanos= timeout;
+ }
+ }
+
+ private boolean testBaseDir(final String path) {
+ final File file= new File(path + File.separatorChar + this.poolId + "-test");
+ if (file.isDirectory()) {
+ return true;
+ }
+ if (file.mkdirs()) {
+ file.delete();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public RServiNodeConfig getConfig() {
+ return this.baseConfig;
+ }
+
+
+ @Override
+ public void createNode(final NodeHandler poolObj) throws RjException {
+ final long t= System.nanoTime();
+ final long timeout;
+
+ final ProcessConfig p;
+ final RMIRegistry registry;
+ synchronized (this) {
+ p= this.processConfig;
+ if (p == null) {
+ final String message= this.errorMessage;
+ throw new RjInvalidConfigurationException((message != null) ? message :
+ "Missing R node configuration.");
+ }
+ registry= this.nodeRegistry;
+ if (registry == null) {
+ throw new RjInvalidConfigurationException("Missing registry configuration.");
+ }
+ timeout= this.timeoutNanos;
+ }
+ ProcessBuilder pBuilder;
+ String id;
+ List<String> command= null;
+ try {
+ synchronized (this) {
+ for (int i= 0; ; i++) {
+ id= this.poolId + '-' + System.currentTimeMillis();
+ poolObj.dir= new File(p.baseWd + File.separatorChar + id);
+ if (!poolObj.dir.exists() && poolObj.dir.mkdirs()) {
+ break;
+ }
+ if (i >= 20) {
+ throw new RjException("Failed to create working directory (parent="+p.baseWd+").");
+ }
+ }
+ }
+ command= new ArrayList<>(p.command.size() + 2);
+ command.addAll(p.command);
+ poolObj.address= new RMIAddress(registry.getAddress(), id);
+ command.set(p.nameCommandIdx, poolObj.address.toString());
+ if (this.verbose) {
+ command.add("-verbose");
+ }
+ if (registry.getAddress().isSSL()) {
+ command.addAll(p.nameCommandIdx - 1, this.sslPropertyArgs);
+ }
+ pBuilder= new ProcessBuilder(command);
+ pBuilder.environment().remove("Path");
+ pBuilder.environment().putAll(p.addEnv);
+ pBuilder.directory(poolObj.dir);
+ pBuilder.redirectErrorStream(true);
+ }
+ catch (final Exception e) {
+ throw new RjException("Error preparing R node.", e);
+ }
+ Process process= null;
+ try {
+ process= pBuilder.start();
+
+ for (int i= 1; i < Integer.MAX_VALUE; i++) {
+ try {
+ final Server server= (Server) registry.getRegistry().lookup(id);
+ final ServerLogin login= server.createLogin(Server.C_RSERVI_NODECONTROL);
+ final RServiNode node= (RServiNode) server.execute(Server.C_RSERVI_NODECONTROL, null, login);
+
+ Utils.logInfo("New R node started (t="+((System.nanoTime()-t)/1000000)+"ms).");
+
+ String line= null;
+ try {
+ if (p.rStartupSnippet != null && p.rStartupSnippet.length() > 0) {
+ final String[] lines= p.rStartupSnippet.split("\\p{Blank}*\\r[\\n]?|\\n\\p{Blank}*"); //$NON-NLS-1$
+ for (int j= 0; j < lines.length; j++) {
+ line= lines[j];
+ if (line.length() > 0) {
+ node.runSnippet(line);
+ }
+ }
+ }
+ }
+ catch (final RjException e) {
+ try {
+ node.shutdown();
+ }
+ catch (final Exception ignore) {}
+ throw new RjException("Running the R startup snippet failed in line '" + line + "'.", e);
+ }
+ try {
+ poolObj.isConsoleEnabled= node.setConsole(p.authConfig);
+ }
+ catch (final RjException e) {
+ try {
+ node.shutdown();
+ }
+ catch (final Exception ignore) {}
+ throw e;
+ }
+
+ poolObj.init(node, process);
+ return;
+ }
+ catch (final NotBoundException e) {
+ final long diff= System.nanoTime() - t;
+ if (i >= 10 && timeout >= 0 && diff > timeout) {
+ throw new RjException("Start of R node aborted because of timeout (t="+(diff/1000000L)+"ms).", e);
+ }
+ };
+
+ try {
+ final int exitValue= process.exitValue();
+ throw new RjException("R node process stopped (exit code= "+exitValue+").");
+ }
+ catch (final IllegalThreadStateException ok) {}
+
+ Thread.sleep(250);
+ }
+ }
+ catch (final Exception e) {
+ final StringBuilder sb= new StringBuilder("Error starting R node:");
+ if (pBuilder != null) {
+ sb.append("\n<COMMAND>");
+ ServerUtils.prettyPrint(pBuilder.command(), sb);
+ sb.append("\n</COMMAND>");
+ }
+ if (process != null) {
+ final char[] buffer= new char[4096];
+ final InputStream stdout= process.getInputStream();
+ {
+ sb.append("\n<STDOUT>\n");
+ final InputStreamReader reader= new InputStreamReader(stdout);
+ try { // read non-blocking
+ int n;
+ while (reader.ready() && (n= reader.read(buffer, 0, buffer.length)) >= 0) {
+ sb.append(buffer, 0, n);
+ }
+ }
+ catch (final IOException ignore) {
+ }
+ process.destroy();
+ try {
+ int n;
+ while ((n= reader.read(buffer, 0, buffer.length)) >= 0) {
+ sb.append(buffer, 0, n);
+ }
+ }
+ catch (final IOException ignore) {
+ }
+ finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ }
+ catch (final IOException ignore) {}
+ }
+ }
+ sb.append("</STDOUT>");
+ }
+ final File logfile= new File(poolObj.dir, "out.log");
+ if (logfile.exists()) {
+ sb.append("\n<LOG file=\"out.log\">\n");
+ FileReader reader= null;
+ try {
+ reader= new FileReader(logfile);
+ int n;
+ while ((n= reader.read(buffer, 0, buffer.length)) >= 0) {
+ sb.append(buffer, 0, n);
+ if (sb.length() > 100000) {
+ break;
+ }
+ }
+ }
+ catch (final IOException ignore) {
+ }
+ finally {
+ if (reader != null) {
+ try {
+ reader.close();
+ }
+ catch (final IOException ignore) {}
+ }
+ }
+ sb.append("</LOG>");
+ }
+ sb.append("\n--------");
+ }
+
+ Thread.interrupted();
+ if (poolObj.dir.exists() && poolObj.dir.isDirectory()) {
+ ServerUtils.delDir(poolObj.dir);
+ }
+ throw new RjException(sb.toString(), e);
+ }
+ }
+
+ @Override
+ public void stopNode(final NodeHandler poolObj) {
+ final long t= System.nanoTime();
+ final long timeout= this.timeoutNanos;
+
+ try {
+ poolObj.shutdown();
+ }
+ catch (final Throwable e) {
+ Utils.logWarning(Messages.ShutdownNode_error_message, e);
+ }
+
+ final Process process= poolObj.process;
+ poolObj.process= null;
+ if (process != null) {
+ for (int i= 0; i < Integer.MAX_VALUE; i++) {
+ try {
+ Thread.sleep(250);
+ }
+ catch (final InterruptedException e) {
+ }
+ try {
+ process.exitValue();
+ break;
+ }
+ catch (final IllegalThreadStateException e) {
+ final long diff= System.nanoTime() - t;
+ if (i >= 10 && timeout >= 0 && diff > timeout) {
+ process.destroy();
+ Utils.logWarning("Killed RServi node '" + poolObj.getAddress().getName() + "'.");
+ break;
+ }
+ continue;
+ }
+ }
+ }
+
+ if (!this.verbose && poolObj.dir != null
+ && poolObj.dir.exists() && poolObj.dir.isDirectory() ) {
+ for (int i= 0; i < 20; i++) {
+ try {
+ Thread.sleep(250);
+ }
+ catch (final InterruptedException e) {
+ }
+
+ if (!poolObj.dir.exists() || ServerUtils.delDir(poolObj.dir)) {
+ return;
+ }
+ }
+ Utils.logWarning("Failed to delete the RServi node working directory '" + poolObj.dir.toString() + "'.");
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeManager.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeManager.java
new file mode 100644
index 0000000..5b77126
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/LocalNodeManager.java
@@ -0,0 +1,159 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.RemoteException;
+import java.util.NoSuchElementException;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+
+
+public class LocalNodeManager implements RServiNodeManager, Disposable {
+
+
+ private class ThisNodeHandler extends NodeHandler implements RServiImpl.PoolRef {
+
+ @Override
+ public void returnObject(final long accessId) throws RjException, RemoteException {
+ returnRServi(accessId);
+ }
+
+ }
+
+
+ private final String id;
+
+ private final RMIRegistry registry;
+
+ private final LocalNodeFactory factory;
+
+ private ThisNodeHandler handler;
+
+ private boolean inUse;
+ private long accessId;
+
+
+ public LocalNodeManager(final String id, final RMIRegistry registry, final LocalNodeFactory factory) {
+ if (id == null || registry == null) {
+ throw new NullPointerException();
+ }
+ this.id= id;
+ this.registry= registry;
+ this.factory= factory;
+
+ Utils.preLoad();
+ }
+
+
+ @Override
+ public String getId() {
+ return this.id;
+ }
+
+ @Override
+ public RServiNodeFactory getFactory() {
+ return this.factory;
+ }
+
+ @Override
+ public void dispose() {
+ stop();
+ }
+
+ @Override
+ public synchronized void start() throws RjException {
+ final ThisNodeHandler poolObj= new ThisNodeHandler();
+ try {
+ this.factory.createNode(poolObj);
+ this.handler= poolObj;
+ ECommonsRuntime.getEnv().addStoppingListener(this);
+ }
+ catch (final Throwable e) {
+ ECommonsRuntime.getEnv().log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID,
+ Messages.StartNode_error_message, e ));
+ throw new RjInitFailedException(Messages.StartLocal_pub_error_message,
+ (e instanceof RjException) ? e : null);
+ }
+ }
+
+ @Override
+ public synchronized void stop() {
+ if (this.handler == null) {
+ return;
+ }
+ ECommonsRuntime.getEnv().removeStoppingListener(this);
+ if (this.inUse) {
+ returnRServi(this.accessId);
+ if (this.handler == null) {
+ return;
+ }
+ }
+ this.factory.stopNode(this.handler);
+ this.handler= null;
+ }
+
+ @Override
+ public synchronized RServi getRServi(final String name) throws NoSuchElementException, RjException {
+ if (this.handler == null) {
+ start();
+ }
+ if (this.inUse) {
+ throw new NoSuchElementException(Messages.GetRServi_NoInstance_pub_Single_message);
+ }
+ try {
+ this.handler.bindClient(name, "local");
+ }
+ catch (final Throwable e) {
+ ECommonsRuntime.getEnv().log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID,
+ Messages.BindClient_error_message, e ));
+ throw new RjException(Messages.GetRServi_pub_error_message);
+ }
+ this.inUse= true;
+ return new RServiImpl(this.accessId, this.handler, this.handler.getClientHandler());
+ }
+
+ private synchronized void returnRServi(final long accessId) {
+ if (this.handler == null) {
+ return;
+ }
+ if (this.accessId != accessId) {
+ throw new IllegalStateException("Access id no longer valid.");
+ }
+ this.inUse= false;
+ this.accessId++;
+ try {
+ this.handler.unbindClient();
+ }
+ catch (final Throwable e) {
+ ECommonsRuntime.getEnv().log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID,
+ Messages.UnbindClient_error_message, e ));
+ stop();
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Messages.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Messages.java
new file mode 100644
index 0000000..9e700f6
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Messages.java
@@ -0,0 +1,31 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+
+public class Messages {
+
+
+ public static String BindClient_error_message= "An exception was thrown when trying to bind the client (activate a node).";
+ public static String GetRServi_pub_error_message= "Cannot provide RServi instance: Internal error occurred.";
+ public static String GetRServi_NoInstance_pub_Single_message= "Cannot provide RServi instance: Single instance is already in use.";
+ public static String GetRServi_NoInstance_pub_Pool_message= "Cannot provide RServi instance: No free node available.";
+ public static String UnbindClient_error_message= "An exception was thrown when trying to unbind the client (passivate a node).";
+ public static String StartNode_error_message= "An exception was thrown when trying to start the node (make a node).";
+ public static String StartLocal_pub_error_message= "Cannot start the RServi instance.";
+ public static String ShutdownNode_error_message= "An exception was thrown when trying to shutdown the node (destroy a node).";
+ public static String RmiUnexportNode_error_message= "An exception was thrown when trying to unexport the node (destroy a node).";
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeFactory.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeFactory.java
new file mode 100644
index 0000000..f1cbfe5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeFactory.java
@@ -0,0 +1,27 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+
+
+public interface NodeFactory extends RServiNodeFactory {
+
+
+ void createNode(NodeHandler poolObj) throws RjException;
+ void stopNode(NodeHandler poolObj);
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeHandler.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeHandler.java
new file mode 100644
index 0000000..4778ca1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/NodeHandler.java
@@ -0,0 +1,128 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.File;
+import java.rmi.RemoteException;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.internal.rj.servi.server.RServiBackend;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNode;
+
+
+public abstract class NodeHandler {
+
+
+ protected RServiNode node;
+
+ RMIAddress address;
+ File dir;
+ Process process;
+
+ private String clientLabel;
+ private RServiBackend clientHandler;
+
+ boolean isConsoleEnabled;
+
+ private final long startTime;
+ private long shutdownTime;
+
+
+ public NodeHandler() {
+ this.startTime= System.currentTimeMillis();
+ this.shutdownTime= -1;
+ }
+
+
+ public boolean isConsoleEnabled() {
+ return this.isConsoleEnabled;
+ }
+
+ public void enableConsole(final String authConfig) throws RjException {
+ try {
+ this.isConsoleEnabled= this.node.setConsole(authConfig);
+ }
+ catch (final Exception e) {
+ Utils.logError("An error occurred when configuring the debug console.", e);
+ throw new RjException("An error occurred when configuring the debug console. See server log for detail.");
+ }
+ }
+
+ public void disableConsole() throws RjException {
+ enableConsole(null);
+ }
+
+ public RMIAddress getAddress() {
+ return this.address;
+ }
+
+
+ void init(final RServiNode node, final Process process) {
+ this.node= node;
+ this.process= process;
+ }
+
+ void bindClient(final String name, final String host) throws RemoteException {
+ final StringBuilder sb= new StringBuilder(80);
+ if (name != null) {
+ sb.append(name);
+ }
+ sb.append('@');
+ sb.append(host);
+ final String client= sb.toString();
+ this.clientHandler= this.node.bindClient(client);
+ setClientLabel(client);
+ }
+
+ void unbindClient() throws RemoteException {
+ this.clientHandler= null;
+ setClientLabel(null);
+ this.node.unbindClient();
+ }
+
+ void shutdown() throws RemoteException {
+ this.shutdownTime= System.currentTimeMillis();
+ this.clientHandler= null;
+ setClientLabel(null);
+ final RServiNode node= this.node;
+ this.node= null;
+ if (node != null) {
+ node.shutdown();
+ }
+ }
+
+ RServiBackend getClientHandler() {
+ return this.clientHandler;
+ }
+
+ void setClientLabel(final String clientLabel) {
+ this.clientLabel= clientLabel;
+ }
+
+ public String getClientLabel() {
+ return this.clientLabel;
+ }
+
+ public long getStartTime() {
+ return this.startTime;
+ }
+
+ public long getShutdownTime() {
+ return this.shutdownTime;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/RServiImpl.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/RServiImpl.java
new file mode 100644
index 0000000..3a341c8
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/RServiImpl.java
@@ -0,0 +1,324 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.io.OutputStream;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+import org.eclipse.statet.internal.rj.servi.server.RServiBackend;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.data.RObject;
+import org.eclipse.statet.rj.data.RReference;
+import org.eclipse.statet.rj.data.impl.DefaultRObjectFactory;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.client.AbstractRJComClient;
+import org.eclipse.statet.rj.server.client.AbstractRJComClientGraphicActions;
+import org.eclipse.statet.rj.server.client.FunctionCallImpl;
+import org.eclipse.statet.rj.server.client.RClientGraphicFactory;
+import org.eclipse.statet.rj.server.client.RGraphicCreatorImpl;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.services.FunctionCall;
+import org.eclipse.statet.rj.services.RGraphicCreator;
+import org.eclipse.statet.rj.services.RPlatform;
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * Client side {@link RServi} handler
+ */
+public class RServiImpl implements RServi, Externalizable {
+
+
+ private class RServiComClient extends AbstractRJComClient {
+
+
+ public RServiComClient() {
+ }
+
+
+ @Override
+ protected void initGraphicFactory() {
+ final Object graphicFactory= RjsComConfig.getProperty("rj.servi.graphicFactory");
+ final Object actionsFactory= RjsComConfig.getProperty("rj.servi.comClientGraphicActionsFactory");
+ if (graphicFactory instanceof RClientGraphicFactory) {
+ setGraphicFactory((RClientGraphicFactory) graphicFactory,
+ (actionsFactory instanceof AbstractRJComClientGraphicActions.Factory) ?
+ ((AbstractRJComClientGraphicActions.Factory) actionsFactory).create(
+ this, getRHandle() ) : null );
+ }
+ }
+
+ @Override
+ protected void handleServerStatus(final RjsStatus serverStatus, final IProgressMonitor monitor) throws CoreException {
+ switch (serverStatus.getCode()) {
+ case 0:
+ return;
+ case Server.S_DISCONNECTED:
+ case Server.S_LOST:
+ case Server.S_STOPPED:
+ break;
+ case RjsStatus.ERROR:
+ throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, "Server or IO error."));
+ default:
+ throw new IllegalStateException();
+ }
+
+ if (!isClosed()) {
+ setClosed(true);
+ handleStatus(new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, "RServi is disconnected."), monitor);
+ }
+ throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, "RServi is closed."));
+ }
+
+ @Override
+ protected void handleStatus(final Status status, final IProgressMonitor monitor) {
+ if (!status.isOK()) {
+ log(status);
+ }
+ }
+
+ @Override
+ protected void log(final IStatus status) {
+ ECommonsRuntime.getEnv().log(status);
+ }
+
+ }
+
+
+ public static interface PoolRef extends Remote {
+ void returnObject(long accessId) throws RjException, RemoteException;
+ }
+
+
+ private long accessId;
+ private PoolRef poolRef;
+ private RServiBackend backend;
+
+ private final AbstractRJComClient rjs= new RServiComClient();
+ private int rjsId;
+
+ private Object rHandle;
+
+
+ public RServiImpl(final long accessId, final PoolRef ref, final RServiBackend backend) {
+ this.accessId= accessId;
+ this.poolRef= ref;
+ this.backend= backend;
+ this.rjs.setServer(this.backend, 1);
+ }
+
+ public RServiImpl() {
+ }
+
+
+ public void setRHandle(final Object rHandle) {
+ this.rHandle= rHandle;
+ }
+
+ public Object getRHandle() {
+ return this.rHandle;
+ }
+
+ @Override
+ public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+ this.accessId= in.readLong();
+ this.poolRef= (PoolRef) in.readObject();
+ this.backend= (RServiBackend) in.readObject();
+ this.rjs.setServer(this.backend, 1);
+ }
+
+ @Override
+ public void writeExternal(final ObjectOutput out) throws IOException {
+ out.writeLong(this.accessId);
+ out.writeObject(this.poolRef);
+ out.writeObject(this.backend);
+ }
+
+
+ private void init() throws CoreException {
+ this.rjsId= RjsComConfig.registerClientComHandler(this.rjs);
+ final Map<String, Object> properties= new HashMap<>();
+ this.rjs.initClient(this.rHandle, this, properties, this.rjsId);
+ this.rjs.setRjsProperties(properties);
+ }
+
+ @Override
+ public boolean isClosed() {
+ return this.rjs.isClosed();
+ }
+
+ @Override
+ public synchronized void close() throws CoreException {
+ if (this.rjs.isClosed()) {
+ throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, 0,
+ "RServi is already closed.", null));
+ }
+ try {
+ this.rjs.setClosed(true);
+ this.poolRef.returnObject(this.accessId);
+ }
+ catch (final Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, 0,
+ "An error occurred when closing RServi instance.", e));
+ }
+ finally {
+ this.poolRef= null;
+ this.backend= null;
+ RjsComConfig.unregisterClientComHandler(this.rjsId);
+ this.rjs.disposeAllGraphics();
+ }
+ }
+
+
+ @Override
+ public RPlatform getPlatform() {
+ return this.rjs.getRPlatform();
+ }
+
+ @Override
+ public void evalVoid(final String expression,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ this.rjs.evalVoid(expression, null, monitor);
+ }
+
+ @Override
+ public void evalVoid(final String expression, final RObject envir,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ this.rjs.evalVoid(expression, envir, monitor);
+ }
+
+ @Override
+ public RObject evalData(final String expression,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return this.rjs.evalData(expression, null, null, 0, RService.DEPTH_INFINITE, monitor);
+ }
+
+ @Override
+ public RObject evalData(final String expression, final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return this.rjs.evalData(expression, null, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public RObject evalData(final String expression, final RObject envir,
+ final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return this.rjs.evalData(expression, envir, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public RObject evalData(final RReference reference,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return this.rjs.evalData(reference, null, 0, -1, monitor);
+ }
+
+ @Override
+ public RObject evalData(final RReference reference, final String factoryId, final int options, final int depth,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return this.rjs.evalData(reference, factoryId, options, depth, monitor);
+ }
+
+ @Override
+ public void assignData(final String expression, final RObject data,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ this.rjs.assignData(expression, data, null, monitor);
+ }
+
+ @Override
+ public void downloadFile(final OutputStream out, final String fileName, final int options,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ this.rjs.downloadFile(out, fileName, options, monitor);
+ }
+
+ @Override
+ public byte[] downloadFile(final String fileName, final int options,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return this.rjs.downloadFile(fileName, options, monitor);
+ }
+
+ @Override
+ public void uploadFile(final InputStream in, final long length, final String fileName, final int options,
+ final IProgressMonitor monitor) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ this.rjs.uploadFile(in, length, fileName, options, monitor);
+ }
+
+ @Override
+ public FunctionCall createFunctionCall(final String name) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return new FunctionCallImpl(this.rjs, name, DefaultRObjectFactory.INSTANCE);
+ }
+
+ @Override
+ public RGraphicCreator createRGraphicCreator(final int options) throws CoreException {
+ if (this.rjsId == 0) {
+ init();
+ }
+ return new RGraphicCreatorImpl(this, this.rjs, options);
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Utils.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Utils.java
new file mode 100644
index 0000000..940ead5
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/internal/rj/servi/Utils.java
@@ -0,0 +1,229 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime.AppEnvironment;
+
+import org.eclipse.statet.rj.servi.RServiUtil;
+
+
+public class Utils {
+
+
+ public static final boolean IS_WINDOWS= System.getProperty("os.name").toLowerCase().startsWith("win");
+ public static final boolean IS_MAC= System.getProperty("os.name").toLowerCase().startsWith("mac");
+
+
+ public static void preLoad() {
+ // Load class for errors
+ new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, Messages.StartNode_error_message);
+ }
+
+ /**
+ * Utility class to parse command line arguments.
+ */
+ private static class ArgumentParser {
+
+ private final String args;
+ private int index= 0;
+ private int ch= -1;
+
+ public ArgumentParser(final String args) {
+ this.args= args;
+ }
+
+ public List<String> parseArguments() {
+ final List<String> v= new ArrayList<>();
+
+ this.ch= getNext();
+ while (this.ch > 0) {
+ if (Character.isWhitespace((char) this.ch)) {
+ this.ch= getNext();
+ }
+ else {
+ if (this.ch == '"') {
+ final StringBuffer buf= new StringBuffer();
+ buf.append(parseString());
+ if (buf.length() == 0 && IS_WINDOWS) {
+ // empty string on windows platform
+ buf.append("\"\""); //$NON-NLS-1$
+ }
+ v.add(buf.toString());
+ }
+ else {
+ v.add(parseToken());
+ }
+ }
+ }
+
+ return v;
+ }
+
+ private int getNext() {
+ if (this.index < this.args.length()) {
+ return this.args.charAt(this.index++);
+ }
+ return -1;
+ }
+
+ private String parseString() {
+ this.ch= getNext();
+ if (this.ch == '"') {
+ this.ch= getNext();
+ return ""; //$NON-NLS-1$
+ }
+ final StringBuffer buf= new StringBuffer();
+ while (this.ch > 0 && this.ch != '"') {
+ if (this.ch == '\\') {
+ this.ch= getNext();
+ if (this.ch != '"') { // Only escape double quotes
+ buf.append('\\');
+ }
+ else {
+ if (IS_WINDOWS) {
+ buf.append('\\');
+ }
+ }
+ }
+ if (this.ch > 0) {
+ buf.append((char) this.ch);
+ this.ch= getNext();
+ }
+ }
+ this.ch= getNext();
+ return buf.toString();
+ }
+
+ private String parseToken() {
+ final StringBuffer buf= new StringBuffer();
+
+ while (this.ch > 0 && !Character.isWhitespace((char) this.ch)) {
+ if (this.ch == '\\') {
+ this.ch= getNext();
+ if (Character.isWhitespace((char) this.ch)) {
+ // end of token, don't lose trailing backslash
+ buf.append('\\');
+ return buf.toString();
+ }
+ if (this.ch > 0) {
+ if (this.ch != '"') { // Only escape double quotes
+ buf.append('\\');
+ }
+ else {
+ if (IS_WINDOWS) {
+ buf.append('\\');
+ }
+ }
+ buf.append((char) this.ch);
+ this.ch= getNext();
+ }
+ else if (this.ch == -1) { // Don't lose a trailing backslash
+ buf.append('\\');
+ }
+ }
+ else if (this.ch == '"') {
+ buf.append(parseString());
+ }
+ else {
+ buf.append((char) this.ch);
+ this.ch= getNext();
+ }
+ }
+ return buf.toString();
+ }
+ }
+
+ public static List<String> parseArguments(final String args) {
+ if (args == null) {
+ return new ArrayList<>(0);
+ }
+ else {
+ final ArgumentParser parser= new ArgumentParser(args);
+ return parser.parseArguments();
+ }
+ }
+
+ public static void logInfo(final String message) {
+ final AppEnvironment env= ECommonsRuntime.getEnv();
+ if (env != null) {
+ env.log(new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, message));
+ }
+ }
+
+ public static void logInfo(final String message, final Throwable e) {
+ final AppEnvironment env= ECommonsRuntime.getEnv();
+ if (env != null) {
+ env.log(new Status(IStatus.INFO, RServiUtil.RJ_SERVI_ID, message, e));
+ }
+ }
+
+ public static void logWarning(final String message) {
+ final AppEnvironment env= ECommonsRuntime.getEnv();
+ if (env != null) {
+ env.log(new Status(IStatus.WARNING, RServiUtil.RJ_SERVI_ID, message));
+ }
+ }
+
+ public static void logWarning(final String message, final Throwable e) {
+ final AppEnvironment env= ECommonsRuntime.getEnv();
+ if (env != null) {
+ env.log(new Status(IStatus.WARNING, RServiUtil.RJ_SERVI_ID, message, e));
+ }
+ }
+
+ public static void logError(final String message) {
+ final AppEnvironment env= ECommonsRuntime.getEnv();
+ if (env != null) {
+ env.log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, message));
+ }
+ }
+
+ public static void logError(final String message, final Throwable e) {
+ final AppEnvironment env= ECommonsRuntime.getEnv();
+ if (env != null) {
+ env.log(new Status(IStatus.ERROR, RServiUtil.RJ_SERVI_ID, message, e));
+ }
+ }
+
+ public static String getProperty(final Properties properties, final String key, final String altKey) {
+ String s= properties.getProperty(key);
+ if (s == null && altKey != null) {
+ s= properties.getProperty(altKey);
+ }
+ return s;
+ }
+
+ public static void setProperty(final Properties properties, final String key, final String value) {
+ if (value != null) {
+ properties.setProperty(key, value);
+ }
+ else {
+ properties.remove(key);
+ }
+ }
+
+
+ private Utils() {
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServi.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServi.java
new file mode 100644
index 0000000..bea9d66
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServi.java
@@ -0,0 +1,83 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.statet.rj.services.RService;
+
+
+/**
+ * A RServi provides {@link RService R services} as background computing engine without an
+ * interactive R console. An RServi can be for example connected to a server side R engine or
+ * an R engine embedded in the local application.
+ * <p>
+ * How to receive an RServi instance depends on the application.
+ * The RServi framework includes a server side RServi
+ * {@link org.eclipse.statet.rj.servi.node.RServiPool pool}
+ * which can be used to provide RServi instances. To get a RServi instance
+ * from such a pool which made available via RMI {@link org.eclipse.statet.rj.servi.pool.RServiUtil RServiUtil}
+ * provides helper methods to request a RServi instance.</p>
+ * <p>
+ * In many applications it is sufficient to use an RServi for a direct
+ * sequence of executions, so that request, evaluations and closing can be
+ * performed one after another in a single thread. If it is required to use
+ * the RServi multiple times (e.g. a large data set should be reused),
+ * the application must prevent concurrent access.</p>
+ * <p>
+ * A RServi instance must be closed if it is no longer used,
+ * so that the R service consumer doesn't block the resources.
+ * When using a RServi pool closing means that the RServi is returned
+ * to the pool and can can be used by other consumers.</p>
+ * <p>
+ * After closing the RServi all resources created by it, R data objects and
+ * files on the R host system are cleaned up. Client side R data objects and
+ * files are not affected by the clean up. After calling this method,
+ * the RServi instance can no longer be used; further function call will
+ * throw an exception.</p>
+ * <p>
+ * All common guidelines of {@link RService} should be taken into account.</p>
+ *
+ * @since 0.1
+ */
+public interface RServi extends RService {
+
+
+ /**
+ * Returns the current state of the RServi instance.
+ * <p>
+ * The RServi instance is usually closed by {@link #close()} or if a disconnection to the
+ * R engine was detected. The method does not actively test the connection.
+ *
+ * @return <code>true</code> if the RServi instance is closed, otherwise <code>false</code>.
+ * @since 1.2
+ */
+ boolean isClosed();
+
+ /**
+ * Closes this RServi instance. An cleanup of resources created by this RServi
+ * is automatically performed.
+ * <p>
+ * See {@link RServi class comment} for detail.</p>
+ * <p>
+ * After calling the method the RServi instance is closed even if the method
+ * thrown an exception.</p>
+ *
+ * @throws CoreException if the operation failed; the status
+ * of the exception contains detail about the cause
+ */
+ void close() throws CoreException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServiUtil.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServiUtil.java
new file mode 100644
index 0000000..e50411f
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/RServiUtil.java
@@ -0,0 +1,155 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi;
+
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.NotBoundException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.NoSuchElementException;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeManager;
+import org.eclipse.statet.rj.servi.node.RServiPool;
+
+
+/**
+ * The class provides utility methods for the work with {@link RServi}.
+ * <p>
+ * It is not intend to instance the class.</p>
+ */
+public class RServiUtil {
+
+
+ public static final String RJ_SERVI_ID= "org.eclipse.statet.rj.servi";
+ public static final String RJ_CLIENT_ID= "org.eclipse.statet.rj.client";
+
+
+ /**
+ * Requests a {@link RServi} instance from a pool. The pool must be accessible
+ * via RMI under the given address.
+ * <p>
+ * The R services returned by this method are available for exclusive usage
+ * by the caller (consumer). The consumer is responsible to return it to the pool
+ * by {@link RServi#close() closing} the RServi.
+ *
+ * For SSL connections, use the prefix <code>ssl:</code>. Note that SSL requires
+ * the configuration of keystore and truststore at server and client side.
+ *
+ * @param address the RMI address of the pool
+ * @param name a name which can be used to identify the client
+ * @return a reference to the RServi instance
+ * @throws CoreException if the operation was failed; the status
+ * of the exception contains detail about the cause
+ * @throws NoSuchElementException if there is currently no free RServi
+ * instance available. A later call with the same configuration
+ * can be successfully.
+ * @throws LoginException if the RServi request requires authentication
+ */
+ public static RServi getRServi(final String address, final String name) throws CoreException, NoSuchElementException, LoginException {
+ try {
+ RjsComConfig.setRMIClientSocketFactory(null);
+ RServiPool pool;
+ try {
+ final RMIAddress rmiAddress= new RMIAddress(address);
+ final Registry registry= LocateRegistry.getRegistry(rmiAddress.getHost(), rmiAddress.getPortNum(),
+ (rmiAddress.isSSL()) ? new SslRMIClientSocketFactory() : null );
+ pool= (RServiPool) registry.lookup(rmiAddress.getName());
+ }
+ catch (final MalformedURLException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "Invalid address for the RServi pool.", e));
+ }
+ catch (final UnknownHostException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "Invalid address for the RServi pool.", e));
+ }
+ catch (final NotBoundException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "The address does not point to a valid RServi pool.", e));
+ }
+ catch (final ClassCastException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "The address does not point to a valid/compatible RServi pool.", e));
+ }
+ catch (final RemoteException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "Failed looking for RServi pool in the RMI registry.", e));
+ }
+ try {
+ return pool.getRServi(name, null);
+ }
+ catch (final RjException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "Failed getting an RServi instance from the RServi pool.", e));
+ }
+ catch (final RemoteException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "Failed looking for RServi pool in the RMI registry.", e));
+ }
+ }
+ finally {
+ RjsComConfig.clearRMIClientSocketFactory();
+ }
+ }
+
+ /**
+ * Requests a {@link RServi} instance from the given manager. The manager must be
+ * configured and started.
+ * <p>
+ * The R services returned by this method are available for exclusive usage
+ * by the caller (consumer). The consumer is responsible to return it to the manager
+ * by {@link RServi#close() closing} the RServi.
+ *
+ * @param manager manager for RServi node(s)
+ * @param name a name which can be used to identify the client
+ * @return a reference to the RServi instance
+ * @throws CoreException if the operation was failed; the status
+ * of the exception contains detail about the cause
+ * @throws NoSuchElementException if there is currently no free RServi
+ * instance available. A later call with the same configuration
+ * can be successfully.
+ */
+ public static RServi getRServi(final RServiNodeManager manager, final String name) throws CoreException, NoSuchElementException {
+ if (manager == null) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "RServi is not available.", null));
+ }
+ try {
+ return manager.getRServi(name);
+ }
+ catch (final RjException e) {
+ throw new CoreException(new Status(IStatus.ERROR, RJ_SERVI_ID, 0,
+ "Failed getting an RServi instance.", e));
+ }
+ }
+
+
+ private RServiUtil() {
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/PropertiesBean.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/PropertiesBean.java
new file mode 100644
index 0000000..61863df
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/PropertiesBean.java
@@ -0,0 +1,58 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.util.Collection;
+import java.util.Properties;
+
+
+public interface PropertiesBean {
+
+
+ class ValidationMessage {
+
+
+ private final String propertyId;
+ private final String message;
+
+
+ public ValidationMessage(final String message) {
+ this(null, message);
+ }
+
+ public ValidationMessage(final String propertyId, final String message) {
+ this.propertyId= propertyId;
+ this.message= message;
+ }
+
+
+ public String getPropertyId() {
+ return this.propertyId;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+
+ }
+
+
+ String getBeanId();
+ void load(Properties map);
+ void save(Properties map);
+
+ boolean validate(Collection<ValidationMessage> messages);
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiImpl.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiImpl.java
new file mode 100644
index 0000000..a31bf89
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiImpl.java
@@ -0,0 +1,89 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_DATA_ID;
+import static org.eclipse.statet.rj.server.util.ServerUtils.RJ_SERVER_ID;
+import static org.eclipse.statet.rj.servi.RServiUtil.RJ_SERVI_ID;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.internal.rj.servi.LocalNodeFactory;
+import org.eclipse.statet.internal.rj.servi.LocalNodeManager;
+import org.eclipse.statet.internal.rj.servi.PoolManager;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+/**
+ * Factory for RServi objects
+ */
+public class RServiImpl {
+
+
+ private static final ImList<String> LIB_IDS= ImCollections.newList(
+ RJ_DATA_ID, RJ_SERVER_ID, RJ_SERVI_ID );
+
+
+ /**
+ * Creates a node factory establishing RServi nodes on the local system.
+ *
+ * This method is intended for RServi pools when utilizing the default bundles.
+ *
+ * @param poolId the id of the pool or application
+ * @param context context to resolve the RJ libraries
+ * @return a node factory
+ * @throws RjInvalidConfigurationException
+ */
+ public static RServiNodeFactory createLocalNodeFactory(final String poolId, final RJContext context)
+ throws RjInvalidConfigurationException {
+ final ImList<String> libIds= LIB_IDS;
+ context.searchRJLibs(libIds); // check
+
+ return new LocalNodeFactory(poolId, context, libIds);
+ }
+
+ /**
+ * Creates an {@link RServiPoolManager RServi pool}.
+ *
+ * @param poolId the id of the pool
+ * @param registry a handler for the RMI registry to use
+ * @return the pool manager
+ */
+ public static RServiPoolManager createPool(final String poolId, final RMIRegistry registry) {
+ return new PoolManager(poolId, registry);
+ }
+
+ /**
+ * Creates an {@link RServiNodeManager RServi node manager}.
+ *
+ * @param id the id (like the poolId)
+ * @param registry a handler for the RMI registry to use
+ * @param factory the node factory to use to establish the node
+ * @return the manager for the RServi instance
+ */
+ public static RServiNodeManager createNodeManager(final String id, final RMIRegistry registry,
+ final RServiNodeFactory factory) {
+ if (factory instanceof LocalNodeFactory) {
+ return new LocalNodeManager(id, registry, (LocalNodeFactory) factory);
+ }
+ throw new UnsupportedOperationException(factory.getClass().getName());
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNode.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNode.java
new file mode 100644
index 0000000..a5c9db0
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNode.java
@@ -0,0 +1,48 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+import org.eclipse.statet.internal.rj.servi.server.RServiBackend;
+import org.eclipse.statet.rj.RjException;
+
+
+public interface RServiNode extends Remote {
+
+
+ void ping() throws RemoteException;
+
+ String getPoolHost() throws RemoteException;
+ RServiBackend bindClient(String client) throws RemoteException;
+ void unbindClient() throws RemoteException;
+
+ void shutdown() throws RemoteException;
+
+ int getEvalTime() throws RemoteException;
+
+ boolean setConsole(String authConfig) throws RjException, RemoteException;
+
+ /**
+ * Runs the given code in R
+ *
+ * @param code the R code
+ * @throws RjException if an R error occurred when running the snippet
+ * @throws RemoteException if an RMI/communication error occurred
+ */
+ void runSnippet(String code) throws RjException, RemoteException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeConfig.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeConfig.java
new file mode 100644
index 0000000..960e0d6
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeConfig.java
@@ -0,0 +1,340 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.eclipse.statet.internal.rj.servi.Utils;
+
+
+/**
+ * Configuration for an R node.
+ */
+public class RServiNodeConfig implements PropertiesBean {
+
+
+ public static final String BEAN_ID= "rconfig";
+
+ public static final String R_HOME_ID= "r_home.path";
+
+ public static final String R_ARCH_ID= "r_arch.code";
+
+ public static final String JAVA_HOME_ID= "java_home.path";
+
+ public static final String JAVA_ARGS_ID= "java_cmd.args";
+ private static final String JAVA_ARGS_OLD_ID= "java_args.path";
+
+ public static final String NODE_ENVIRONMENT_VARIABLES_PREFIX= "node_environment.variables.";
+ public static final String NODE_ARGS_ID= "node_cmd.args";
+
+ public static final String BASE_WD_ID= "base_wd.path";
+
+ /**
+ * Property id for R startup snippet
+ *
+ * @see #setRStartupSnippet(String)
+ * @since 0.5
+ */
+ public static final String R_STARTUP_SNIPPET_ID= "r_startup.snippet";
+
+ public static final String CONSOLE_ENABLED_ID= "debug_console.enabled";
+
+ public static final String VERBOSE_ENABLED_ID= "debug_verbose.enabled";
+
+ /**
+ * Property id for timeout of start/stop of nodes
+ *
+ * @see #setStartStopTimeout(long)
+ * @since 2.0
+ */
+ public static final String STARTSTOP_TIMEOUT__ID= "startstop_timeout.millis";
+
+ private static final long STARTSTOP_TIMEOUT_DEFAULT= 30 * 1000;
+
+
+ private String rHome;
+ private String rArch;
+
+ private String javaHome;
+ private String javaArgs;
+
+ private final Map<String, String> environmentVariables= new HashMap<>();
+ private String nodeArgs;
+
+ private String baseWd;
+
+ private String rStartupSnippet;
+
+ private boolean enableConsole;
+ private boolean enableVerbose;
+
+ private long startStopTimeout;
+
+
+ public RServiNodeConfig() {
+ this.rHome= System.getenv("R_HOME");
+ this.rArch= System.getenv("R_ARCH");
+ this.javaArgs= "-server";
+ this.nodeArgs= "";
+ this.rStartupSnippet= "";
+ this.startStopTimeout= STARTSTOP_TIMEOUT_DEFAULT;
+ }
+
+ public RServiNodeConfig(final RServiNodeConfig config) {
+ this();
+ synchronized (config) {
+ load(config);
+ }
+ }
+
+
+ @Override
+ public String getBeanId() {
+ return BEAN_ID;
+ }
+
+ public synchronized void load(final RServiNodeConfig templ) {
+ this.rHome= templ.rHome;
+ this.rArch= templ.rArch;
+ this.javaHome= templ.javaHome;
+ this.javaArgs= templ.javaArgs;
+ this.environmentVariables.clear();
+ this.environmentVariables.putAll(templ.environmentVariables);
+ this.nodeArgs= templ.nodeArgs;
+ this.baseWd= templ.baseWd;
+ this.rStartupSnippet= templ.rStartupSnippet;
+ this.enableConsole= templ.enableConsole;
+ this.enableVerbose= templ.enableVerbose;
+ this.startStopTimeout= templ.startStopTimeout;
+ }
+
+ @Override
+ public synchronized void load(final Properties map) {
+ setRHome(map.getProperty(R_HOME_ID));
+ setRArch(map.getProperty(R_ARCH_ID));
+ setJavaHome(map.getProperty(JAVA_HOME_ID));
+ setJavaArgs(map.getProperty(JAVA_ARGS_ID));
+ if (this.javaArgs.length() == 0) {
+ setJavaArgs(map.getProperty(JAVA_ARGS_OLD_ID));
+ }
+ this.environmentVariables.clear();
+ final int prefixLength= NODE_ENVIRONMENT_VARIABLES_PREFIX.length();
+ for (final Entry<Object, Object> p : map.entrySet()) {
+ final String name= (String) p.getKey();
+ if (name != null && name.length() > prefixLength
+ && name.startsWith(NODE_ENVIRONMENT_VARIABLES_PREFIX)
+ && p.getValue() instanceof String) {
+ this.environmentVariables.put(name.substring(prefixLength), (String) p.getValue());
+ }
+ }
+ setNodeArgs(map.getProperty(NODE_ARGS_ID));
+ setBaseWorkingDirectory(map.getProperty(BASE_WD_ID));
+ setRStartupSnippet(map.getProperty(R_STARTUP_SNIPPET_ID));
+ setEnableConsole(Boolean.parseBoolean(map.getProperty(CONSOLE_ENABLED_ID)));
+ setEnableVerbose(Boolean.parseBoolean(map.getProperty(VERBOSE_ENABLED_ID)));
+ { final String s= map.getProperty(STARTSTOP_TIMEOUT__ID);
+ this.startStopTimeout= ((s != null) ? Long.parseLong(s) : STARTSTOP_TIMEOUT_DEFAULT);
+ }
+ }
+
+ @Override
+ public synchronized void save(final Properties map) {
+ Utils.setProperty(map, R_HOME_ID, this.rHome);
+ Utils.setProperty(map, R_ARCH_ID, this.rArch);
+ Utils.setProperty(map, JAVA_HOME_ID, this.javaHome);
+ Utils.setProperty(map, JAVA_ARGS_ID, this.javaArgs);
+ for (final Entry<String, String> variable : this.environmentVariables.entrySet()) {
+ map.setProperty(NODE_ENVIRONMENT_VARIABLES_PREFIX + variable.getKey(), variable.getValue());
+ }
+ Utils.setProperty(map, NODE_ARGS_ID, this.nodeArgs);
+ Utils.setProperty(map, BASE_WD_ID, this.baseWd);
+ Utils.setProperty(map, R_STARTUP_SNIPPET_ID, this.rStartupSnippet);
+ Utils.setProperty(map, CONSOLE_ENABLED_ID, Boolean.toString(this.enableConsole));
+ Utils.setProperty(map, VERBOSE_ENABLED_ID, Boolean.toString(this.enableVerbose));
+ Utils.setProperty(map, STARTSTOP_TIMEOUT__ID, Long.toString(this.startStopTimeout));
+ }
+
+ public synchronized void setRHome(final String path) {
+ this.rHome= path;
+ }
+
+ public synchronized String getRHome() {
+ return this.rHome;
+ }
+
+ public synchronized void setRArch(final String code) {
+ this.rArch= code;
+ }
+
+ public synchronized String getRArch() {
+ return this.rArch;
+ }
+
+ public synchronized String getJavaHome() {
+ return this.javaHome;
+ }
+
+ public synchronized void setJavaHome(final String javaHome) {
+ this.javaHome= (javaHome != null && javaHome.trim().length() > 0) ? javaHome : null;
+ }
+
+ public synchronized String getJavaArgs() {
+ return this.javaArgs;
+ }
+
+ public synchronized void setJavaArgs(final String args) {
+ this.javaArgs= (args != null) ? args : "";
+ }
+
+ /**
+ * Additional environment variables for the R process.
+ *
+ * @return a name - value map of the environment variables
+ */
+ public synchronized Map<String, String> getEnvironmentVariables() {
+ return this.environmentVariables;
+ }
+
+ public synchronized void addToClasspath(final String entry) {
+ String cp= this.environmentVariables.get("CLASSPATH");
+ if (cp != null) {
+ cp+= File.pathSeparatorChar + entry;
+ }
+ else {
+ cp= entry;
+ }
+ this.environmentVariables.put("CLASSPATH", cp);
+ }
+
+ public synchronized String getNodeArgs() {
+ return this.nodeArgs;
+ }
+
+ public synchronized void setNodeArgs(final String args) {
+ this.nodeArgs= (args != null) ? args : "";
+ }
+
+ public synchronized void setBaseWorkingDirectory(final String path) {
+ this.baseWd= (path != null && path.trim().length() > 0) ? path : null;
+ }
+
+ public synchronized String getBaseWorkingDirectory() {
+ return this.baseWd;
+ }
+
+ /**
+ * Returns the R code snippet to run at startup of a node.
+ *
+ * @return the code
+ *
+ * @see #setRStartupSnippet(String)
+ * @since 0.5
+ */
+ public synchronized String getRStartupSnippet() {
+ return this.rStartupSnippet;
+ }
+
+ /**
+ * Sets the R code snippet to run at startup of a node.
+ * <p>
+ * Typical use case is to load required R packages. The default is an empty snippet.
+ * If the execution of the code throws an error, the startup of the node is canceled.</p>
+ *
+ * @param code the R code to run
+ *
+ * @since 0.5
+ */
+ public synchronized void setRStartupSnippet(final String code) {
+ this.rStartupSnippet= (code != null) ? code : "";
+ }
+
+ public synchronized boolean getEnableConsole() {
+ return this.enableConsole;
+ }
+
+ public synchronized void setEnableConsole(final boolean enable) {
+ this.enableConsole= enable;
+ }
+
+ public synchronized boolean getEnableVerbose() {
+ return this.enableVerbose;
+ }
+
+ public synchronized void setEnableVerbose(final boolean enable) {
+ this.enableVerbose= enable;
+ }
+
+ /**
+ * Returns the timeout of start/stop of nodes
+ *
+ * @return the timeout in milliseconds
+ *
+ * @since 2.0
+ */
+ public long getStartStopTimeout() {
+ return this.startStopTimeout;
+ }
+
+ /**
+ * Sets the timeout of start/stop of nodes
+ *
+ * @param milliseconds the timeout in milliseconds
+ *
+ * @since 2.0
+ */
+ public void setStartStopTimeout(final long milliseconds) {
+ this.startStopTimeout= milliseconds;
+ }
+
+
+ @Override
+ public synchronized boolean validate(final Collection<ValidationMessage> messages) {
+ boolean valid= true;
+
+ if (this.rHome != null && !new File(this.rHome).exists()) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(R_HOME_ID, "The directory does not exist."));
+ }
+ valid= false;
+ }
+ if (this.javaHome != null && !new File(this.javaHome).exists()) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(JAVA_HOME_ID, "The directory does not exist."));
+ }
+ valid= false;
+ }
+ if (this.baseWd != null && !new File(this.baseWd).exists()) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(BASE_WD_ID, "The directory does not exist."));
+ }
+ valid= false;
+ }
+
+ if (this.startStopTimeout != -1 && this.startStopTimeout < 0) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(STARTSTOP_TIMEOUT__ID, "Value must be > 0 or -1 (infinite)."));
+ }
+ valid= false;
+ }
+
+ return valid;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeFactory.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeFactory.java
new file mode 100644
index 0000000..4a893cb
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeFactory.java
@@ -0,0 +1,30 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+
+
+public interface RServiNodeFactory {
+
+
+ void setRegistry(RMIRegistry rmiRegistry);
+
+ RServiNodeConfig getConfig();
+ void setConfig(RServiNodeConfig config) throws RjInvalidConfigurationException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeManager.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeManager.java
new file mode 100644
index 0000000..a99472e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiNodeManager.java
@@ -0,0 +1,64 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.util.NoSuchElementException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.RServi;
+
+
+/**
+ * Manager for a directly controlled RServi instance.
+ *
+ * @see RServiImpl
+ */
+public interface RServiNodeManager {
+
+
+ String getId();
+
+ /**
+ * Returns the R factory passed during creation.
+ *
+ * @return the factory
+ */
+ RServiNodeFactory getFactory();
+
+ /**
+ * Starts the RServi respectively R instance.
+ * Does nothing if already started.
+ *
+ * @throws RjException if the node could not be started
+ */
+ void start() throws RjException;
+
+ /**
+ * Stops the RServi respectively R instance.
+ * Does nothing if not started.
+ */
+ void stop();
+
+ /**
+ * Returns the RServi instance.
+ *
+ * @param name
+ * @return the RServi instance
+ * @throws NoSuchElementException if the RServi instance is already in use
+ * @throws RjException if an error occurred
+ */
+ RServi getRServi(final String name) throws NoSuchElementException, RjException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiPool.java b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiPool.java
new file mode 100644
index 0000000..464f195
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/src/org/eclipse/statet/rj/servi/node/RServiPool.java
@@ -0,0 +1,54 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.node;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.servi.RServi;
+
+
+/**
+ * Generic interface to a pool providing RServi instances.
+ */
+public interface RServiPool extends Remote {
+
+
+ /**
+ * Requests a {@link RServi} instance from this pool.
+ *
+ * <p>The R services returned by this method are available for exclusive usage
+ * by the caller (consumer). The consumer is responsible to return it to the pool
+ * by {@link RServi#close() closing} the RServi.
+ *
+ * @param name a name which can be used to identify the client
+ * @param login not yet used
+ * @return an R services node
+ *
+ * @throws NoSuchElementException if there is currently no free RServi
+ * instance available. A later call with the same configuration
+ * can be successfully.
+ * @throws RjException when an server error occurs (retry not promising)
+ * @throws LoginException when the login failed
+ * @throws RemoteException when communication or runtime error occurs
+ */
+ RServi getRServi(String name, ServerLogin login) throws NoSuchElementException, RjException, LoginException, RemoteException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/NodeServer.java b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/NodeServer.java
new file mode 100644
index 0000000..1c51343
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/NodeServer.java
@@ -0,0 +1,460 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.server;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.rmi.ConnectException;
+import java.rmi.RemoteException;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.logging.Level;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+import javax.security.auth.login.LoginException;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.server.DataCmdItem;
+import org.eclipse.statet.rj.server.MainCmdC2SList;
+import org.eclipse.statet.rj.server.MainCmdItem;
+import org.eclipse.statet.rj.server.MainCmdS2CList;
+import org.eclipse.statet.rj.server.RjsComConfig;
+import org.eclipse.statet.rj.server.RjsComObject;
+import org.eclipse.statet.rj.server.RjsStatus;
+import org.eclipse.statet.rj.server.Server;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.server.srv.RMIServerControl;
+import org.eclipse.statet.rj.server.srv.engine.SrvEngineServer;
+import org.eclipse.statet.rj.server.srvext.Client;
+import org.eclipse.statet.rj.server.srvext.ServerAuthMethod;
+import org.eclipse.statet.rj.server.srvext.ServerRuntimePlugin;
+import org.eclipse.statet.rj.server.srvext.auth.NoAuthMethod;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+import org.eclipse.statet.rj.servi.node.RServiNode;
+
+
+public class NodeServer extends SrvEngineServer {
+
+
+ class ConsoleDummy extends Thread {
+
+ private final Client client;
+ private final PrintStream out;
+
+ private final MainCmdC2SList c2sList= new MainCmdC2SList();
+
+ ConsoleDummy(final Client client) {
+ setName("R Console");
+ setDaemon(true);
+ setPriority(NORM_PRIORITY-1);
+ this.client= client;
+ this.out= System.out;
+ }
+
+ @Override
+ public void run() {
+ try {
+ synchronized (NodeServer.this.srvEngine) {
+ if (NodeServer.this.isConsoleEnabled || NodeServer.this.isConsoleDummyRunning) {
+ return;
+ }
+ NodeServer.this.srvEngine.connect(this.client, new HashMap<String, Object>());
+ NodeServer.this.isConsoleDummyRunning= true;
+ }
+
+ RjsComObject sendCom= null;
+ boolean error= false;
+ while (true) {
+ try {
+ if (sendCom == null) {
+ this.c2sList.setObjects(null);
+ sendCom= this.c2sList;
+ }
+ final RjsComObject receivedCom= NodeServer.this.srvEngine.runMainLoop(this.client, sendCom);
+ sendCom= null;
+ error= false;
+ if (receivedCom != null) {
+ switch (receivedCom.getComType()) {
+ case RjsComObject.T_PING:
+ sendCom= RjsStatus.OK_STATUS;
+ break;
+ case RjsComObject.T_MAIN_LIST:
+ MainCmdItem item= ((MainCmdS2CList) receivedCom).getItems();
+ MainCmdItem tmp;
+ ITER_ITEMS : for (; (item != null); tmp= item, item= item.next, tmp.next= null) {
+ switch (item.getCmdType()) {
+ case MainCmdItem.T_CONSOLE_WRITE_ITEM:
+ this.out.println("R-OUT (" + item.getOp() + "): " + item.getDataText());
+ break;
+ case MainCmdItem.T_CONSOLE_READ_ITEM:
+ this.out.println("R-PROMPT: " + item.getDataText());
+ break;
+ }
+ }
+ break;
+ case RjsComObject.T_STATUS:
+ switch (((RjsStatus) receivedCom).getCode()) {
+ case Server.S_DISCONNECTED:
+ throw new ConnectException("");
+ case Server.S_LOST:
+ case Server.S_NOT_STARTED:
+ case Server.S_STOPPED:
+ return;
+ }
+ }
+ }
+ }
+ catch (final ConnectException e) {
+ synchronized (NodeServer.this.srvEngine) {
+ if (NodeServer.this.isConsoleEnabled) {
+ NodeServer.this.isConsoleDummyRunning= false;
+ return;
+ }
+ NodeServer.this.srvEngine.connect(this.client, new HashMap<String, Object>());
+ }
+ }
+ catch (final Exception e) {
+ if (error) {
+ throw e;
+ }
+ LOGGER.log(Level.SEVERE, "An error occurred when running dummy R REPL. Trying to continue REPL.", e);
+ error= true;
+ }
+ if (sendCom == null) {
+ try {
+ sleep(5000);
+ }
+ catch (final InterruptedException e) {
+ }
+ }
+ }
+ }
+ catch (final Exception e) {
+ LOGGER.log(Level.SEVERE, "An error occurred when running dummy R REPL. Stopping REPL.", e);
+ }
+ }
+
+ }
+
+ class Node implements RServiNode {
+
+ @Override
+ public boolean setConsole(final String authConfig) throws RemoteException, RjException {
+ final boolean enabled;
+ synchronized (NodeServer.this.srvEngine) {
+// LOGGER.fine("enter lock");
+ final Client currentClient= NodeServer.this.srvEngine.getCurrentClient();
+ if (currentClient != null) {
+ NodeServer.this.srvEngine.disconnect(currentClient);
+ }
+// LOGGER.fine("disconnect");
+ if (authConfig != null) {
+ NodeServer.this.authMethod= NodeServer.this.control.createServerAuth(authConfig);
+ enabled= NodeServer.this.isConsoleEnabled= true;
+ }
+ else {
+ NodeServer.this.authMethod= new NoAuthMethod("<internal>");
+ enabled= NodeServer.this.isConsoleEnabled= false;
+// LOGGER.fine("before start");
+ if (!NodeServer.this.isConsoleDummyRunning) {
+ new ConsoleDummy(NodeServer.this.consoleDummyClient).start();
+ }
+// LOGGER.fine("after start");
+ }
+ }
+ return enabled;
+ }
+
+ @Override
+ public int getEvalTime() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public void ping() throws RemoteException {
+ }
+
+ @Override
+ public String getPoolHost() throws RemoteException {
+ try {
+ return RemoteServer.getClientHost();
+ }
+ catch (final ServerNotActiveException e) {
+ return "<internal>";
+ }
+ }
+
+ @Override
+ public void runSnippet(final String code) throws RemoteException, RjException {
+ runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+ code, null, null, null ));
+ }
+
+ @Override
+ public RServiBackend bindClient(final String client) throws RemoteException {
+ return NodeServer.this.bindClient(client);
+ }
+
+ @Override
+ public void unbindClient() throws RemoteException {
+ NodeServer.this.unbindClient();
+ }
+
+ @Override
+ public void shutdown() throws RemoteException {
+ NodeServer.this.shutdown();
+ }
+
+ }
+
+ class Backend implements RServiBackend {
+
+ @Override
+ public Server getPublic() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> getPlatformData() {
+ return NodeServer.this.srvEngine.getPlatformData();
+ }
+
+ @Override
+ public void setProperties(final Map<String, ? extends Object> properties) throws RemoteException {
+ NodeServer.this.setProperties(properties, this);
+ }
+
+ public boolean interrupt() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void disconnect() throws RemoteException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RjsComObject runMainLoop(final RjsComObject com) throws RemoteException {
+ return NodeServer.this.runMainLoop(com, this);
+ }
+
+ @Override
+ public RjsComObject runAsync(final RjsComObject com) throws RemoteException {
+ return NodeServer.this.runAsync(com, this);
+ }
+
+ @Override
+ public boolean isClosed() throws RemoteException {
+ return (NodeServer.this.currentClientBackend != this);
+ }
+
+ }
+
+
+ private boolean isConsoleEnabled;
+ private boolean isConsoleDummyRunning;
+
+ private final ServerAuthMethod rserviAuthMethod;
+
+ private final Client consoleDummyClient;
+
+ private String currentClientId;
+ private Backend currentClientBackend;
+ private RServiBackend currentClientExp;
+
+ private final Object serviRunLock= new Object();
+
+ private String resetCommand;
+
+ private RMIClientSocketFactory clientSocketFactory;
+ private RMIServerSocketFactory serverSocketFactory;
+
+
+ public NodeServer(final RMIServerControl control) {
+ super(control, new NoAuthMethod("<internal>")); //$NON-NLS-1$
+ this.rserviAuthMethod= new NoAuthMethod("<internal>"); //$NON-NLS-1$
+ this.consoleDummyClient= new Client("-", "dummy", (byte) 0); //$NON-NLS-1$
+
+ if (control.getOptions().containsKey("ssl")) { //$NON-NLS-1$
+ this.clientSocketFactory= new SslRMIClientSocketFactory();
+ this.serverSocketFactory= new SslRMIServerSocketFactory(null, null, true);
+ }
+ }
+
+
+ @Override
+ public boolean getConfigUnbindOnStartup() {
+ return false;
+ }
+
+
+ @Override
+ public void start(final ServerRuntimePlugin runtimePlugin) throws Exception {
+ super.start(runtimePlugin);
+
+ this.resetCommand= "{" +
+ "rm(list=ls());" +
+ "gc();" +
+ ".rj.getTmp<-function(o){x<-get(o,pos=.GlobalEnv);rm(list=o,pos=.GlobalEnv);x};" +
+ ".rj.wd<-\""+this.workingDirectory.replace("\\", "\\\\")+"\";" +
+ "setwd(.rj.wd);" +
+ "graphics.off();" +
+ "}";
+ RjsComConfig.setServerPathResolver(this);
+
+ final Map<String, Object> properties= new HashMap<>();
+ properties.put("args", new String[0]);
+ this.srvEngine.start(this.consoleDummyClient, properties);
+
+ try {
+ synchronized (this.serviRunLock) {
+ LOGGER.log(Level.FINE, "Initializing R node: Loading R package 'rj'...");
+ runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+ "library(rj)", null, null, null ));
+ LOGGER.log(Level.FINE, "Initializing R node: Preparing R workspace for first client...");
+ runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+ this.resetCommand, null, null, null ));
+ }
+ }
+ catch (final Exception e) {
+ throw new RjException("An error occurred while preparing initially the workspace.", e);
+ }
+
+ LOGGER.log(Level.FINE, "Initializing R node: R engine started and initialized.");
+ }
+
+ @Override
+ protected ServerAuthMethod getAuthMethod(final String command) {
+ if (command.startsWith("rservi")) {
+ return this.rserviAuthMethod;
+ }
+ return super.getAuthMethod(command);
+ }
+
+ @Override
+ public Object execute(final String command, final Map<String, ? extends Object> properties, final ServerLogin login) throws RemoteException, LoginException {
+ if (command.equals(C_CONSOLE_START)) {
+ throw new UnsupportedOperationException();
+ }
+ if (command.equals(C_CONSOLE_CONNECT)) {
+ synchronized (this.srvEngine) {
+ if (!this.isConsoleEnabled) {
+ throw new RemoteException("Console is not enabled.");
+ }
+ final Client client= connectClient(command, login);
+ return this.srvEngine.connect(client, properties);
+ }
+ }
+ if (command.equals(C_RSERVI_NODECONTROL)) {
+ final Client client= connectClient(command, login);
+ final Node node= new Node();
+ final RServiNode exported= (RServiNode) UnicastRemoteObject.exportObject(node, 0,
+ this.clientSocketFactory, this.serverSocketFactory );
+ return exported;
+ }
+ throw new UnsupportedOperationException();
+ }
+
+
+ RServiBackend bindClient(final String client) throws RemoteException {
+ synchronized (this.serverClient) {
+ if (NodeServer.this.currentClientBackend != null) {
+ throw new IllegalStateException();
+ }
+ final Backend backend= new Backend();
+ final RServiBackend export= (RServiBackend) UnicastRemoteObject.exportObject(backend, 0,
+ this.clientSocketFactory, this.serverSocketFactory );
+ this.currentClientId= client;
+ this.currentClientBackend= backend;
+ this.currentClientExp= export;
+ SrvEngineServer.addClient(export);
+ return export;
+ }
+ }
+
+ void unbindClient() throws RemoteException {
+ synchronized (this.serverClient) {
+ final Backend previous= this.currentClientBackend;
+ if (previous != null) {
+ SrvEngineServer.removeClient(this.currentClientExp);
+ this.currentClientId= null;
+ this.currentClientBackend= null;
+ this.currentClientExp= null;
+ UnicastRemoteObject.unexportObject(previous, true);
+ try {
+ synchronized (this.serviRunLock) {
+ runServerLoopCommand(null, new DataCmdItem(DataCmdItem.EVAL_EXPR_VOID, 0,
+ this.resetCommand, null, null, null ));
+ ServerUtils.cleanDir(new File(this.workingDirectory), "out.log");
+ }
+ }
+ catch (final Exception e) {
+ throw new RemoteException("An error occurred while resetting the workspace.", e);
+ }
+ }
+ }
+ }
+
+ void shutdown() {
+ this.control.checkCleanup();
+ new Timer(true).schedule(new TimerTask() {
+ @Override
+ public void run() {
+ try {
+ unbindClient();
+ }
+ catch (final Exception e) {
+ e.printStackTrace();
+ }
+ System.exit(0);
+ }
+ }, 500L);
+ }
+
+ public void setProperties(final Map<String, ? extends Object> properties, final Object caller) throws RemoteException {
+ synchronized (this.serviRunLock) {
+ if (caller != null && this.currentClientBackend != caller) {
+ throw new IllegalAccessError();
+ }
+ this.srvEngine.setProperties(this.serverClient, properties);
+ }
+ }
+
+ @Override
+ protected RjsComObject runMainLoop(final RjsComObject com, final Object caller) throws RemoteException {
+ synchronized (this.serviRunLock) {
+ if (caller != null && this.currentClientBackend != caller) {
+ throw new IllegalAccessError();
+ }
+ }
+ return super.runMainLoop(com, caller);
+ }
+
+ private RjsComObject runAsync(final RjsComObject com, final Backend backend) throws RemoteException {
+ if (backend != null && this.currentClientBackend != backend) {
+ throw new IllegalAccessError();
+ }
+ return this.srvEngine.runAsync(this.serverClient, com);
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/RServiBackend.java b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/RServiBackend.java
new file mode 100644
index 0000000..a959962
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServer/org/eclipse/statet/internal/rj/servi/server/RServiBackend.java
@@ -0,0 +1,23 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi.server;
+
+import java.rmi.Remote;
+
+import org.eclipse.statet.rj.server.REngine;
+
+
+public interface RServiBackend extends REngine, Remote {
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2.java
new file mode 100644
index 0000000..1006117
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2.java
@@ -0,0 +1,153 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultEvictionPolicy;
+import org.apache.commons.pool2.impl.EvictionConfig;
+import org.apache.commons.pool2.impl.EvictionPolicy;
+import org.apache.commons.pool2.impl.GenericObjectPool;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+
+import org.eclipse.statet.jcommons.collections.ImList;
+
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+
+
+public class APool2 extends GenericObjectPool<APool2NodeHandler> {
+
+
+ private static final EvictionPolicy<APool2NodeHandler> EVICTION_POLICY= new DefaultEvictionPolicy<APool2NodeHandler>() {
+
+ @Override
+ public boolean evict(final EvictionConfig config,
+ final PooledObject<APool2NodeHandler> underTest, final int idleCount) {
+ return (super.evict(config, underTest, idleCount)
+ || underTest.getObject().isEvictRequested(0) );
+ }
+
+ };
+
+
+ private static GenericObjectPoolConfig createAConfig(final PoolConfig config) {
+ final GenericObjectPoolConfig aConfig= new GenericObjectPoolConfig();
+
+ aConfig.setLifo(true);
+ aConfig.setTestOnReturn(true);
+ aConfig.setTestWhileIdle(false);
+ aConfig.setTestOnBorrow(false);
+ aConfig.setBlockWhenExhausted(true);
+ aConfig.setMaxTotal(config.getMaxTotalCount());
+ aConfig.setMaxWaitMillis(config.getMaxWaitTime());
+ aConfig.setMinIdle(config.getMinIdleCount());
+ aConfig.setMaxIdle(config.getMaxIdleCount());
+ aConfig.setMinEvictableIdleTimeMillis(0L);
+ aConfig.setSoftMinEvictableIdleTimeMillis(config.getMinIdleTime());
+ aConfig.setTimeBetweenEvictionRunsMillis(7500L);
+ aConfig.setNumTestsPerEvictionRun(-3);
+
+ return aConfig;
+ }
+
+
+ private final APool2NodeFactory factory;
+
+ private volatile boolean closing;
+
+
+ public APool2(final APool2NodeFactory factory, final PoolConfig config) {
+ super(factory, createAConfig(config));
+
+ factory.setPool(this);
+ this.factory= factory;
+ }
+
+
+ public void setConfig(final PoolConfig config) {
+ setConfig(createAConfig(config));
+ }
+
+
+ public APool2NodeHandler borrowObject(final String client) throws Exception {
+ if (this.closing) {
+ throw new IllegalStateException("Pool not open");
+ }
+
+ this.factory.registerArgs(client);
+ try {
+ return super.borrowObject();
+ }
+ finally {
+ this.factory.clearArgs();
+ }
+ }
+
+ @Override
+ public int getMinIdle() {
+ if (this.closing) {
+ return 0;
+ }
+ return super.getMinIdle();
+ }
+
+ public void close(final long evictionTimeout) {
+ this.closing= true;
+
+ clear();
+
+ final long evictNanos= APool2NodeHandler.evictNanos(evictionTimeout);
+ final boolean evictDirect= (evictionTimeout == 0);
+
+ final ImList<APool2NodeHandler> objects= this.factory.getAllObjects();
+ for (final APool2NodeHandler poolObj : objects) {
+ poolObj.doEvict(evictNanos, evictDirect);
+ }
+ }
+
+ @Override
+ public void evict() throws Exception {
+ int evicted;
+ do {
+ evicted= 0;
+ final long nanos= APool2NodeHandler.safeNanos(System.nanoTime());
+
+ final ImList<APool2NodeHandler> objects= this.factory.getAllObjects();
+ for (final APool2NodeHandler poolObj : objects) {
+ if (poolObj.isEvictRequested(nanos)) {
+ try {
+ evicted++;
+ invalidateObject(poolObj);
+ }
+ catch (final Exception e) {}
+ }
+ }
+ }
+ while (evicted > 0);
+
+ super.evict();
+
+ if (this.closing && this.factory.getNumAll() == 0) {
+ super.close();
+
+ this.factory.dispose();
+ }
+ }
+
+ @Override
+ protected EvictionPolicy<APool2NodeHandler> getEvictionPolicy() {
+ return EVICTION_POLICY;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeFactory.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeFactory.java
new file mode 100644
index 0000000..af6d8ae
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeFactory.java
@@ -0,0 +1,250 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteServer;
+import java.rmi.server.ServerNotActiveException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.PooledObjectFactory;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+import org.eclipse.statet.jcommons.collections.CopyOnWriteList;
+import org.eclipse.statet.jcommons.collections.ImList;
+
+
+public class APool2NodeFactory implements PooledObjectFactory<APool2NodeHandler> {
+
+
+ private APool2 pool;
+
+ private final NodeFactory nodeFactory;
+
+ private final CopyOnWriteList<APool2NodeHandler> nodes= new CopyOnWriteList<>();
+
+ private final CopyOnWriteIdentityListSet<PoolListener> poolListeners;
+
+ private int statMaxTotal;
+ private int statMaxAllocated;
+
+ private int maxUsageCount;
+
+ private RMIClientSocketFactory sslClientSocketFactory;
+ private RMIServerSocketFactory sslServerSocketFactory;
+
+ private final ThreadLocal<String> activateArguments= new ThreadLocal<>();
+
+ private final ExecutorService executor= Executors.newSingleThreadExecutor();
+
+
+ public APool2NodeFactory(final NodeFactory factory,
+ final CopyOnWriteIdentityListSet<PoolListener> poolListeners) {
+ this.nodeFactory= factory;
+ this.poolListeners= poolListeners;
+ }
+
+ void setPool(final APool2 pool) {
+ this.pool= pool;
+ }
+
+ void dispose() {
+ this.executor.shutdown();
+ }
+
+
+ public void setMaxUsageCount(final int count) {
+ this.maxUsageCount= count;
+ }
+
+ public int getNumAll() {
+ return this.nodes.size();
+ }
+
+ public ImList<APool2NodeHandler> getAllObjects() {
+ return this.nodes.toList();
+ }
+
+
+ @Override
+ public PooledObject<APool2NodeHandler> makeObject() throws Exception {
+ // start
+ final APool2NodeHandler poolObj= new APool2NodeHandler(this.pool);
+ synchronized (this.nodes) {
+ this.nodes.add(poolObj);
+
+ final int total= this.nodes.size();
+ if (total > this.statMaxTotal) {
+ this.statMaxTotal= total;
+ }
+ }
+
+ boolean ok= false;
+ try {
+ for (final PoolListener listener : this.poolListeners.toList()) {
+ try {
+ listener.initializing(poolObj);
+ }
+ catch (final Exception e) {
+ e.printStackTrace(); // TODO
+ }
+ }
+
+ this.nodeFactory.createNode(poolObj);
+
+ { RMIClientSocketFactory clientSocketFactory= null;
+ RMIServerSocketFactory serverSocketFactory= null;
+ if (poolObj.address.isSSL()) {
+ synchronized (this) {
+ if (this.sslClientSocketFactory == null) {
+ this.sslClientSocketFactory= new SslRMIClientSocketFactory();
+ this.sslServerSocketFactory= new SslRMIServerSocketFactory(null, null, true);
+ }
+ clientSocketFactory= this.sslClientSocketFactory;
+ serverSocketFactory= this.sslServerSocketFactory;
+ }
+ }
+ poolObj.thisRemote= UnicastRemoteObject.exportObject(poolObj, 0,
+ clientSocketFactory, serverSocketFactory );
+ }
+
+ for (final PoolListener listener : this.poolListeners.toList()) {
+ try {
+ listener.initialized(poolObj);
+ }
+ catch (final Exception e) {
+ e.printStackTrace(); // TODO
+ }
+ }
+
+ ok= true;
+ return poolObj.getPooledObject();
+ }
+ finally {
+ if (!ok) {
+ this.nodes.remove(poolObj);
+ }
+ }
+ }
+
+
+ public void registerArgs(final String client) {
+ this.activateArguments.set(client);
+ }
+
+ public void clearArgs() {
+ this.activateArguments.remove();
+ }
+
+ @Override
+ public void activateObject(final PooledObject<APool2NodeHandler> p) throws Exception {
+ synchronized (this) {
+ final int numAllocated= this.pool.getNumActive();
+ if (numAllocated > this.statMaxAllocated) {
+ this.statMaxAllocated= numAllocated;
+ }
+ }
+
+ final String name= this.activateArguments.get();
+
+ final APool2NodeHandler poolObj= p.getObject();
+ String clientHost;
+ try {
+ clientHost= RemoteServer.getClientHost();
+ }
+ catch (final ServerNotActiveException e) {
+ clientHost= poolObj.node.getPoolHost();
+ }
+ poolObj.bindClient(name, clientHost);
+ }
+
+ @Override
+ public void passivateObject(final PooledObject<APool2NodeHandler> p) throws Exception {
+ final APool2NodeHandler poolObj= p.getObject();
+ poolObj.unbindClient();
+ }
+
+ @Override
+ public boolean validateObject(final PooledObject<APool2NodeHandler> p) {
+ final APool2NodeHandler poolObj= p.getObject();
+
+ if (poolObj.isEvictRequested(0)) {
+ return false;
+ }
+
+ final int max= this.maxUsageCount;
+ if (max > 0 && ((DefaultPooledObject<?>) p).getBorrowedCount() > max) {
+ poolObj.stats.shutdownReason= Stats.MAX_USAGE;
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void destroyObject(final PooledObject<APool2NodeHandler> p) throws Exception {
+ final APool2NodeHandler poolObj= p.getObject();
+ try {
+ if (poolObj.thisRemote != null) {
+ try {
+ poolObj.thisRemote= null;
+ UnicastRemoteObject.unexportObject(poolObj, true);
+ }
+ catch (final Throwable e) {
+ Utils.logWarning(Messages.RmiUnexportNode_error_message, e);
+ }
+ }
+ }
+ finally {
+ this.executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ APool2NodeFactory.this.nodeFactory.stopNode(poolObj);
+
+ for (final PoolListener listener : APool2NodeFactory.this.poolListeners.toList()) {
+ try {
+ listener.disposed(poolObj);
+ }
+ catch (final Exception e) {
+ e.printStackTrace(); // TODO
+ }
+ }
+ }
+ finally {
+ APool2NodeFactory.this.nodes.remove(poolObj);
+ }
+ }
+ });
+ }
+ }
+
+
+ public int getStatMaxTotal() {
+ return this.statMaxTotal;
+ }
+
+ public int getStatMaxAllocated() {
+ return this.statMaxAllocated;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeHandler.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeHandler.java
new file mode 100644
index 0000000..12cb215
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/APool2NodeHandler.java
@@ -0,0 +1,223 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.Unreferenced;
+
+import org.apache.commons.pool2.PooledObject;
+import org.apache.commons.pool2.impl.DefaultPooledObject;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolNodeState;
+
+
+public class APool2NodeHandler extends NodeHandler implements PoolNodeObject,
+ RServiImpl.PoolRef, Unreferenced {
+
+
+ static final long safeNanos(final long nanos) {
+ return (nanos != 0) ? nanos : 1;
+ }
+
+ static final long evictNanos(final long timeoutMillis) {
+ long nanos= System.nanoTime();
+ if (timeoutMillis > 0) {
+ nanos+= timeoutMillis * 1_000_000L;
+ }
+ return safeNanos(nanos);
+ }
+
+
+ private final APool2 pool;
+ private final DefaultPooledObject<APool2NodeHandler> p;
+ private volatile long evict;
+
+ final Stats.NodeEntry stats= new Stats.NodeEntry();
+
+ Remote thisRemote;
+
+ private volatile long clientId;
+
+
+ public APool2NodeHandler(final APool2 pool) {
+ this.pool= pool;
+ this.p= new DefaultPooledObject<>(this);
+ }
+
+
+ @Override
+ public NodeHandler getNodeHandler() {
+ return this;
+ }
+
+ PooledObject<APool2NodeHandler> getPooledObject() {
+ return this.p;
+ }
+
+ @Override
+ public long getCreationTime() {
+ return this.p.getCreateTime();
+ }
+
+ @Override
+ public long getAllocatedCount() {
+ return this.p.getBorrowedCount();
+ }
+
+ @Override
+ public long getAllocatedDuration() {
+ return this.p.getActiveTimeMillis();
+ }
+
+ @Override
+ public PoolNodeState getState() {
+ if (this.node == null) {
+ switch (this.p.getState()) {
+ case IDLE:
+ return PoolNodeState.INITIALIZING;
+ case INVALID:
+ return PoolNodeState.DISPOSED;
+ default:
+ break;
+ }
+ }
+
+ switch(this.p.getState()) {
+ case IDLE:
+ return PoolNodeState.IDLING;
+ case ALLOCATED:
+ return PoolNodeState.ALLOCATED;
+ case EVICTION:
+ return PoolNodeState.EVICTING;
+ default:
+ return PoolNodeState.CHECKING;
+ }
+ }
+
+ @Override
+ public long getStateTime() {
+ switch (getState()) {
+ case INITIALIZING:
+ return getStartTime();
+ case ALLOCATED:
+ return this.p.getLastBorrowTime();
+ case CHECKING:
+ case IDLING:
+ case EVICTING:
+ return this.p.getLastReturnTime();
+ case DISPOSED:
+ return getShutdownTime();
+ default:
+ return -1;
+ }
+ }
+
+
+ @Override
+ void bindClient(final String name, final String host) throws RemoteException {
+ super.bindClient(name, host);
+ synchronized (this) {
+ this.clientId= this.p.getBorrowedCount();
+ }
+ }
+
+ void invalidateClient() {
+ this.clientId= -1L;
+ setClientLabel(null);
+ }
+
+ @Override
+ void unbindClient() throws RemoteException {
+ synchronized (this) {
+ invalidateClient();
+ }
+ super.unbindClient();
+ }
+
+ @Override
+ public void evict(final long timeout) {
+ doEvict(evictNanos(timeout), timeout == 0);
+ }
+
+ void doEvict(final long nanos, boolean direct) {
+ synchronized (this.p) {
+ if (this.evict == 0 || this.evict > nanos) {
+ this.evict= safeNanos(nanos);
+ }
+
+ direct|= this.p.startEvictionTest();
+ }
+
+ if (direct) {
+ try {
+ this.pool.invalidateObject(this);
+ }
+ catch (final Exception e) {}
+ }
+ }
+
+ boolean isEvictRequested(final long nanos) {
+ final long evict= this.evict;
+ return (evict != 0
+ && (nanos == 0 || nanos >= evict) );
+ }
+
+ public long getAccessId() {
+ final long clientId= this.clientId;
+ if (clientId == -1L) {
+ throw new IllegalAccessError();
+ }
+ return clientId;
+ }
+
+ @Override
+ public void returnObject(final long accessId) throws RjException {
+ try {
+ synchronized (this) {
+ if (this.clientId != accessId) {
+ throw new IllegalStateException("Access id no longer valid.");
+ }
+ invalidateClient();
+ }
+ this.pool.returnObject(this);
+ }
+ catch (final Exception e) {
+ Utils.logError("An unexpected error occurred when returning RServi instance.", e);
+ throw new RjException("An unexpected error occurred when closing RServi instance. See server log for detail.");
+ }
+ }
+
+ @Override
+ public void unreferenced() {
+ final PoolNodeState state= getState();
+ synchronized (this) {
+ if (state != PoolNodeState.ALLOCATED || this.clientId == -1L) {
+ return;
+ }
+ invalidateClient();
+ }
+ Utils.logInfo("The RServi instance is lent and unreferenced. It will be returned now.");
+ try {
+ this.pool.returnObject(this);
+ }
+ catch (final Exception e) {
+ Utils.logError("An unexpected error occurred when returning RServi instance.", e);
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNetConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNetConfig.java
new file mode 100644
index 0000000..47cbc74
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNetConfig.java
@@ -0,0 +1,72 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.servi.jmx.NetConfigMXBean;
+import org.eclipse.statet.rj.servi.pool.NetConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNetConfig extends NetConfig implements NetConfigMXBean {
+
+
+ private final PoolServer server;
+
+ private ObjectName jmName;
+
+
+ public MXNetConfig(final PoolServer server) {
+ if (server == null) {
+ throw new NullPointerException("server");
+ }
+ this.server= server;
+ }
+
+
+ public void initJM() throws JMException {
+ this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.NetConfig");
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+ }
+
+ public void disposeJM() throws JMException {
+ if (this.jmName != null) {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+ this.jmName= null;
+ }
+ }
+
+
+ @Override
+ public void loadDefault() throws OperationsException {
+ load(new NetConfig());
+ }
+
+ @Override
+ public void loadSaved() throws OperationsException {
+ MXUtil.load(this, this.server.getRJContext());
+ }
+
+ @Override
+ public void save() throws OperationsException {
+ MXUtil.save(this, this.server.getRJContext());
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNode.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNode.java
new file mode 100644
index 0000000..314169c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNode.java
@@ -0,0 +1,126 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+import java.util.Date;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.jmx.NodeMXBean;
+import org.eclipse.statet.rj.servi.jmx.NodeStateMX;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNode implements NodeMXBean {
+
+
+ private final PoolServer server;
+ private final PoolNodeObject nodeObj;
+ private final RMIAddress address;
+ private final Date creationTime;
+
+ private ObjectName jmName;
+
+
+ public MXNode(final PoolServer server, final PoolNodeObject nodeObj) {
+ this.server= server;
+ this.nodeObj= nodeObj;
+ this.address= this.nodeObj.getNodeHandler().getAddress();
+ if (this.address == null) {
+ throw new NullPointerException("address");
+ }
+ this.creationTime= new Date(this.nodeObj.getCreationTime());
+ }
+
+
+ public void initJM() throws JMException {
+ this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.Node,rservi.nodeId=" + this.address.getName());
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+ }
+
+ public void disposeJM() throws JMException {
+ if (this.jmName != null) {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+ this.jmName= null;
+ }
+ }
+
+
+ @Override
+ public String getId() {
+ return this.address.getName();
+ }
+
+ @Override
+ public Date getCreationTime() {
+ return this.creationTime;
+ }
+
+ @Override
+ public NodeStateMX getState() {
+ final PoolNodeItem item= new PoolNodeItem(this.nodeObj, System.currentTimeMillis());
+ return new MXNodeState(item);
+ }
+
+ @Override
+ public boolean isConsoleEnabled() {
+ return this.nodeObj.getNodeHandler().isConsoleEnabled();
+ }
+
+ @Override
+ public synchronized void setConsoleEnabled(final boolean enable) throws OperationsException {
+ try {
+ if (enable) {
+ this.nodeObj.getNodeHandler().enableConsole("none");
+ }
+ else {
+ this.nodeObj.getNodeHandler().disableConsole();
+ }
+ }
+ catch (final RjException e) {
+ throw new OperationsException(e.getMessage());
+ }
+ }
+
+ @Override
+ public void stop() throws OperationsException {
+ final PoolConfig config= new PoolConfig();
+ this.server.getPoolConfig(config);
+ this.nodeObj.evict(config.getEvictionTimeout());
+ }
+
+ @Override
+ public void stop(final long timeoutMillis) throws OperationsException {
+ if (timeoutMillis < 0) {
+ throw new OperationsException("Invalid parameter 'timeoutMillis' >= 0.");
+ }
+ this.nodeObj.evict(timeoutMillis);
+ }
+
+ @Override
+ public void kill() throws OperationsException {
+ this.nodeObj.evict(0);
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeConfig.java
new file mode 100644
index 0000000..2e5e72c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeConfig.java
@@ -0,0 +1,105 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+import java.util.Map;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.servi.jmx.NodeConfigMXBean;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNodeConfig extends RServiNodeConfig implements NodeConfigMXBean {
+
+
+ private final PoolServer server;
+
+ private ObjectName jmName;
+
+
+ public MXNodeConfig(final PoolServer server) throws JMException {
+ if (server == null) {
+ throw new NullPointerException("server");
+ }
+ this.server= server;
+ }
+
+
+ public void initJM() throws JMException {
+ this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.NodeConfig");
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+ }
+
+ public void disposeJM() throws JMException {
+ if (this.jmName != null) {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+ this.jmName= null;
+ }
+ }
+
+
+ @Override
+ public synchronized void setEnvironmentVariable(final String name, final String value) {
+ final Map<String, String> variables= getEnvironmentVariables();
+ if (value == null) {
+ variables.remove(name);
+ }
+ else {
+ variables.put(name, value);
+ }
+ }
+
+
+ @Override
+ public void apply() throws OperationsException {
+ synchronized (this) {
+ MXUtil.validate(this);
+
+ try {
+ this.server.setNodeConfig(this);
+ }
+ catch (final RjInvalidConfigurationException e) {
+ throw new OperationsException(e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void loadActual() throws OperationsException {
+ this.server.getNodeConfig(this);
+ }
+
+ @Override
+ public void loadDefault() throws OperationsException {
+ load(new RServiNodeConfig());
+ }
+
+ @Override
+ public void loadSaved() throws OperationsException {
+ MXUtil.load(this, this.server.getRJContext());
+ }
+
+ @Override
+ public void save() throws OperationsException {
+ MXUtil.save(this, this.server.getRJContext());
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeManager.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeManager.java
new file mode 100644
index 0000000..9ebb8c7
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeManager.java
@@ -0,0 +1,119 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.management.JMException;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXNodeManager implements PoolListener {
+
+
+ private final PoolServer server;
+
+ private final Map<PoolNodeObject, MXNode> nodes= new HashMap<>();
+
+ private final PoolManager poolManager;
+
+
+ public MXNodeManager(final PoolServer server, final PoolManager poolManager) {
+ this.server= server;
+ this.poolManager= poolManager;
+ }
+
+
+ @Override
+ public void initializing(final PoolNodeObject nodeObj) {
+ }
+
+ @Override
+ public void initialized(final PoolNodeObject nodeObj) {
+ final MXNode node;
+ synchronized (this) {
+ if (this.nodes.containsKey(nodeObj)) {
+ return;
+ }
+ node= new MXNode(this.server, nodeObj);
+ this.nodes.put(nodeObj, node);
+ }
+ try {
+ node.initJM();
+ }
+ catch (final JMException e) {
+ Utils.logError("An error occurred when initializing JMX for node '" + node.getId() + "'.", e);
+ }
+ }
+
+ @Override
+ public void disposed(final PoolNodeObject nodeObj) {
+ final MXNode node= this.nodes.remove(nodeObj);
+ if (node != null) {
+ dispose(node);
+ }
+ }
+
+ private void dispose(final MXNode node) {
+ try {
+ node.disposeJM();
+ }
+ catch (final JMException e) {
+ Utils.logError("An error occurred when disposing JMX for node '" + node.getId() + "'.", e);
+ }
+ }
+
+ public void activate() {
+ this.poolManager.addPoolListener(this);
+
+ final Collection<? extends PoolNodeObject> objects= this.poolManager.getPoolNodeObjects();
+ synchronized (this) {
+ for (final PoolNodeObject nodeObj : objects) {
+ switch (nodeObj.getState()) {
+ case EVICTING:
+ case DISPOSED:
+ break;
+ default:
+ initialized(nodeObj);
+ break;
+ }
+ }
+ }
+ }
+
+ public void deactivate() {
+ this.poolManager.removePoolListener(this);
+
+ synchronized (this) {
+ try {
+ for (final Entry<PoolNodeObject, MXNode> entry : this.nodes.entrySet()) {
+ dispose(entry.getValue());
+ }
+ }
+ catch (final Exception e) {
+ e.printStackTrace();
+ }
+ finally {
+ this.nodes.clear();
+ }
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeState.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeState.java
new file mode 100644
index 0000000..757c6c1
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXNodeState.java
@@ -0,0 +1,80 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.util.Date;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.rj.servi.jmx.NodeStateMX;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolNodeState;
+
+
+public class MXNodeState implements NodeStateMX {
+
+
+ private final PoolNodeItem item;
+
+ private final Date creationTime;
+ private final Date stateTime;
+
+
+ public MXNodeState(final PoolNodeItem item) {
+ this.item= item;
+
+ this.creationTime= new Date(this.item.getCreationTime());
+ this.stateTime= new Date(this.item.getStateTime());
+ }
+
+
+ @Override
+ public PoolNodeState getState() {
+ return this.item.getState();
+ }
+
+ @Override
+ public Date getStateBeginTime() {
+ return this.stateTime;
+ }
+
+ @Override
+ public String getCurrentClientId() {
+ return this.item.getCurrentClientId();
+ }
+
+
+ @Override
+ public Date getCreationTime() {
+ return this.creationTime;
+ }
+
+ @Override
+ public long getUsageCount() {
+ return this.item.getUsageCount();
+ }
+
+ @Override
+ public long getUsageDuration() {
+ return this.item.getUsageDuration();
+ }
+
+ @Override
+ public String getRMIAddress() {
+ final RMIAddress address= this.item.getAddress();
+ return (address != null) ? address.getAddress() : "";
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolConfig.java
new file mode 100644
index 0000000..1c6593a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolConfig.java
@@ -0,0 +1,86 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.servi.jmx.PoolConfigMXBean;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+
+
+public class MXPoolConfig extends PoolConfig implements PoolConfigMXBean {
+
+
+ private final PoolServer server;
+
+ private ObjectName jmName;
+
+
+ public MXPoolConfig(final PoolServer server) throws JMException {
+ if (server == null) {
+ throw new NullPointerException("server");
+ }
+ this.server= server;
+ }
+
+
+ public void initJM() throws JMException {
+ this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.PoolConfig");
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+ }
+
+ public void disposeJM() throws JMException {
+ if (this.jmName != null) {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+ this.jmName= null;
+ }
+ }
+
+
+ @Override
+ public void apply() throws OperationsException {
+ synchronized (this) {
+ MXUtil.validate(this);
+
+ this.server.setPoolConfig(this);
+ }
+ }
+
+ @Override
+ public void loadActual() throws OperationsException {
+ this.server.getPoolConfig(this);
+ }
+
+ @Override
+ public void loadDefault() throws OperationsException {
+ load(new PoolConfig());
+ }
+
+ @Override
+ public void loadSaved() throws OperationsException {
+ MXUtil.load(this, this.server.getRJContext());
+ }
+
+ @Override
+ public void save() throws OperationsException {
+ MXUtil.save(this, this.server.getRJContext());
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolStatus.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolStatus.java
new file mode 100644
index 0000000..a78fe32
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXPoolStatus.java
@@ -0,0 +1,76 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.lang.management.ManagementFactory;
+import java.util.Date;
+
+import javax.management.JMException;
+import javax.management.ObjectName;
+
+import org.eclipse.statet.rj.servi.jmx.NodeStateMX;
+import org.eclipse.statet.rj.servi.jmx.PoolStatusMX;
+import org.eclipse.statet.rj.servi.pool.PoolNodeItem;
+import org.eclipse.statet.rj.servi.pool.PoolServer;
+import org.eclipse.statet.rj.servi.pool.PoolStatus;
+
+
+public class MXPoolStatus extends PoolStatus<NodeStateMX> implements PoolStatusMX {
+
+
+ private ObjectName jmName;
+
+ private Date time;
+
+
+ public MXPoolStatus(final PoolServer server) {
+ super(server);
+
+ refresh();
+ }
+
+
+ public void initJM() throws JMException {
+ this.jmName= new ObjectName(this.server.getJMBaseName() + "type=Server.PoolStatus");
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmName);
+ }
+
+ public void disposeJM() throws JMException {
+ if (this.jmName != null) {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmName);
+ this.jmName= null;
+ }
+ }
+
+ protected synchronized void refresh() {
+ final long stamp= System.currentTimeMillis();
+ refresh(this.server.getManager(), stamp);
+ this.time= new Date(stamp);
+ }
+
+
+ @Override
+ protected NodeStateMX createNodeState(final PoolNodeItem item) {
+ return new MXNodeState(item);
+ }
+
+
+ @Override
+ public synchronized Date getStatusTime() {
+ return this.time;
+ }
+
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXUtil.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXUtil.java
new file mode 100644
index 0000000..5fb08ac
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/MXUtil.java
@@ -0,0 +1,108 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.management.OperationsException;
+
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+import org.eclipse.statet.rj.servi.node.PropertiesBean.ValidationMessage;
+
+
+public class MXUtil {
+
+ public static boolean validate(final PropertiesBean bean) throws OperationsException {
+ final List<ValidationMessage> messages= new ArrayList<>();
+ if (bean.validate(messages)) {
+ return true;
+ }
+ final StringBuilder sb= new StringBuilder();
+ sb.append(MessageFormat.format("The configuration ''{0}'' has invalid values:\n", bean.getBeanId()));
+ for (final ValidationMessage message : messages) {
+ if (message.getPropertyId() != null) {
+ sb.append("{");
+ sb.append(message.getPropertyId());
+ sb.append("}: ");
+ }
+ sb.append(message);
+ sb.append('\n');
+ }
+ sb.deleteCharAt(sb.length() - 1);
+ throw new OperationsException(sb.toString());
+ }
+
+ public static PropertiesBean loadInit(final PropertiesBean bean, final RJContext context) throws RjInitFailedException {
+ try {
+ final Properties map= context.loadProperties(bean.getBeanId());
+ if (map == null) {
+ Utils.logInfo(MessageFormat.format("The configuration ''{0}'' could not be found. Default values are used.", bean.getBeanId()));
+ }
+ else {
+ bean.load(map);
+ bean.validate(null);
+ }
+
+ return bean;
+ }
+ catch (final IOException e) {
+ throw new RjInitFailedException(MessageFormat.format("Failed to load configuration ''{0}''.", bean.getBeanId()), e);
+ }
+ }
+
+
+ public static PropertiesBean load(final PropertiesBean bean, final RJContext context) throws OperationsException {
+ try {
+ final Properties map= context.loadProperties(bean.getBeanId());
+
+ synchronized (bean) {
+ bean.load(map);
+ validate(bean);
+ }
+
+ return bean;
+ }
+ catch (final IOException e) {
+ throw new OperationsException(MessageFormat.format("Failed to load configuration ''{0}'': {1}", bean.getBeanId(), e.getMessage()));
+ }
+ }
+
+ public static void save(final PropertiesBean bean, final RJContext context) throws OperationsException {
+ try {
+ final Properties map= new Properties();
+
+ synchronized (bean) {
+ if (!validate(bean)) {
+ return;
+ }
+ bean.save(map);
+ }
+
+ context.saveProperties(bean.getBeanId(), map);
+
+ return;
+ }
+ catch (final IOException e) {
+ throw new OperationsException(MessageFormat.format("Failed to save configuration ''{0}'': {1}", bean.getBeanId(), e.getMessage()));
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolListener.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolListener.java
new file mode 100644
index 0000000..270027d
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolListener.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+
+
+public interface PoolListener {
+
+
+ void initializing(PoolNodeObject nodeObj);
+ void initialized(PoolNodeObject nodeObj);
+
+ void disposed(PoolNodeObject nodeObj);
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolManager.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolManager.java
new file mode 100644
index 0000000..5c59c13
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/PoolManager.java
@@ -0,0 +1,230 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import java.rmi.Remote;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+import org.eclipse.statet.jcommons.collections.CopyOnWriteIdentityListSet;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.server.ServerLogin;
+import org.eclipse.statet.rj.servi.RServi;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+import org.eclipse.statet.rj.servi.node.RServiPool;
+import org.eclipse.statet.rj.servi.pool.PoolConfig;
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+import org.eclipse.statet.rj.servi.pool.RServiPoolManager;
+
+
+public class PoolManager implements RServiPool, RServiPoolManager {
+
+
+ private final String id;
+
+ private final RMIRegistry registry;
+
+ private Remote thisRemote;
+
+ private APool2 pool;
+ private APool2NodeFactory poolFactory;
+ private PoolConfig poolConfig;
+
+ private NodeFactory nodeFactory;
+
+ private final CopyOnWriteIdentityListSet<PoolListener> poolListeners= new CopyOnWriteIdentityListSet<>();
+ private final Stats stats;
+
+
+ public PoolManager(final String id, final RMIRegistry registry) {
+ if (id == null || registry == null) {
+ throw new NullPointerException();
+ }
+ this.id= id;
+ this.registry= registry;
+ this.stats= new Stats();
+ this.poolListeners.add(this.stats);
+ this.poolConfig= new PoolConfig();
+
+ Utils.preLoad();
+ }
+
+
+ @Override
+ public String getId() {
+ return this.id;
+ }
+
+ @Override
+ public NodeFactory getFactories() {
+ return this.nodeFactory;
+ }
+
+ @Override
+ public synchronized void addNodeFactory(final RServiNodeFactory factory) {
+ this.nodeFactory= (NodeFactory) factory;
+ }
+
+ @Override
+ public synchronized void setConfig(final PoolConfig config) {
+ if (this.pool != null) {
+ this.pool.setConfig(config);
+ this.poolFactory.setMaxUsageCount(config.getMaxUsageCount());
+ }
+ this.poolConfig= config;
+ }
+
+ @Override
+ public PoolConfig getConfig() {
+ return this.poolConfig;
+ }
+
+ public void addPoolListener(final PoolListener listener) {
+ this.poolListeners.add(listener);
+ }
+
+ public void removePoolListener(final PoolListener listener) {
+ this.poolListeners.remove(listener);
+ }
+
+ @Override
+ public synchronized void init() throws RjException {
+ this.poolFactory= new APool2NodeFactory(this.nodeFactory, this.poolListeners);
+ this.poolFactory.setMaxUsageCount(this.poolConfig.getMaxUsageCount());
+ this.pool= new APool2(this.poolFactory, this.poolConfig);
+
+ Utils.logInfo("Publishing pool in registry...");
+ if (this.registry != null) {
+ RMIClientSocketFactory clientSocketFactory= null;
+ RMIServerSocketFactory serverSocketFactory= null;
+ if (this.registry.getAddress().isSSL()) {
+ clientSocketFactory= new SslRMIClientSocketFactory();
+ serverSocketFactory= new SslRMIServerSocketFactory(null, null, true);
+ }
+ try {
+ this.thisRemote= UnicastRemoteObject.exportObject(this, 0,
+ clientSocketFactory, serverSocketFactory );
+ this.registry.getRegistry().rebind(PoolConfig.getPoolName(this.id), this.thisRemote);
+ }
+ catch (final Exception e) {
+ try {
+ stop(8);
+ }
+ catch (final Exception ignore) {}
+ Utils.logError("An error occurred when binding the pool in the registry.", e);
+ throw new RjInitFailedException("An error occurred when publishing the pool in the registry.");
+ }
+ }
+ }
+
+ @Override
+ public Collection<? extends PoolNodeObject> getPoolNodeObjects() {
+ return this.poolFactory.getAllObjects();
+ }
+
+ public boolean isInitialized() {
+ return (this.thisRemote != null);
+ }
+
+ @Override
+ public synchronized void stop(final int mode) throws RjException {
+ Utils.logInfo("Unpublishing pool...");
+ if (this.registry != null) {
+ try {
+ this.registry.getRegistry().unbind(PoolConfig.getPoolName(this.id));
+ }
+ catch (final Exception e) {
+ if (mode != 8) {
+ Utils.logError("An error occurred when unbinding the pool from the registry.", e);
+ }
+ }
+ }
+ if (this.thisRemote != null) {
+ try {
+ this.thisRemote= null;
+ UnicastRemoteObject.unexportObject(this, true);
+ }
+ catch (final Exception e) {
+ if (mode != 8) {
+ Utils.logError("An error occurred when unexport the pool.", e);
+ }
+ }
+ }
+
+ try {
+ Thread.sleep(1000);
+ }
+ catch (final InterruptedException e) {
+ }
+ if (PoolManager.this.pool != null) {
+ Utils.logInfo("Closing R nodes...");
+ try {
+ PoolManager.this.pool.close(this.poolConfig.getEvictionTimeout());
+ }
+ catch (final Exception e) {
+ Utils.logError("An error occurred when closing the pool.", e);
+ }
+ finally {
+ Runtime.getRuntime().gc();
+ }
+ }
+ }
+
+ @Override
+ public RServi getRServi(final String name, final ServerLogin login) throws NoSuchElementException, RjException {
+ final APool2NodeHandler handler= getPoolObject(name);
+ return new RServiImpl(handler.getAccessId(), handler, handler.getClientHandler());
+ }
+
+ public APool2NodeHandler getPoolObject(final String client) throws NoSuchElementException, RjException {
+ try {
+ return this.pool.borrowObject(client);
+ }
+ catch (final NoSuchElementException e) {
+ this.stats.logServRequestFailed(3);
+ throw new NoSuchElementException(Messages.GetRServi_NoInstance_pub_Pool_message);
+ }
+ catch (final Exception e) {
+ this.stats.logServRequestFailed(4);
+ Utils.logError(Messages.BindClient_error_message, e);
+ throw new RjException(Messages.GetRServi_pub_error_message);
+ }
+ }
+
+ @Override
+ public RServiPoolManager.Counter getCounter() {
+ final RServiPoolManager.Counter counter= new RServiPoolManager.Counter();
+ synchronized (this.pool) {
+ counter.numIdling= this.pool.getNumIdle();
+ counter.numInUse= this.pool.getNumActive();
+ counter.numTotal= counter.numIdling + counter.numTotal;
+ counter.maxIdling= -1;
+ counter.maxInUse= this.poolFactory.getStatMaxAllocated();
+ counter.maxTotal= this.poolFactory.getStatMaxTotal();
+ }
+ return counter;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/Stats.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/Stats.java
new file mode 100644
index 0000000..785fd21
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/internal/rj/servi/Stats.java
@@ -0,0 +1,57 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.rj.servi;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeObject;
+
+
+public class Stats implements PoolListener {
+
+
+ public final static int MAX_USAGE= 1;
+ public final static int VALIDATION_FAILED= 2;
+
+ public final static int EXHAUSTED_FAILED= 3;
+ public final static int UNEXPECTED_FAILED= 4;
+
+
+ static class NodeEntry {
+ int shutdownReason;
+ }
+
+
+// private final ArrayList<NodeEntry> tempList= new ArrayList<NodeEntry>();
+
+
+ @Override
+ public void initializing(final PoolNodeObject nodeObj) {
+ }
+
+ @Override
+ public void initialized(final PoolNodeObject nodeObj) {
+// this.tempList.add(p.stats);
+ }
+
+ @Override
+ public void disposed(final PoolNodeObject nodeObj) {
+ }
+
+ public void logServUsage(final int borrowTime, final int evalTime) {
+ }
+
+ public void logServRequestFailed(final int reason) {
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/DisplayName.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/DisplayName.java
new file mode 100644
index 0000000..c687e97
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/DisplayName.java
@@ -0,0 +1,35 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.management.DescriptorKey;
+
+
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DisplayName {
+
+
+ @DescriptorKey("displayName")
+ String value();
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NetConfigMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NetConfigMXBean.java
new file mode 100644
index 0000000..4862543
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NetConfigMXBean.java
@@ -0,0 +1,47 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface NetConfigMXBean {
+
+
+ @DisplayName("Host address (IP/name)")
+ String getHostAddress();
+ void setHostAddress(String address);
+
+ @DisplayName("RMI registry port (-1 \u21d2 default)")
+ int getRegistryPort();
+ void setRegistryPort(int port);
+
+ @DisplayName("Start embedded registry")
+ boolean getRegistryEmbed();
+ void setRegistryEmbed(boolean embed);
+
+ @DisplayName("Enable SSL")
+ boolean isSSLEnabled();
+ void setSSLEnabled(boolean enable);
+
+
+ @DisplayName("Load the default configuration")
+ void loadDefault() throws OperationsException;
+ @DisplayName("Load the saved configuration")
+ void loadSaved() throws OperationsException;
+ @DisplayName("Save the current configuration")
+ void save() throws OperationsException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeConfigMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeConfigMXBean.java
new file mode 100644
index 0000000..a83c43a
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeConfigMXBean.java
@@ -0,0 +1,79 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Map;
+
+import javax.management.OperationsException;
+
+
+public interface NodeConfigMXBean {
+
+
+ @DisplayName("Java home (path; empty \u21d2 same as the server)")
+ String getJavaHome();
+ void setJavaHome(String javaHome);
+
+ @DisplayName("Java arguments")
+ String getJavaArgs();
+ void setJavaArgs(String args);
+
+ @DisplayName("R home / R_HOME (path)")
+ String getRHome();
+ void setRHome(String path);
+
+ @DisplayName("Architecture of binaries / R_ARCH (empty \u21d2 autodetection)")
+ String getRArch();
+ void setRArch(String code);
+
+ @DisplayName("Environment variables (like R_LIBS)")
+ Map<String, String> getEnvironmentVariables();
+ @DisplayName("Add/Set/Remove an environment variable (like R_LIBS)")
+ void setEnvironmentVariable(String name, String value);
+
+ @DisplayName("Working directory (path; empty \u21d2 default temp dir)")
+ String getBaseWorkingDirectory();
+ void setBaseWorkingDirectory(String path);
+
+ @DisplayName("R startup snippet (complete R command per line)")
+ String getRStartupSnippet();
+ void setRStartupSnippet(String code);
+
+ @DisplayName("Timeout when starting/stopping node (millis)")
+ long getStartStopTimeout();
+ void setStartStopTimeout(long milliseconds);
+
+ @DisplayName("Enable debug console")
+ boolean getEnableConsole();
+ void setEnableConsole(boolean enable);
+
+ @DisplayName("Enable verbose logging")
+ boolean getEnableVerbose();
+ void setEnableVerbose(boolean enable);
+
+
+ @DisplayName("Apply the current configuration")
+ void apply() throws OperationsException;
+
+ @DisplayName("Reset current changes / load actual configuration")
+ void loadActual() throws OperationsException;
+ @DisplayName("Load the default configuration")
+ void loadDefault() throws OperationsException;
+ @DisplayName("Load the saved configuration")
+ void loadSaved() throws OperationsException;
+ @DisplayName("Save the current configuration")
+ void save() throws OperationsException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeMXBean.java
new file mode 100644
index 0000000..7654572
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeMXBean.java
@@ -0,0 +1,41 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Date;
+
+import javax.management.OperationsException;
+
+
+public interface NodeMXBean {
+
+
+ String getId();
+ Date getCreationTime();
+
+ NodeStateMX getState();
+
+ boolean isConsoleEnabled();
+ void setConsoleEnabled(boolean enable) throws OperationsException;
+
+
+ @DisplayName("Stop using the default timeout")
+ void stop() throws OperationsException;
+ @DisplayName("Stop using given timeout")
+ void stop(long timeoutMillis) throws OperationsException;
+ @DisplayName("Stop using timeout 0")
+ void kill() throws OperationsException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeStateMX.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeStateMX.java
new file mode 100644
index 0000000..d3f68a8
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/NodeStateMX.java
@@ -0,0 +1,39 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Date;
+
+import org.eclipse.statet.rj.servi.pool.PoolNodeState;
+
+
+public interface NodeStateMX {
+
+
+ Date getCreationTime();
+
+ PoolNodeState getState();
+
+ Date getStateBeginTime();
+
+ String getCurrentClientId();
+
+ long getUsageCount();
+
+ long getUsageDuration();
+
+ String getRMIAddress();
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolConfigMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolConfigMXBean.java
new file mode 100644
index 0000000..ea173ee
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolConfigMXBean.java
@@ -0,0 +1,64 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface PoolConfigMXBean {
+
+
+ @DisplayName("Max total nodes (count)")
+ int getMaxUsageCount();
+ void setMaxUsageCount(int count);
+
+ @DisplayName("Min idle nodes (count)")
+ long getMaxWaitTime();
+ void setMaxWaitTime(long milliseconds);
+
+ @DisplayName("Max idle nodes (count)")
+ long getMinIdleTime();
+ void setMinIdleTime(long milliseconds);
+
+ @DisplayName("Min node idle time (millisec)")
+ int getMaxIdleCount();
+ void setMaxIdleCount(int count);
+
+ @DisplayName("Max wait time (millisec)")
+ int getMinIdleCount();
+ void setMinIdleCount(int count);
+
+ @DisplayName("Max node reuse (count)")
+ int getMaxTotalCount();
+ void setMaxTotalCount(int count);
+
+ @DisplayName("Timeout when evicting node in use (millisec)")
+ long getEvictionTimeout();
+ void setEvictionTimeout(long milliseconds);
+
+
+ @DisplayName("Apply the current configuration")
+ void apply() throws OperationsException;
+
+ @DisplayName("Reset current changes / load actual configuration")
+ void loadActual() throws OperationsException;
+ @DisplayName("Load the default configuration")
+ void loadDefault() throws OperationsException;
+ @DisplayName("Load the saved configuration")
+ void loadSaved() throws OperationsException;
+ @DisplayName("Save the current configuration")
+ void save() throws OperationsException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolServerMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolServerMXBean.java
new file mode 100644
index 0000000..c9c9a7f
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolServerMXBean.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface PoolServerMXBean {
+
+
+ String getId();
+
+ String getPoolAddress();
+
+ PoolStatusMX getPoolStatus();
+
+ boolean isPoolNodeManagementEnabled();
+ void setPoolNodeManagementEnabled(boolean enable);
+
+
+ void start() throws OperationsException;
+ void stop() throws OperationsException;
+ void restart() throws OperationsException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolStatusMX.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolStatusMX.java
new file mode 100644
index 0000000..b603789
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/PoolStatusMX.java
@@ -0,0 +1,36 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import java.util.Date;
+import java.util.List;
+
+
+public interface PoolStatusMX {
+
+
+ Date getStatusTime();
+
+ int getNumInUse();
+ int getNumIdling();
+ int getNumTotal();
+
+ int getMaxInUse();
+ int getMaxIdling();
+ int getMaxTotal();
+
+ List<NodeStateMX> getNodeStates();
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/StandalonePoolServerMXBean.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/StandalonePoolServerMXBean.java
new file mode 100644
index 0000000..1fb62d3
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/jmx/StandalonePoolServerMXBean.java
@@ -0,0 +1,25 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.jmx;
+
+import javax.management.OperationsException;
+
+
+public interface StandalonePoolServerMXBean extends PoolServerMXBean {
+
+
+ void shutdown() throws OperationsException;
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/JMPoolServer.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/JMPoolServer.java
new file mode 100644
index 0000000..51f5809
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/JMPoolServer.java
@@ -0,0 +1,445 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.lang.management.ManagementFactory;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.RMIClientSocketFactory;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.management.ObjectName;
+import javax.management.OperationsException;
+import javax.rmi.ssl.SslRMIClientSocketFactory;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistry;
+import org.eclipse.statet.ecommons.rmi.core.RMIRegistryManager;
+
+import org.eclipse.statet.internal.rj.servi.MXNetConfig;
+import org.eclipse.statet.internal.rj.servi.MXNodeConfig;
+import org.eclipse.statet.internal.rj.servi.MXNodeManager;
+import org.eclipse.statet.internal.rj.servi.MXPoolConfig;
+import org.eclipse.statet.internal.rj.servi.MXPoolStatus;
+import org.eclipse.statet.internal.rj.servi.MXUtil;
+import org.eclipse.statet.internal.rj.servi.PoolManager;
+import org.eclipse.statet.internal.rj.servi.Utils;
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.server.util.ServerUtils;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.jmx.PoolServerMXBean;
+import org.eclipse.statet.rj.servi.jmx.PoolStatusMX;
+import org.eclipse.statet.rj.servi.node.RServiImpl;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+
+
+public class JMPoolServer implements PoolServer, PoolServerMXBean {
+
+
+ private final String id;
+ private final RJContext context;
+
+ private final String jmBaseName;
+ private ObjectName jmxName;
+
+ private RMIRegistry rmiRegistry;
+ private Set<Integer> rmiEmbeddedPorts;
+ private boolean rmiHostnameSet;
+
+ private String poolAddress;
+
+ private final MXNetConfig currentNetConfig;
+ private volatile PoolConfig currentPoolConfig;
+ private volatile RServiNodeConfig currentNodeConfig;
+
+ private final MXNetConfig jmNetConfig;
+ private final MXPoolConfig jmPoolConfig;
+ private final MXNodeConfig jmNodeConfig;
+
+ private volatile boolean jmIsNodeManagementEnabled;
+ private MXNodeManager jmNodeManager;
+
+ private final RServiNodeFactory nodeFactory;
+
+ private PoolManager poolManager;
+
+
+ public JMPoolServer(final String id, final RJContext context) throws RjInitFailedException {
+ this(id, context, true);
+ }
+
+ public JMPoolServer(final String id, final RJContext context, final boolean enableJM) throws RjInitFailedException {
+ this.id= id;
+ this.context= context;
+ this.jmBaseName= "RServi:rservi.id=" + getId() + ",";
+
+ this.currentNetConfig= (MXNetConfig) MXUtil.loadInit(new MXNetConfig(this), this.context);
+ this.currentPoolConfig= (PoolConfig) MXUtil.loadInit(new PoolConfig(), this.context);
+ this.currentNodeConfig= (RServiNodeConfig) MXUtil.loadInit(new RServiNodeConfig(), this.context);
+
+ try {
+ this.nodeFactory= RServiImpl.createLocalNodeFactory(this.id, this.context);
+ }
+ catch (final RjInvalidConfigurationException e) {
+ throw new RjInitFailedException("Creating local R node factory failed.", e);
+ }
+ try {
+ if (enableJM) {
+ this.jmxName= new ObjectName(this.jmBaseName + "type=Server");
+ ManagementFactory.getPlatformMBeanServer().registerMBean(this, this.jmxName);
+ }
+
+ this.jmNetConfig= this.currentNetConfig;
+ if (enableJM) {
+ this.jmNetConfig.initJM();
+ }
+
+ this.jmPoolConfig= new MXPoolConfig(this);
+ this.jmPoolConfig.load(this.currentPoolConfig);
+ if (enableJM) {
+ this.jmPoolConfig.initJM();
+ }
+
+ this.jmNodeConfig= new MXNodeConfig(this);
+ this.jmNodeConfig.load(this.currentNodeConfig);
+ if (enableJM) {
+ this.jmNodeConfig.initJM();
+ }
+ }
+ catch (final Exception e) {
+ try {
+ shutdown();
+ }
+ catch (final Exception e2) {}
+ throw new RjInitFailedException("Initializing JMX for pool server failed.", e);
+ }
+ try {
+ this.nodeFactory.setConfig(this.currentNodeConfig);
+ }
+ catch (final RjInvalidConfigurationException e) {
+ Utils.logWarning(e.getMessage());
+ }
+ }
+
+
+ @Override
+ public String getId() {
+ return this.id;
+ }
+
+ @Override
+ public RJContext getRJContext() {
+ return this.context;
+ }
+
+ @Override
+ public String getJMBaseName() {
+ return this.jmBaseName;
+ }
+
+ @Override
+ public void getNetConfig(final NetConfig config) {
+ config.load(this.currentNetConfig);
+ }
+
+ @Override
+ public void setNetConfig(NetConfig config) {
+ config= new NetConfig(config);
+
+ if (!config.validate(null)) {
+ throw new IllegalArgumentException();
+ }
+ this.currentNetConfig.load(config);
+ }
+
+ @Override
+ public void getPoolConfig(final PoolConfig config) {
+ config.load(this.currentPoolConfig);
+ }
+
+ @Override
+ public void setPoolConfig(PoolConfig config) {
+ config= new PoolConfig(config); // intern
+
+ if (!config.validate(null)) {
+ throw new IllegalArgumentException();
+ }
+ synchronized (this.jmPoolConfig) {
+ final PoolManager manager= this.poolManager;
+ if (manager != null) {
+ manager.setConfig(config);
+ }
+
+ this.currentPoolConfig= config;
+ this.jmPoolConfig.load(config);
+ }
+ }
+
+ @Override
+ public void getNodeConfig(final RServiNodeConfig config) {
+ config.load(this.currentNodeConfig);
+ }
+
+ @Override
+ public void setNodeConfig(RServiNodeConfig config) throws RjInvalidConfigurationException {
+ config= new RServiNodeConfig(config); // intern
+
+ if (!config.validate(null)) {
+ throw new IllegalArgumentException();
+ }
+ synchronized (this.jmPoolConfig) {
+ this.nodeFactory.setConfig(config);
+
+ this.currentNodeConfig= config;
+ this.jmNodeConfig.load(config);
+ }
+ }
+
+
+ private void initRMI() throws RjException, OperationsException {
+ final String hostAddress;
+ final int registryPort;
+ final boolean embed;
+ final boolean ssl;
+ synchronized (this.currentNetConfig) {
+ if (!MXUtil.validate(this.currentNetConfig)) {
+ return;
+ }
+ hostAddress= this.currentNetConfig.getEffectiveHostaddress();
+ registryPort= this.currentNetConfig.getEffectiveRegistryPort();
+ embed= this.currentNetConfig.getRegistryEmbed();
+ ssl= this.currentNetConfig.isSSLEnabled();
+ }
+
+ this.rmiRegistry= null;
+ this.nodeFactory.setRegistry(null);
+ this.poolAddress= null;
+
+ // RMI registry setup
+ final String property= System.getProperty("java.rmi.server.codebase");
+ if (property == null) {
+ final List<String> libs= this.context.searchRJLibs(
+ ImCollections.newList(ServerUtils.RJ_SERVER_ID, RServiUtil.RJ_SERVI_ID) );
+ System.setProperty("java.rmi.server.codebase", ServerUtils.concatCodebase(libs));
+ }
+
+ if (this.rmiHostnameSet || System.getProperty("java.rmi.server.hostname") == null) {
+ System.setProperty("java.rmi.server.hostname", hostAddress);
+ this.rmiHostnameSet= true;
+ }
+
+ RMIAddress rmiRegistryAddress;
+ Registry registry;
+ try {
+ rmiRegistryAddress= new RMIAddress(hostAddress, registryPort, null);
+ final RMIClientSocketFactory csf= (ssl) ? new SslRMIClientSocketFactory() : null;
+ registry= LocateRegistry.getRegistry(null, registryPort, csf);
+ }
+ catch (final UnknownHostException e) {
+ throw new RjInvalidConfigurationException("Invalid RMI address.", e);
+ }
+ catch (final MalformedURLException e) {
+ throw new RjInvalidConfigurationException("Invalid RMI address.", e);
+ }
+ catch (final RemoteException e) {
+ throw new RjInitFailedException("Failed to reference local registry.", e);
+ }
+ RMIRegistry rmiRegistry= null;
+ if (embed) {
+ if (this.rmiEmbeddedPorts == null) {
+ this.rmiEmbeddedPorts= new HashSet<>();
+ }
+ try {
+ rmiRegistry= new RMIRegistry(rmiRegistryAddress, registry, true);
+ if (this.rmiEmbeddedPorts.add(registryPort)) {
+ Utils.logWarning("Found running RMI registry at port "+registryPort+", embedded RMI registry will not be started.");
+ }
+ }
+ catch (final RemoteException e) {
+ RMIRegistryManager.INSTANCE.setEmbeddedPrivateMode(false, ssl);
+ RMIRegistryManager.INSTANCE.setEmbeddedPrivatePort(registryPort);
+ try {
+ rmiRegistry= RMIRegistryManager.INSTANCE.getEmbeddedPrivateRegistry(new NullProgressMonitor());
+ if (rmiRegistry != null) {
+ Utils.logInfo("Embedded RMI registry at port "+registryPort+" started.");
+ }
+ else {
+ Utils.logInfo("Failed to connect to running RMI registry at port "+registryPort+".", e);
+ Utils.logError("Failed to start embedded RMI registry at port "+registryPort+".");
+ throw new RjInitFailedException("Initalization of RMI registry setup failed.");
+ }
+ }
+ catch (final CoreException ee) {
+ Utils.logError("Failed to start embedded RMI registry at port "+registryPort+".", ee);
+ }
+ }
+ }
+ else {
+ try {
+ rmiRegistry= new RMIRegistry(rmiRegistryAddress, registry, true);
+ Utils.logInfo("Found running RMI registry at port "+registryPort+".");
+ }
+ catch (final RemoteException e) {
+ Utils.logError("Failed to connect to running RMI registry at port "+registryPort+".", e);
+ throw new RjInitFailedException("Initalization of RMI registry setup failed.");
+ }
+ }
+
+ this.rmiRegistry= rmiRegistry;
+ this.nodeFactory.setRegistry(rmiRegistry);
+ this.poolAddress= NetConfig.getPoolAddress(hostAddress, registryPort, this.id);
+ }
+
+ private void startManager() throws RjException {
+ final PoolManager manager= new PoolManager(this.id, this.rmiRegistry);
+ synchronized (this.jmPoolConfig) {
+
+ manager.setConfig(this.currentPoolConfig);
+
+ manager.addNodeFactory(this.nodeFactory);
+
+ manager.init();
+
+ this.poolManager= manager;
+ }
+
+ if (this.jmIsNodeManagementEnabled) {
+ this.jmNodeManager= new MXNodeManager(this, manager);
+ this.jmNodeManager.activate();
+ }
+ }
+
+
+ private void stopManager() {
+ final PoolManager manager= this.poolManager;
+ this.poolManager= null;
+ if (manager != null && manager.isInitialized()) {
+ try {
+ manager.stop(0);
+ }
+ catch (final RjException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+
+ @Override
+ public PoolManager getManager() {
+ return this.poolManager;
+ }
+
+ @Override
+ public String getPoolAddress() {
+ return this.poolAddress;
+ }
+
+ @Override
+ public PoolStatusMX getPoolStatus() {
+ return new MXPoolStatus(this);
+ }
+
+ @Override
+ public boolean isPoolNodeManagementEnabled() {
+ return this.jmIsNodeManagementEnabled;
+ }
+
+ @Override
+ public synchronized void setPoolNodeManagementEnabled(final boolean enable) {
+ if (this.jmIsNodeManagementEnabled == enable) {
+ return;
+ }
+ this.jmIsNodeManagementEnabled= enable;
+ if (enable) {
+ if (this.jmNodeManager == null) {
+ this.jmNodeManager= new MXNodeManager(this, this.poolManager);
+ }
+ this.jmNodeManager.activate();
+ }
+ else {
+ if (this.jmNodeManager != null) {
+ this.jmNodeManager.deactivate();
+ }
+ }
+ }
+
+
+ @Override
+ public synchronized void start() throws OperationsException {
+ try {
+ final PoolManager manager= this.poolManager;
+ if (manager != null) {
+ return;
+ }
+
+ initRMI();
+
+ startManager();
+ }
+ catch (final RjException e) {
+ Utils.logError("Failed to start RServi pool server.", e);
+ throw new OperationsException("Failed to start RServi pool server: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public synchronized void stop() throws OperationsException {
+ stopManager();
+ }
+
+ @Override
+ public synchronized void restart() throws OperationsException {
+ stop();
+ start();
+ }
+
+ public synchronized void shutdown() {
+ stopManager();
+ try {
+ if (this.jmPoolConfig != null) {
+ this.jmPoolConfig.disposeJM();
+ }
+ if (this.jmNetConfig != null) {
+ this.jmNetConfig.disposeJM();
+ }
+ if (this.jmNodeConfig != null) {
+ this.jmNodeConfig.disposeJM();
+ }
+
+ if (this.jmxName != null) {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(this.jmxName);
+ this.jmxName= null;
+ }
+ }
+ catch (final Exception e) {
+ Utils.logError("An error occured when disposing JMX for pool server.", e);
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/NetConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/NetConfig.java
new file mode 100644
index 0000000..eaca202
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/NetConfig.java
@@ -0,0 +1,247 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.Properties;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.internal.rj.servi.Utils;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+
+
+public class NetConfig implements PropertiesBean {
+
+
+ public static final String BEAN_ID= "netconfig";
+
+
+ public static String getPoolAddress(final NetConfig config, final String poolId) {
+ final String hostAddress;
+ final int registryPort;
+ synchronized (config) {
+ if (!config.validate(null)) {
+ return null;
+ }
+ hostAddress= config.effectiveHostaddress;
+ registryPort= config.effectiveRegistryPort;
+ }
+ return getPoolAddress(hostAddress, registryPort, poolId);
+ }
+
+ public static String getPoolAddress(final String hostAddress, final int registryPort,
+ final String poolId) {
+ try {
+ return new RMIAddress(hostAddress, registryPort, PoolConfig.getPoolName(poolId))
+ .toString();
+ }
+ catch (final UnknownHostException e) {}
+ catch (final MalformedURLException e) {
+ }
+ return null;
+ }
+
+
+ public static final String HOSTADDRESS_ID= "host.address";
+ public static final String REGISTRY_PORT_ID= "rmi_registry.address.port";
+ public static final String REGISTRY_EMBED_ID= "rmi_registry.embed.enabled";
+
+ /**
+ * Property id if SSL is enabled
+ *
+ * @see #setSSLEnabled(boolean)
+ * @since 2.0
+ */
+ public static final String SSL_ENABLED_ID= "ssl.enabled";
+
+ private static final String REGISTRY_HOST_DEFAULT= null;
+ private static final int REGISTRY_PORT_DEFAULT= -1;
+ private static final boolean REGISTRY_EMBED_DEFAULT= true;
+ private static final boolean SSL_ENABLED_DEFAULT= false;
+
+
+ private String hostAddress;
+ private String effectiveHostaddress;
+ private int registryPort;
+ private int effectiveRegistryPort;
+
+ private boolean registryEmbed;
+
+ private boolean isSSLEnabled;
+
+
+ public NetConfig() {
+ loadDefaults();
+ }
+
+ public NetConfig(final NetConfig config) {
+ load(config);
+ }
+
+
+ @Override
+ public String getBeanId() {
+ return BEAN_ID;
+ }
+
+
+ public synchronized void loadDefaults() {
+ setHostAddress(REGISTRY_HOST_DEFAULT);
+ setRegistryPort(REGISTRY_PORT_DEFAULT);
+ setRegistryEmbed(REGISTRY_EMBED_DEFAULT);
+ setSSLEnabled(SSL_ENABLED_DEFAULT);
+ }
+
+ public synchronized void load(final NetConfig templ) {
+ setHostAddress(templ.hostAddress);
+ setRegistryPort(templ.registryPort);
+ setRegistryEmbed(templ.registryEmbed);
+ setSSLEnabled(templ.isSSLEnabled);
+ }
+
+ @Override
+ public synchronized void load(final Properties map) {
+ loadDefaults();
+
+ if (map != null) {
+ { final String s= map.getProperty(HOSTADDRESS_ID);
+ if (s != null && !s.isEmpty()) {
+ setHostAddress(s);
+ }
+ }
+ { final String s= map.getProperty(REGISTRY_PORT_ID);
+ setRegistryPort((s != null && !s.isEmpty()) ?
+ Integer.parseInt(s) : REGISTRY_PORT_DEFAULT );
+ }
+ { final String s= map.getProperty(REGISTRY_EMBED_ID);
+ setRegistryEmbed((s != null && !s.isEmpty()) ?
+ Boolean.parseBoolean(s) : REGISTRY_EMBED_DEFAULT);
+ }
+ { final String s= map.getProperty(SSL_ENABLED_ID);
+ setSSLEnabled((s != null && !s.isEmpty()) ?
+ Boolean.parseBoolean(s) : SSL_ENABLED_DEFAULT);
+ }
+ }
+ }
+
+ @Override
+ public synchronized void save(final Properties map) {
+ Utils.setProperty(map, HOSTADDRESS_ID, this.hostAddress);
+ Utils.setProperty(map, REGISTRY_PORT_ID, (this.registryPort > 0) ? Integer.toString(this.registryPort) : null);
+ map.put(REGISTRY_EMBED_ID, Boolean.toString(this.registryEmbed));
+ map.put(SSL_ENABLED_ID, Boolean.toString(this.isSSLEnabled));
+ }
+
+
+ public synchronized String getHostAddress() {
+ return this.hostAddress;
+ }
+
+ public synchronized void setHostAddress(final String address) {
+ this.hostAddress= address;
+ this.effectiveHostaddress= null;
+ }
+
+ public synchronized String getEffectiveHostaddress() {
+ return this.effectiveHostaddress;
+ }
+
+ public synchronized int getRegistryPort() {
+ return this.registryPort;
+ }
+
+ public synchronized void setRegistryPort(final int port) {
+ this.registryPort= port;
+ this.effectiveRegistryPort= (port <= 0) ? 1099 : port;
+ }
+
+ public synchronized int getEffectiveRegistryPort() {
+ return this.effectiveRegistryPort;
+ }
+
+ public synchronized boolean getRegistryEmbed() {
+ return this.registryEmbed;
+ }
+
+ public synchronized void setRegistryEmbed(final boolean embed) {
+ this.registryEmbed= embed;
+ }
+
+ /**
+ * Returns if SSL is enabled
+ *
+ * @return <code>true</code> if SSL is enabled, otherwise <code>false</code>
+ */
+ public synchronized boolean isSSLEnabled() {
+ return this.isSSLEnabled;
+ }
+
+ /**
+ * Sets if SSL is enabled.
+ *
+ * @param enable
+ *
+ * @since 2.0
+ */
+ public synchronized void setSSLEnabled(final boolean enable) {
+ this.isSSLEnabled= enable;
+ }
+
+
+ @Override
+ public synchronized boolean validate(final Collection<ValidationMessage> messages) {
+ boolean valid= true;
+
+ String effective= this.hostAddress;
+ if (effective == null || effective.length() == 0) {
+ effective= System.getProperty("java.rmi.server.hostname");
+ }
+ try {
+ InetAddress inet= null;
+ if (effective != null && !effective.isEmpty()) {
+ inet= InetAddress.getByName(effective);
+ }
+ else {
+ try {
+ inet= InetAddress.getLocalHost();
+ }
+ catch (final UnknownHostException e) {}
+ catch (final ArrayIndexOutOfBoundsException e) { /* JVM bug */ }
+ if (inet == null) {
+ inet= RMIAddress.LOOPBACK;
+ }
+ }
+ this.effectiveHostaddress= inet.getHostAddress();
+ }
+ catch (final Exception e) {
+ this.effectiveHostaddress= null;
+ String msg= e.getMessage();
+ if (e instanceof UnknownHostException) {
+ msg= "Unknown Host";
+ }
+ if (messages != null) {
+ messages.add(new ValidationMessage(HOSTADDRESS_ID, msg));
+ }
+ valid= false;
+ }
+
+ return valid;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolConfig.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolConfig.java
new file mode 100644
index 0000000..efc0e4e
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolConfig.java
@@ -0,0 +1,256 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.util.Collection;
+import java.util.Properties;
+
+import org.eclipse.statet.internal.rj.servi.Utils;
+import org.eclipse.statet.rj.servi.node.PropertiesBean;
+
+
+public class PoolConfig implements PropertiesBean {
+
+
+ public static final String BEAN_ID= "poolconfig";
+
+
+ public static String getPoolName(final String id) {
+ return (new StringBuilder(String.valueOf(id))).append("-pool").toString();
+ }
+
+
+ public static final long MINUTES= 60000L;
+ public static final long SECONDS= 1000L;
+
+ public static final String MAX_TOTAL_COUNT_ID= "max_total.count";
+ public static final String MIN_IDLE_COUNT_ID= "min_idle.count";
+ public static final String MAX_IDLE_COUNT_ID= "max_idle.count";
+ public static final String MIN_IDLE_MILLIS_ID= "min_idle.millis";
+ @Deprecated
+ public static final String MIN_IDLE_TIME_ID= "min_idle.time";
+ public static final String MAX_WAIT_MILLIS_ID= "max_wait.millis";
+ @Deprecated
+ public static final String MAX_WAIT_TIME_ID= "max_wait.time";
+ public static final String MAX_USAGE_COUNT_ID= "max_usage.count";
+
+ /**
+ * Id of timeout when evicing lent pool items
+ *
+ * @since 2.0
+ */
+ public static final String EVICT_TIMEOUT_ID= "eviction_timeout.millis";
+
+ private static final long EVICT_TIMEOUT_DEFAULT= 30*MINUTES;
+
+
+ private int maxTotalCount;
+ private int minIdleCount;
+ private int maxIdleCount;
+ private long minIdleTime;
+ private long maxWaitTime;
+ private int maxUsageCount;
+
+ private long evictTimeout;
+
+
+ public PoolConfig() {
+ this.maxTotalCount= 20;
+ this.minIdleCount= 1;
+ this.maxIdleCount= 10;
+ this.minIdleTime= 10*MINUTES;
+ this.maxWaitTime= 3*SECONDS;
+ this.maxUsageCount= 1000;
+
+ this.evictTimeout= EVICT_TIMEOUT_DEFAULT;
+ }
+
+ public PoolConfig(final PoolConfig config) {
+ this();
+ synchronized (config) {
+ load(config);
+ }
+ }
+
+
+ @Override
+ public String getBeanId() {
+ return BEAN_ID;
+ }
+
+ public synchronized void load(final PoolConfig templ) {
+ this.maxTotalCount= templ.maxTotalCount;
+ this.minIdleCount= templ.minIdleCount;
+ this.maxIdleCount= templ.maxIdleCount;
+ this.minIdleTime= templ.minIdleTime;
+ this.maxWaitTime= templ.maxWaitTime;
+ this.maxUsageCount= templ.maxUsageCount;
+ this.evictTimeout= templ.evictTimeout;
+ }
+
+ @Override
+ public synchronized void load(final Properties map) {
+ this.maxTotalCount= Integer.parseInt(map.getProperty(MAX_TOTAL_COUNT_ID));
+ this.minIdleCount= Integer.parseInt(map.getProperty(MIN_IDLE_COUNT_ID));
+ this.maxIdleCount= Integer.parseInt(map.getProperty(MAX_IDLE_COUNT_ID));
+ this.minIdleTime= Long.parseLong(Utils.getProperty(map, MIN_IDLE_MILLIS_ID, MIN_IDLE_TIME_ID));
+ this.maxWaitTime= Long.parseLong(Utils.getProperty(map, MAX_WAIT_MILLIS_ID, MAX_WAIT_TIME_ID));
+ this.maxUsageCount= Integer.parseInt(map.getProperty(MAX_USAGE_COUNT_ID));
+ { final String s= map.getProperty(EVICT_TIMEOUT_ID);
+ this.evictTimeout= (s != null) ? Long.parseLong(s) : EVICT_TIMEOUT_DEFAULT;
+ }
+ }
+
+ @Override
+ public synchronized void save(final Properties map) {
+ map.setProperty(MAX_TOTAL_COUNT_ID, Integer.toString(this.maxTotalCount));
+ map.setProperty(MIN_IDLE_COUNT_ID, Integer.toString(this.minIdleCount));
+ map.setProperty(MAX_IDLE_COUNT_ID, Integer.toString(this.maxIdleCount));
+ map.setProperty(MIN_IDLE_MILLIS_ID, Long.toString(this.minIdleTime));
+ map.setProperty(MAX_WAIT_MILLIS_ID, Long.toString(this.maxWaitTime));
+ map.setProperty(MAX_USAGE_COUNT_ID, Integer.toString(this.maxUsageCount));
+ map.setProperty(EVICT_TIMEOUT_ID, Long.toString(this.evictTimeout));
+ }
+
+ public synchronized int getMaxTotalCount() {
+ return this.maxTotalCount;
+ }
+
+ public synchronized void setMaxTotalCount(final int count) {
+ this.maxTotalCount= count;
+ }
+
+ public synchronized int getMinIdleCount() {
+ return this.minIdleCount;
+ }
+
+ public synchronized void setMinIdleCount(final int count) {
+ this.minIdleCount= count;
+ }
+
+ public synchronized int getMaxIdleCount() {
+ return this.maxIdleCount;
+ }
+
+ public synchronized void setMaxIdleCount(final int count) {
+ this.maxIdleCount= count;
+ }
+
+ public synchronized long getMinIdleTime() {
+ return this.minIdleTime;
+ }
+
+ public synchronized void setMinIdleTime(final long milliseconds) {
+ this.minIdleTime= milliseconds;
+ }
+
+ public synchronized void setMaxWaitTime(final long milliseconds) {
+ this.maxWaitTime= milliseconds;
+ }
+
+ public synchronized long getMaxWaitTime() {
+ return this.maxWaitTime;
+ }
+
+ public synchronized void setMaxUsageCount(final int count) {
+ this.maxUsageCount= count;
+ }
+
+ public synchronized int getMaxUsageCount() {
+ return this.maxUsageCount;
+ }
+
+
+ /**
+ * Returns the timeout when evicing lent pool items
+ *
+ * @return the timeout in milliseconds
+ *
+ * @since 2.0
+ */
+ public synchronized long getEvictionTimeout() {
+ return this.evictTimeout;
+ }
+
+ /**
+ * Sets the timeout when evicing lent pool items
+ *
+ * @param milliseconds the timeout in milliseconds
+ *
+ * @since 2.0
+ */
+
+ public synchronized void setEvictionTimeout(final long milliseconds) {
+ this.evictTimeout= milliseconds;
+ }
+
+
+ @Override
+ public synchronized boolean validate(final Collection<ValidationMessage> messages) {
+ boolean valid= true;
+
+ if (this.minIdleCount < 0) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(MIN_IDLE_COUNT_ID, "Value must be >= 0"));
+ }
+ valid= false;
+ }
+ if (this.maxTotalCount < 1) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(MAX_TOTAL_COUNT_ID, "Value must be > 0."));
+ }
+ valid= false;
+ }
+ if (this.maxIdleCount < 0) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(MAX_IDLE_COUNT_ID, "Value must be >= 0."));
+ }
+ valid= false;
+ }
+ if (this.minIdleCount >= 0 && this.maxIdleCount >= 0 && this.maxIdleCount < this.minIdleCount) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(MAX_IDLE_COUNT_ID, "Value must be >= {" + MIN_IDLE_COUNT_ID + "}."));
+ }
+ valid= false;
+ }
+ if (this.minIdleTime < 0L) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(MIN_IDLE_MILLIS_ID, "Value must be >= 0"));
+ }
+ valid= false;
+ }
+ if (this.maxWaitTime < 0L && this.maxUsageCount != -1) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(MAX_WAIT_MILLIS_ID, "Value must be >= 0 or == -1 (infinite)"));
+ }
+ valid= false;
+ }
+ if (this.maxUsageCount < 1 && this.maxUsageCount != -1) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(MAX_USAGE_COUNT_ID, "Value must be > 0 or == -1 (disable)"));
+ }
+ valid= false;
+ }
+
+ if (this.evictTimeout < 0) {
+ if (messages != null) {
+ messages.add(new ValidationMessage(EVICT_TIMEOUT_ID, "Value must be >= 0"));
+ }
+ valid= false;
+ }
+ return valid;
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeItem.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeItem.java
new file mode 100644
index 0000000..4ab6fc7
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeItem.java
@@ -0,0 +1,128 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import org.eclipse.statet.ecommons.rmi.core.RMIAddress;
+
+import org.eclipse.statet.internal.rj.servi.NodeHandler;
+import org.eclipse.statet.rj.RjException;
+
+
+public class PoolNodeItem {
+
+
+ private long creationTime;
+
+ private PoolNodeState state;
+ private long stateTime;
+
+ private long usageCount;
+ private long usageDuration;
+
+ private final PoolNodeObject object;
+ private final NodeHandler nodeHandler;
+
+ private String client;
+
+
+ public PoolNodeItem(final PoolNodeObject nodeObj, final long stamp) {
+ synchronized(nodeObj) {
+ this.object= nodeObj;
+ this.nodeHandler= nodeObj.getNodeHandler();
+
+ this.creationTime= nodeObj.getCreationTime();
+ this.state= nodeObj.getState();
+
+ this.stateTime= nodeObj.getStateTime();
+ this.usageCount= nodeObj.getAllocatedCount();
+ this.usageDuration= nodeObj.getAllocatedDuration();
+// if (this.state == PoolNodeState.ALLOCATED) {
+// this.usageDuration+= Math.min(stamp - this.stateTime, 0L);
+// }
+ this.client= nodeObj.getClientLabel();
+ }
+ }
+
+
+ public long getCreationTime() {
+ return this.creationTime;
+ }
+
+ public PoolNodeState getState() {
+ return this.state;
+ }
+
+ public long getStateTime() {
+ return this.stateTime;
+ }
+
+ public String getCurrentClientId() {
+ return this.client;
+ }
+
+ public long getUsageCount() {
+ return this.usageCount;
+ }
+
+ public long getUsageDuration() {
+ return this.usageDuration;
+ }
+
+ public boolean isConsoleEnabled() {
+ return (this.nodeHandler != null && this.nodeHandler.isConsoleEnabled());
+ }
+
+ public void enableConsole(final String authConfig) throws RjException {
+ if (this.nodeHandler != null) {
+ this.nodeHandler.enableConsole(authConfig);
+ }
+ }
+
+ public void disableConsole() throws RjException {
+ if (this.nodeHandler != null) {
+ this.nodeHandler.disableConsole();
+ }
+ }
+
+ /**
+ * Returns the RMI address of the node.
+ *
+ * @return the address of the node if available, otherwise <code>null</code>
+ *
+ * @since 2.0
+ */
+ public RMIAddress getAddress() {
+ if (this.nodeHandler != null) {
+ return this.nodeHandler.getAddress();
+ }
+ return null;
+ }
+
+ /**
+ * Evicts the pool item.
+ *
+ * The specified timeout is used when the node is in use.
+ *
+ * @param timeoutMillis the timeout in milliseconds
+ *
+ * @since 2.0
+ */
+ public void evict(final long timeoutMillis) {
+ if (this.object != null) {
+ this.object.evict(timeoutMillis);
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeObject.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeObject.java
new file mode 100644
index 0000000..f5e5106
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeObject.java
@@ -0,0 +1,37 @@
+/*=============================================================================#
+ # Copyright (c) 2016, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import org.eclipse.statet.internal.rj.servi.NodeHandler;
+
+
+public interface PoolNodeObject {
+
+
+ NodeHandler getNodeHandler();
+
+ long getCreationTime();
+ long getAllocatedCount();
+ long getAllocatedDuration();
+
+ PoolNodeState getState();
+ long getStateTime();
+
+ String getClientLabel();
+
+ void evict(long timeoutMillis);
+
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeState.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeState.java
new file mode 100644
index 0000000..7b76917
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolNodeState.java
@@ -0,0 +1,28 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+
+public enum PoolNodeState {
+
+
+ INITIALIZING,
+ CHECKING,
+ IDLING,
+ ALLOCATED,
+ EVICTING,
+ DISPOSED
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServer.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServer.java
new file mode 100644
index 0000000..98fb519
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServer.java
@@ -0,0 +1,44 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.jmx.PoolServerMXBean;
+import org.eclipse.statet.rj.servi.node.RServiNodeConfig;
+
+
+/**
+ * @since 2.0
+ */
+public interface PoolServer extends PoolServerMXBean {
+
+
+ RJContext getRJContext();
+ String getJMBaseName();
+
+ void getNetConfig(NetConfig config);
+ void setNetConfig(NetConfig config);
+
+ void getPoolConfig(PoolConfig config);
+ void setPoolConfig(PoolConfig config);
+
+ void getNodeConfig(RServiNodeConfig config);
+ void setNodeConfig(RServiNodeConfig config) throws RjInvalidConfigurationException;
+
+ RServiPoolManager getManager();
+
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServerDaemon.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServerDaemon.java
new file mode 100644
index 0000000..7410527
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolServerDaemon.java
@@ -0,0 +1,56 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+
+/**
+ * This class allows to run the {@link StandalonePoolServer} as daemon using JSVC of Apache
+ * Commons-Daemon (http://commons.apache.org/proper/commons-daemon/).
+ *
+ * Not tested, feedback welcome.
+ */
+public class PoolServerDaemon {
+
+
+ private StandalonePoolServer poolServer;
+
+
+ public PoolServerDaemon() {
+ }
+
+
+ public void init(final String[] args) throws Exception {
+ if (this.poolServer != null) {
+ throw new IllegalStateException();
+ }
+ this.poolServer= StandalonePoolServer.initServer(args);
+ }
+
+ public void start() throws Exception {
+ this.poolServer.start();
+ }
+
+ public void stop() throws Exception {
+ this.poolServer.stop();
+ }
+
+ public void destroy() {
+ if (this.poolServer != null) {
+ this.poolServer.shutdown();
+ this.poolServer= null;
+ }
+ }
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolStatus.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolStatus.java
new file mode 100644
index 0000000..55e30ba
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/PoolStatus.java
@@ -0,0 +1,141 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * A fixed pool status including note states.
+ *
+ * @param <N> type of node state items, see {@link #createNodeState(PoolNodeItem)}
+ *
+ * @since 2.0
+ */
+public abstract class PoolStatus<N> {
+
+
+ private final RServiPoolManager.Counter NO_MANAGER= new RServiPoolManager.Counter();
+
+
+ protected final PoolServer server;
+
+ private long stamp;
+ private RServiPoolManager.Counter counter;
+
+ private List<N> nodeStates;
+
+
+ public PoolStatus(final PoolServer server) {
+ if (server == null) {
+ throw new NullPointerException("server");
+ }
+ this.server= server;
+ }
+
+
+ protected long getStatusStamp() {
+ return this.stamp;
+ }
+
+ public synchronized int getNumInUse() {
+ check();
+ return this.counter.numInUse;
+ }
+
+ public synchronized int getNumIdling() {
+ check();
+ return this.counter.numIdling;
+ }
+
+ public synchronized int getNumTotal() {
+ check();
+ return this.counter.numTotal;
+ }
+
+ public synchronized int getMaxInUse() {
+ check();
+ return this.counter.maxInUse;
+ }
+
+ public synchronized int getMaxIdling() {
+ check();
+ return this.counter.maxIdling;
+ }
+
+ public synchronized int getMaxTotal() {
+ check();
+ return this.counter.maxTotal;
+ }
+
+
+ public synchronized List<N> getNodeStates() {
+ check();
+ return this.nodeStates;
+ }
+
+
+ protected void check() {
+ }
+
+
+ protected void refresh(final RServiPoolManager manager, final long stamp) {
+ final List<N> list;
+ RServiPoolManager.Counter counter;
+
+ if (manager == null) {
+ counter= this.NO_MANAGER;
+ list= Collections.emptyList();
+ }
+ else {
+ final Collection<? extends PoolNodeObject> objects= manager.getPoolNodeObjects();
+ counter= manager.getCounter();
+ list= new ArrayList<>();
+ counter.numIdling= 0;
+ counter.numInUse= 0;
+ counter.numTotal= 0;
+ for (final PoolNodeObject nodeObj : objects) {
+ final PoolNodeItem item= createPoolItem(nodeObj, stamp);
+ final N nodeState= createNodeState(item);
+ switch (item.getState()) {
+ case ALLOCATED:
+ counter.numInUse++;
+ break;
+ case IDLING:
+ counter.numIdling++;
+ break;
+ default:
+ break;
+ }
+ counter.numTotal++;
+ list.add(nodeState);
+ }
+ }
+
+ this.stamp= stamp;
+ this.counter= counter;
+ this.nodeStates= list;
+ }
+
+ protected PoolNodeItem createPoolItem(final PoolNodeObject node, final long stamp) {
+ return new PoolNodeItem(node, stamp);
+ }
+
+ protected abstract N createNodeState(PoolNodeItem item);
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/RServiPoolManager.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/RServiPoolManager.java
new file mode 100644
index 0000000..a756f5c
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/RServiPoolManager.java
@@ -0,0 +1,51 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.util.Collection;
+
+import org.eclipse.statet.rj.RjException;
+import org.eclipse.statet.rj.servi.node.RServiNodeFactory;
+
+
+public interface RServiPoolManager {
+
+
+ class Counter {
+ public int numIdling;
+ public int numInUse;
+ public int numTotal;
+ public int maxIdling;
+ public int maxInUse;
+ public int maxTotal;
+
+ public Counter() {}
+ }
+
+
+ String getId();
+
+ PoolConfig getConfig();
+ void setConfig(PoolConfig config);
+ void addNodeFactory(RServiNodeFactory nodeFactory);
+ RServiNodeFactory getFactories();
+
+ void init() throws RjException;
+ void stop(int mode) throws RjException;
+
+ RServiPoolManager.Counter getCounter();
+ Collection<? extends PoolNodeObject> getPoolNodeObjects();
+
+}
diff --git a/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/StandalonePoolServer.java b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/StandalonePoolServer.java
new file mode 100644
index 0000000..30caefc
--- /dev/null
+++ b/servi/org.eclipse.statet.rj.servi/srcServiPool/org/eclipse/statet/rj/servi/pool/StandalonePoolServer.java
@@ -0,0 +1,172 @@
+/*=============================================================================#
+ # Copyright (c) 2013, 2017 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.rj.servi.pool;
+
+import java.io.File;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.management.OperationsException;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+import org.eclipse.statet.jcommons.lang.Disposable;
+
+import org.eclipse.statet.ecommons.runtime.core.ECommonsRuntime;
+
+import org.eclipse.statet.rj.RjInitFailedException;
+import org.eclipse.statet.rj.RjInvalidConfigurationException;
+import org.eclipse.statet.rj.server.util.RJContext;
+import org.eclipse.statet.rj.servi.RServiUtil;
+import org.eclipse.statet.rj.servi.jmx.StandalonePoolServerMXBean;
+
+
+/**
+ * Standalone version of pool server managed by JMX
+ *
+ * <p>Required bundles (libraries): <code>org.eclipse.statet.rj.data</code>,
+ * <code>org.eclipse.statet.rj.server</code>, <code>org.eclipse.statet.rj.client</code>,
+ * <code>org.eclipse.statet.rj.servi</code>, <code>org.eclipse.statet.rj.services.eruntime</code>
+ * </p>
+ * <p>The configuration is loaded from / saved to the current directory.
+ * </p>
+ * <p>To start the server use e.g.:
+ * <pre>
+ * java -cp "*" org.eclipse.statet.rj.servi.pool.StandalonePoolServer <id>
+ * </pre></p>
+ * <p>By default the libraries are expected in the current directory. If they are located
+ * in another directory, it must be specified in the java property <code>org.eclipse.statet.rj.path</code>:
+ * <pre>
+ * java -cp "/path/to/rjlibs/*" -Dorg.eclipse.statet.rj.path=/path/to/rjlibs/ org.eclipse.statet.rj.servi.pool.StandalonePoolServer <id>
+ * </pre></p>
+ * </p>
+ */
+public class StandalonePoolServer extends JMPoolServer implements StandalonePoolServerMXBean {
+
+
+ private static class EAppEnv implements ECommonsRuntime.AppEnvironment {
+
+
+ private final CopyOnWriteArraySet<Disposable> stopListeners= new CopyOnWriteArraySet<>();
+
+
+ public EAppEnv() {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ for (final Disposable listener : EAppEnv.this.stopListeners) {
+ listener.dispose();
+ }
+ }
+ });
+ }
+
+
+ @Override
+ public void log(final IStatus status) {
+ System.out.println(status.toString());
+ }
+
+ @Override
+ public void addStoppingListener(final Disposable listener) {
+ this.stopListeners.add(listener);
+ }
+
+ @Override
+ public void removeStoppingListener(final Disposable listener) {
+ this.stopListeners.add(listener);
+ }
+
+ }
+
+
+ private final AtomicBoolean running= new AtomicBoolean(true);
+
+
+ protected StandalonePoolServer(final String id, final RJContext context) throws RjInitFailedException {
+ super(id, context);
+
+ new Thread("KeepAlive") {
+ {
+ setDaemon(false);
+ }
+ @Override
+ public void run() {
+ while (StandalonePoolServer.this.running.get()) {
+ synchronized (StandalonePoolServer.this.running) {
+ try {
+ StandalonePoolServer.this.running.wait();
+ }
+ catch (final InterruptedException e) {
+ Thread.interrupted();
+ }
+ }
+ }
+ }
+ }.start();
+ }
+
+
+ @Override
+ public synchronized void shutdown() {
+ try {
+ super.shutdown();
+ }
+ finally {
+ this.running.set(false);
+ synchronized (this.running) {
+ this.running.notifyAll();
+ }
+ }
+ }
+
+
+ public static void main(final String[] args) throws RjInitFailedException {
+ final StandalonePoolServer server= initServer(args);
+
+ try {
+ server.start();
+ }
+ catch (final OperationsException e) {
+ ECommonsRuntime.getEnv().log(new Status(IStatus.WARNING, RServiUtil.RJ_SERVI_ID,
+ "The server is started, but the pool could not be started.", e));
+ }
+ }
+
+ static StandalonePoolServer initServer(final String[] args) throws RjInitFailedException {
+ final String id= (args.length > 0) ? args[0] : null;
+ if (id == null || id.isEmpty()) {
+ throw new IllegalArgumentException("No pool id specified.");
+ }
+
+ ECommonsRuntime.init(RServiUtil.RJ_SERVI_ID, new EAppEnv());
+
+ final RJContext context= new RJContext(System.getProperty("user.dir")) {
+ @Override
+ public String getServerPolicyFilePath() throws RjInvalidConfigurationException {
+ final String path= getPropertiesDirPath() + "security.policy";
+ if (new File(path).exists()) {
+ return path;
+ }
+ return super.getServerPolicyFilePath();
+ }
+ };
+
+ return new StandalonePoolServer(id, context);
+ }
+
+
+}