diff --git a/.classpath b/.classpath index 85eee6f8f01684e82fb18b8747592cd3e328747d..4720ad68e208eca3476a8a9e198bfb7f36be92f7 100644 --- a/.classpath +++ b/.classpath @@ -11,7 +11,6 @@ <classpathentry kind="lib" path="lib/velocity-1.6.3.jar"/> <classpathentry kind="lib" path="lib/sqlite-jdbc-3.20.0.jar"/> <classpathentry kind="lib" path="lib/junit-4.8.1.jar"/> - <classpathentry kind="lib" path="lib/drmaa.jar"/> <classpathentry kind="lib" path="lib/stax2-api-4.0.0.jar"/> <classpathentry kind="lib" path="lib/woodstox-core-5.0.3.jar"/> <classpathentry kind="lib" path="lib/commons-logging-1.1.1.jar"/> diff --git a/CHANGES b/CHANGES index d2a4a2bc7d64a3944c570c80d88eef84e404ba86..bfc99b2dbd9f7ed1fb36e17969bdac62b518628e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,12 @@ +v2.2 +---- + +- Praxis was really slow on machines where 'localhost' takes seconds + to resolve, due to some DNS (mis)configuration. This has been + observed on Mac OS X "Sierra". + Thanks to Patrick Gasser (Singapore-ETH Centre) for reporting the + issue, and for his help to diagnose than fix the problem. + v2.1 ---- diff --git a/ant/dependencies.xml b/ant/dependencies.xml new file mode 100644 index 0000000000000000000000000000000000000000..939c070b9dbcea99104a5081134fd34323a7e66f --- /dev/null +++ b/ant/dependencies.xml @@ -0,0 +1,148 @@ +<project name="praxis-variables"> + <!-- If not called from an other project setting praxis.home, define it --> + <condition property="praxis.home" value="${basedir}"> + <not> + <isset property="praxis.home" /> + </not> + </condition> + + <import file="macros.xml" /> + <import file="praxis.core.xml"/> + <import file="praxis.swing_gui.xml"/> + + <!-- Dependencies for the client --> + + <selector id="praxis.client.dependencies.selector"> + <or> + <filename name="args4j-2.33.jar"/> + <filename name="commons-logging-1.1.1.jar"/> + <filename name="javassist.jar"/> + <filename name="jaxen.jar"/> + <filename name="jdom.jar"/> + <filename name="org.apache.common.lang.SystemUtils.jar"/> + <filename name="rmiio-2.0.2.jar"/> + <filename name="saxpath.jar"/> + <filename name="sqlite-jdbc-3.20.0.jar"/> + <filename name="stax2-api-4.0.0.jar"/> + <filename name="woodstox-core-5.0.3.jar"/> + <filename name="velocity-1.6.3-dep.jar"/> + <filename name="velocity-1.6.3.jar"/> + </or> + </selector> + + <fileset id="praxis.client.dependencies" dir="${praxis.core.lib}"> + <selector refid="praxis.client.dependencies.selector" /> + </fileset> + + <path id="praxis.client.classpath"> + <fileset refid="praxis.client.dependencies"/> + </path> + <pathconvert pathsep=" " + property="praxis.client.manifest.classpath" + refid="praxis.client.classpath"> + <map from="${praxis.core.lib}" to="lib"/> + </pathconvert> + + + <!-- Dependencies for the server --> + + <selector id="praxis.server.dependencies.selector"> + <or> + <filename name="args4j-2.33.jar"/> + <filename name="javassist.jar"/> + <filename name="jaxen.jar"/> + <filename name="jdom.jar"/> + <filename name="org.apache.common.lang.SystemUtils.jar"/> + <filename name="saxpath.jar"/> + <filename name="sqlite-jdbc-3.20.0.jar"/> + <filename name="stax2-api-4.0.0.jar"/> + <filename name="woodstox-core-5.0.3.jar"/> + </or> + </selector> + <fileset dir="${praxis.core.lib}" id="praxis.server.dependencies"> + <selector refid="praxis.server.dependencies.selector" /> + </fileset> + <pathconvert dirsep="/" pathsep=" " property="praxis.server.manifest.classpath" refid="praxis.server.dependencies"> + <map from="${praxis.core.lib}" to="lib"/> + </pathconvert> + <echo message="Server Classpath is ${praxis.server.manifest.classpath}" level="verbose"/> + + + <!-- Dependencies for the platform --> + <selector id="praxis.platform.dependencies.selector"> + <or> + <filename name="args4j-2.33.jar" /> + <filename name="jaxen.jar" /> + <filename name="jdom.jar" /> + <filename name="saxpath.jar" /> + <filename name="org.apache.common.lang.SystemUtils.jar" /> + </or> + </selector> + <fileset dir="${praxis.core.lib}" id="praxis.platform.dependencies"> + <selector refid="praxis.platform.dependencies.selector" /> + </fileset> + <pathconvert dirsep="/" pathsep=" " property="praxis.platform.manifest.classpath"> + <map from="${praxis.core.lib}" to="lib"/> + <path> + <fileset refid="praxis.platform.dependencies"/> + </path> + </pathconvert> + <echo message="Platform Classpath is ${praxis.platform.manifest.classpath}" level="verbose"/> + + + <!-- Dependencies for server + platform --> + <selector id="praxis.server_platform.dependencies.selector"> + <or> + <selector refid="praxis.server.dependencies.selector" /> + <selector refid="praxis.platform.dependencies.selector" /> + </or> + </selector> + <fileset dir="${praxis.core.lib}" id="praxis.server_platform.dependencies"> + <selector refid="praxis.server_platform.dependencies.selector" /> + </fileset> + <pathconvert dirsep="/" pathsep=" " property="praxis.server_platform.manifest.classpath"> + <map from="${praxis.core.lib}" to="lib"/> + <path> + <fileset refid="praxis.server_platform.dependencies"/> + </path> + </pathconvert> + <echo message="Server+Platform Classpath is ${praxis.server_platform.manifest.classpath}" level="verbose"/> + + + <!-- Dependencies for all: client + server + platform --> + <selector id="praxis.all.dependencies.selector"> + <or> + <selector refid="praxis.client.dependencies.selector" /> + <selector refid="praxis.server.dependencies.selector" /> + <selector refid="praxis.platform.dependencies.selector" /> + </or> + </selector> + <fileset dir="${praxis.core.lib}" id="praxis.all.dependencies"> + <selector refid="praxis.all.dependencies.selector" /> + </fileset> + <pathconvert dirsep="/" pathsep=" " property="praxis.all.manifest.classpath"> + <map from="${praxis.core.lib}" to="lib"/> + <path> + <fileset refid="praxis.all.dependencies"/> + </path> + </pathconvert> + + + <!-- All jars --> + + <path id="praxis.core.all.libs"> + <fileset dir="${praxis.core.lib}"> + <include name="**/*.jar"/> + </fileset> + </path> + + + <target name="print-dependencies" description="Print Dependencies"> + <echo message="praxis_home: ${basedir}"/> + <echo-fileset filesetref="praxis.client.dependencies" /> + <echo-path pathref="praxis.client.classpath" /> + <echo message="client.manifest.classpath: ${client.manifest.classpath}"/> + + </target> + +</project> diff --git a/ant/javadoc.xml b/ant/javadoc.xml new file mode 100644 index 0000000000000000000000000000000000000000..a60136d498b04ad36afe3213fb0901dbec4b201c --- /dev/null +++ b/ant/javadoc.xml @@ -0,0 +1,31 @@ +<project name="javadoc" default="javadoc" basedir="../.."> + <property name="praxis.home" value="${basedir}"/> + + <import file="dependencies.xml"/> + + <target name="javadoc" + description="Generates the javadoc"> + + <javadoc packagenames="eu.telecom_bretagne.praxis.*" + sourcepath="${praxis.core.src}:${praxis.swing_gui.src}" + source="8" + defaultexcludes="yes" + destdir="${praxis.core.home}/doc/api" + author="true" + encoding="utf8" docencoding="utf8" charset="utf8" + version="true" + use="true" + splitindex="true" + notree="false" + nodeprecated="false" nodeprecatedlist="false" + noindex="false" nonavbar="false" + windowtitle="Praxis API"> + <doctitle><![CDATA[<h1>Praxis documentation</h1>]]></doctitle> + <bottom><![CDATA[<i>Copyright © 2002-2017, Institut Mines Telecom - IMT Atlantique Bretagne Pays de la Loire. All Rights Reserved.</i>]]></bottom> + <tag name="implementation" scope="all" description="Implementation note: "/> + <tag name="category" scope="all" description="Category:"/> + <link href="https://docs.oracle.com/javase/8/docs/api/" /> + <classpath refid="praxis.core.all.libs"/> + </javadoc> + </target> +</project> diff --git a/ant/macros.xml b/ant/macros.xml new file mode 100644 index 0000000000000000000000000000000000000000..f07fa1b491240753d59e117158123027462f1c62 --- /dev/null +++ b/ant/macros.xml @@ -0,0 +1,30 @@ +<project name="praxis-macros"> + <!-- cf. +http://blog.andrewbeacock.com/2005/08/pretty-printing-java-classpaths-using.html +http://www.javalobby.org/java/forums/t71033.html + --> + <macrodef name="echo-path"> + <attribute name="pathref" /> + <sequential> + <pathconvert pathsep="${line.separator} |- " + property="@{pathref}.echopath" + refid="@{pathref}"/> + <echo>@{pathref} (path)</echo> + <echo> |- ${@{pathref}.echopath}</echo> + </sequential> + </macrodef> + + <macrodef name="echo-fileset"> + <attribute name="filesetref" /> + <sequential> + <pathconvert pathsep="${line.separator} |- " + property="@{filesetref}.echopath"> + <path> + <fileset refid="@{filesetref}" /> + </path> + </pathconvert> + <echo>@{filesetref} (fileset)</echo> + <echo> |- ${@{filesetref}.echopath}</echo> + </sequential> + </macrodef> +</project> diff --git a/ant/praxis.core.xml b/ant/praxis.core.xml new file mode 100644 index 0000000000000000000000000000000000000000..3c81b00a58c9c423c0946401e73caf4721e58ffd --- /dev/null +++ b/ant/praxis.core.xml @@ -0,0 +1,90 @@ +<project name="praxis-core-common"> + + <import file="macros.xml" /> + + <property name="praxis.core.home" value="${praxis.home}/praxis-core"/> + + <!-- --> + <property name="praxis.core.src" location="${praxis.core.home}/src"/> + <property name="praxis.core.bin" location="${praxis.core.home}/bin"/> + <property name="praxis.core.build" location="${praxis.core.home}/build"/> + + <!-- get git revision. Written by "jmuc" on stackoverflow + http://stackoverflow.com/questions/2974106/how-to-lookup-the-latest-git-commit-hash-from-an-ant-build-script/4059546#4059546 + --> + <available file="${praxis.core.home}/.git" type="dir" property="praxis.core.git.present"/> + <target name="praxis.core.git.revision" description="Store git revision in ${repository.version}" if="praxis.core.git.present"> + <exec executable="git" outputproperty="praxis.core.git.revision" + failifexecutionfails="false" errorproperty="" + dir="${praxis.core.home}"> + <arg value="describe"/> + <arg value="--tags"/> + <arg value="--always"/> + <arg value="HEAD"/> + </exec> + <condition property="praxis.core.repository.version" value="${praxis.core.git.revision}" else="${build.time}"> + <and> + <isset property="praxis.core.git.revision"/> + <length string="${praxis.core.git.revision}" trim="yes" length="0" when="greater"/> + </and> + </condition> + <echo message="praxis.core.git.revision: ${praxis.core.git.revision}"/> + <echo message="praxis.core.repository.version: ${praxis.core.repository.version}"/> + + </target> + + <!-- Libraries --> + <property name="praxis.core.lib" location="${praxis.core.home}/lib"/> + + <import file="dependencies.xml" /> + + <target name="praxis.core.init" unless="praxis.core.init_ok"> + <property name="praxis.core.init_ok" value="ok"/> + <tstamp/> + <mkdir dir="${praxis.core.bin}"/> + <mkdir dir="${praxis.core.build}"/> + </target> + + <target name="praxis.core.compile" depends="praxis.core.init"> +<!-- description="Compile praxis.core sources">--> + <javac destdir="${praxis.core.bin}" + debug="off" + source="1.8" + target="1.8" + encoding="UTF-8" + includeantruntime="false" + > +<!-- excludes="**/*Test*"--> + <classpath refid="praxis.core.all.libs"/> + <src path="${praxis.core.src}"/> + </javac> + </target> + + <target name="praxis.core.clean"> + <delete dir="${praxis.core.bin}"/> + <delete dir="${praxis.core.build}"/> + </target> + + <target name="praxis.core.show-variables" + description="Print variables defined in praxis.core.common"> + <echo message="praxis.core.home: ${praxis.core.home}"/> + <echo message="praxis.core.lib: ${praxis.core.lib}"/> + <echo message="praxis.core.bin: ${praxis.core.bin}"/> + <echo message="---- Client ----" /> + <echo-fileset filesetref="praxis.client.dependencies" /> + <echo-path pathref="praxis.client.classpath" /> + <echo message="client.manifest.classpath: ${praxis.client.manifest.classpath}"/> + <echo message="---- Server ----" /> + <echo-fileset filesetref="praxis.server.dependencies" /> + <!--<echo-path pathref="praxis.server.classpath" />--> + <echo message="praxis.server.manifest.classpath: ${praxis.server.manifest.classpath}"/> + <echo message="---- Platform ----" /> + <echo-fileset filesetref="praxis.platform.dependencies" /> + <!--<echo-path pathref="praxis.server.classpath" />--> + <echo message="praxis.platform.manifest.classpath: ${praxis.platform.manifest.classpath}"/> + <echo message="---- All ----" /> + <echo message="${praxis.all.dependencies}" /> + <echo-fileset filesetref="praxis.all.dependencies" /> + </target> + +</project> diff --git a/ant/praxis.project.xml b/ant/praxis.project.xml new file mode 100644 index 0000000000000000000000000000000000000000..ba79d4ffb2e352440c843336770928d8f23cfc5a --- /dev/null +++ b/ant/praxis.project.xml @@ -0,0 +1,123 @@ +<project name=""> + <description>Builds Praxis projects</description> + + <!-- Add one-jar ant task --> + + <!-- + <property name="one-jar.dist.dir" value="/home0/extern/capexbio/praxis/one-jar/dist"/> +--> +<!-- ori + <property name="one-jar.dist.dir" value="/home/big/lang/java/one-jar.cvs/dist"/> + <property name="one-jar.version" value="0.98"/> --> + +<!-- ori + <taskdef name="one-jar" classname="com.simontuffs.onejar.ant.OneJarTask" + classpath="${one-jar.dist.dir}/one-jar-ant-task-${one-jar.version}.jar" onerror="report"/> +--> +<!-- old + <taskdef name="one-jar" classname="com.simontuffs.onejar.ant.OneJarTask" + classpath="${praxis.home}/praxis-core/lib/one-jar/one-jar-ant-task-${one-jar.version}.jar" onerror="report"/> +--> + <macrodef name="praxis_generate_java"> + <attribute name="descriptions" /> + <attribute name="configuration" /> + <attribute name="target.src" /> + <sequential> + <java + classname="eu.telecom_bretagne.praxis.preprocess.CoreDescriptionsGeneration" + fork="yes" + > + <arg value="@{descriptions}" /> + <arg value="@{target.src}" /> + <jvmarg value="-DCONFIGURATION=@{configuration}" /> + <jvmarg value="-Djava.util.logging.config.file=logging.properties" /> + <classpath> + <fileset refid="praxis.all.dependencies" /> + <pathelement path="${praxis.jar}" /> + <pathelement location="${praxis.core.lib}/velocity-1.6.3-dep.jar" /> + <pathelement location="${praxis.core.lib}/velocity-1.6.3.jar" /> + <pathelement location="${praxis.core.home}/" /> + <pathelement location="." /> + </classpath> + </java> + </sequential> + + </macrodef> + + <macrodef name="praxis_project_one_jar"> + <attribute name="project.name" /> + <attribute name="configuration" /> + <attribute name="destfile" /> + <element name="libs" /> + <element name="includes" /> + <sequential> + <manifest file="project.mf"> + <attribute name="Main-Class" value="com.simontuffs.onejar.Boot"/> + <attribute name="One-Jar-Main-Class" value="eu.telecom_bretagne.praxis.common.Splasher"/> + <attribute name="Specification-Title" value="${project.name} / Standalone"/> + </manifest> + + <copy file="@{configuration}" + tofile="configuration/configuration.cfg" + preservelastmodified="true" + overwrite="true" + /> + <property name="one-jar.class.path" value="." /> + <one-jar destfile="@{destfile}" + manifest="project.mf" + index="true"> + <main jar="${praxis.jar}"/> + <lib> + <fileset refid="praxis.all.dependencies"/> +<!-- <fileset refid="praxis.swing_gui.dependencies" /> --> + <libs /> + </lib> + <includes /> + <fileset dir="${praxis.home}/praxis-core" includes="configurations/**" /> + <fileset dir="${praxis.home}/praxis-core" includes="data/**" excludes="**/.xvpics **/.xvpics/*" /> + </one-jar> + <delete file="project.mf"/> + + </sequential> + </macrodef> + + <macrodef name="praxis_project_stress_one_jar"> + <attribute name="project.name" /> + <attribute name="configuration" /> + <attribute name="destfile" /> + <element name="libs" /> + <element name="includes" /> + <sequential> + <manifest file="project.mf"> + <attribute name="Main-Class" value="com.simontuffs.onejar.Boot"/> + <attribute name="One-Jar-Main-Class" value="eu.telecom_bretagne.praxis.client.StressTst"/> + <attribute name="Specification-Title" value="${project.name} / Standalone"/> + </manifest> + + <copy file="@{configuration}" + tofile="configuration/configuration.cfg" + preservelastmodified="true" + overwrite="true" + /> + <property name="one-jar.class.path" value="." /> + <one-jar destfile="@{destfile}" + manifest="project.mf" + index="true"> + <main jar="${praxis.jar}"/> + <lib> + <fileset refid="praxis.all.dependencies"/> +<!-- <fileset refid="praxis.swing_gui.dependencies" /> --> + <libs /> + </lib> + <includes /> +<!-- + <fileset dir="${praxis}" includes="configurations/**" /> + <fileset dir="${praxis}" includes="data/**" excludes="**/.xvpics **/.xvpics/*" /> +--> + </one-jar> + <delete file="project.mf"/> + + </sequential> + </macrodef> + +</project> diff --git a/ant/praxis.swing_gui.xml b/ant/praxis.swing_gui.xml new file mode 100644 index 0000000000000000000000000000000000000000..4d275d7701fd850d7b3458357bff6000698d8ba6 --- /dev/null +++ b/ant/praxis.swing_gui.xml @@ -0,0 +1,107 @@ +<project name="praxis-swing-gui" basedir=".."> + + <!-- we expect praxis.home to be set --> + <fail unless="praxis.home" + message="Property praxis.home is not defined"/> + + <!-- if not set, defaults to ../praxis-swing-gui/ --> + <condition property="praxis.swing_gui.home" + value="${praxis.home}/praxis-swing-gui"> + <not> + <isset property="praxis.swing_gui.home" /> + </not> + </condition> + + <target name="praxis.swing_gui.check"> + <fail message="Property praxis.swing_gui.home does not point to a valid directory (value: ${praxis.swing_gui.home})"> + <condition> + <not> + <available file="${praxis.swing_gui.home}" type="dir" /> + </not> + </condition> + </fail> + </target> + + <!-- --> + <property name="praxis.swing_gui.src" location="${praxis.swing_gui.home}/src"/> + <property name="praxis.swing_gui.bin" location="${praxis.swing_gui.home}/bin"/> + + <!-- Libraries --> + <property name="praxis.swing_gui.lib" location="${praxis.swing_gui.home}/lib"/> + + + <!-- All jars --> + <path id="praxis.swing_gui.libs"> + <fileset dir="${praxis.swing_gui.home}/lib"> + <include name="**/*.jar"/> + <exclude name="*junit.jar"/> + </fileset> + </path> + + + + <!-- Dependencies --> + <fileset dir="${praxis.core.lib}" id="praxis.swing_gui.dependencies"> + <include name="jaxen.jar"/> + <include name="jdom.jar"/> + <include name="saxpath.jar"/> + </fileset> + <path id="praxis.swing_gui.classpath"> + <fileset refid="praxis.swing_gui.dependencies"/> + </path> + + <pathconvert pathsep=" " property="praxis.swing_gui.manifest.classpath" refid="praxis.swing_gui.classpath"> + <map from="${praxis.core.lib}" to="lib"/> + <map from="${praxis.swing_gui.lib}" to="lib"/> + </pathconvert> + + <!-- targets --> + + <target name="praxis.swing_gui.init" + unless="praxis.swing_gui.init_ok" + depends="praxis.swing_gui.check"> + <property name="praxis.swing_gui.init_ok" value="ok"/> + <tstamp/> + <mkdir dir="${praxis.swing_gui.bin}"/> + </target> + + <target name="praxis.swing_gui.compile" + depends="praxis.core.compile, praxis.swing_gui.init"> + <!-- description="Compile Praxis Swing GUI" --> + <javac destdir="${praxis.swing_gui.bin}" + debug="off" + source="1.8" + target="1.8" + encoding="utf-8" + includeantruntime="false" + > +<!-- excludes="**/*Test*"--> + + <classpath location="${praxis.core.bin}" /> + <classpath refid="praxis.swing_gui.libs" /> + <classpath refid="praxis.swing_gui.classpath" /> + <src path="${praxis.swing_gui.src}" /> + </javac> + </target> + + <target name="praxis.swing_gui.clean" + depends="praxis.swing_gui.check"> +<!-- + description="Praxis Swing GUI: Removes class files, jars, zips, tmp files"> + --> + <delete dir="${praxis.swing_gui.bin}"/> + </target> + + + <target name="praxis.swing_gui.show-variables" + description="Print variables defined in praxis.swing_gui"> + <echo message="praxis.swing_gui.home: ${praxis.swing_gui.home}"/> + <echo message="praxis.swing_gui.lib: ${praxis.swing_gui.lib}"/> + <echo message="praxis.swing_gui.bin: ${praxis.swing_gui.bin}"/> + <echo-path pathref="praxis.swing_gui.dependencies"/> + <echo message="praxis.swing_gui.manifest.classpath: ${praxis.swing_gui.manifest.classpath}"/> + <echo-path pathref="praxis.swing_gui.libs" /> + <echo-path pathref="praxis.swing_gui.classpath" /> + </target> + +</project> diff --git a/build.xml b/build.xml new file mode 100644 index 0000000000000000000000000000000000000000..86b9a62c3e83676b85c652d1621a3a3eee0c3ebc --- /dev/null +++ b/build.xml @@ -0,0 +1,129 @@ +<project name="praxis" default="praxis.build.standalone.jar" basedir=".."> + <description> + Praxis build.xml + </description> + + <tstamp> + <format property="build.time" pattern="yyyy-MM-dd'T'hh:mm:ss.SSSZ"/> + </tstamp> + + <property name="praxis.version" value="1.11"/> + <!-- If not called from an other project setting praxis.home, define it. + In details: + - it is unset when directly building the jars of Praxis, + - it is set when imported from a build.xml in a Praxis project. + --> + <condition property="praxis.home" value="${basedir}"> + <not> + <isset property="praxis.home" /> + </not> + </condition> + <tstamp/> + + <!-- --> + <import file="ant/dependencies.xml"/> + <import file="ant/praxis.core.xml"/> + <import file="ant/praxis.swing_gui.xml"/> + <import file="ant/javadoc.xml"/> + <import file="ant/praxis.project.xml" /> + + <target name="praxis.compile" + depends="praxis.core.compile, praxis.swing_gui.compile"/> + + <property name="praxis.jar" value="${praxis.core.build}/praxis.jar" /> + + <!-- Common values for MANIFEST files --> + <manifest file="MANIFEST.MF"> + <attribute name="Built-By" value="${user.name}"/> + <attribute name="Build-Date" value="${build.time}"/> + <attribute name="Specification-Title" value="Praxis"/> + <attribute name="Specification-Vendor" value="Institut Mines-Telecom / TELECOM Bretagne"/> + <attribute name="Specification-Version" value="${praxis.version}"/> +<!--<attribute name="Implementation-Title" value="Praxis"/>--> +<!-- + <attribute name="Implementation-Version" value="${praxis.version} ${praxis.core.repository.version} ${build.time}"/> +--> + <attribute name="Implementation-Vendor" value="Institut Mines-Telecom / TELECOM Bretagne"/> + </manifest> + + <target name="praxis.build.server_platform.jar" + depends="praxis.core.compile, praxis.core.git.revision" + description="Builds the jar for the server+platform"> + <jar jarfile="${praxis.core.build}/praxis_server_platform.jar" manifest="MANIFEST.MF" index="true"> + <manifest> + <attribute name="Main-Class" value="eu.telecom_bretagne.praxis.common.Launcher"/> + <attribute name="Implementation-Title" value="Praxis Server and Platform"/> + <attribute name="Class-Path" value="./ ${server_platform.manifest.classpath}"/> + </manifest> + <fileset dir="${praxis.core.bin}"> + <include name="eu/telecom_bretagne/praxis/platform/**"/> + <include name="eu/telecom_bretagne/praxis/common/**"/> + <include name="eu/telecom_bretagne/praxis/core/**"/> + <include name="eu/telecom_bretagne/praxis/server/**"/> + <exclude name="**/*Test*"/> + </fileset> + <fileset dir="." includes="data/i18n/**" excludes="**/*~"/> + </jar> + </target> + + <target name="praxis.build.standalone.jar" + depends="praxis.compile, praxis.core.git.revision" + description="Builds the jar for the standalone version of praxis"> + <jar jarfile="${praxis.jar}" manifest="MANIFEST.MF" index="false"> + <manifest> + <attribute name="Main-Class" value="eu.telecom_bretagne.praxis.common.Launcher"/> + <attribute name="Implementation-Title" value="Praxis / Standalone"/> + <attribute name="Class-Path" value=". ${praxis.all.manifest.classpath}"/> + <attribute name="Implementation-Version" value="${praxis.version} ${praxis.core.git.revision} ${build.time}"/> + <!-- TODO: own dependencies --> + </manifest> + <fileset dir="${praxis.core.bin}"> + <exclude name="**/*Test*"/> + </fileset> + <fileset dir="${praxis.swing_gui.bin}"> + <exclude name="**/*Test*"/> + </fileset> + <fileset dir="${praxis.core.home}" + includes="data/i18n/praxis_*.properties" excludes="**/*~"/> + <fileset dir="${praxis.core.home}" + includes="data/dtd/**" excludes="**/*~"/> + <fileset dir="${praxis.core.home}" + includes="configurations/** templates/*.vm" excludes="**/*~"/> + <fileset dir="${praxis.swing_gui.home}" + includes="data/**" excludes="**/*~"/> + </jar> + </target> + + + <!-- what for ? --> + <target name="praxis.build.common.jar" + depends="praxis.core.compile" + unless="jar_generated" + description="Builds praxis's common.jar"> + <!-- praxis.common, but NOT the sub packages such as praxis.common.events --> + <jar jarfile="${praxis.core.build}/praxis_common.jar" manifest="MANIFEST.MF" index="false"> + <manifest> + <attribute name="Specification-Title" value="Praxis / Common"/> + </manifest> + <fileset dir="${praxis.core.bin}"> + <include name="eu/telecom_bretagne/praxis/common/*"/> + <exclude name="*Launcher*"/> + <exclude name="**/*Test*"/> + </fileset> + </jar> + </target> + +<!-- + <target name="build_jars" + depends="build_standalone_jar,build_client_jar,build_server_jar,build_platform_jar,build_common_jar" + description="Builds the 4 jars: client, server, platform and standalone/praxis"> + </target> +--> + + <!-- ==== Clean ==== --> + <target name="clean" + description="Removes class files, jars and zips, temporary files" + depends="praxis.core.clean, praxis.swing_gui.clean"> + </target> + +</project> diff --git a/data/i18n/praxis_en.properties b/data/i18n/praxis_en.properties index d8671b0fa95f8f7ad75935fb61c693693f4b97bc..c95ac3703b3cb535ee9bebadcb5a8b877c15b328 100644 --- a/data/i18n/praxis_en.properties +++ b/data/i18n/praxis_en.properties @@ -53,7 +53,7 @@ UI.actions.zoom_original = Zoom 1:1 UI.actions.zoom_original_tt = Restores the default zoom factor UI.actions.zoom_out = Zoom Out UI.actions.zoom_out_tt = Draws a smaller workflow to show a larger part of it -UI.annotation.for_worflow = Annotation for workflow ''{0}'' +UI.annotation.for_workflow = Annotation for workflow ''{0}'' UI.annotation.for_program = Annotation for program: ''{0}'' UI.ctrlwf.run.file_does_not_exist = File {0} does not exist UI.ctrlwf.run.file_unreadable = File {0} cannot be read diff --git a/data/i18n/praxis_fr.properties b/data/i18n/praxis_fr.properties index a2d62869e666dd194e6afd82f0b290ae606b3eb6..4989361fdadd5771615bda4ade121f1795d4e215 100644 --- a/data/i18n/praxis_fr.properties +++ b/data/i18n/praxis_fr.properties @@ -48,7 +48,7 @@ UI.actions.valid_links_confirm = \u00CAtes-vous certain(e UI.actions.create_file_error = Impossible de cr\u00e9er le fichier {0} UI.actions.create_existing_file_error = Impossible de cr\u00e9er le fichier {0}: il existe d\u00e9j\u00e0 UI.actions.zoom_in = Zoom avant -UI.actions.zoom_in_tt = Dessine le workflow en plus grand pour mieux en distinguer les d\u00e9�tails +UI.actions.zoom_in_tt = Dessine le workflow en plus grand pour mieux en distinguer les d\u00e9tails UI.actions.zoom_original = Zoom 1:1 UI.actions.zoom_original_tt = R\u00e9tablit le facteur de zoom par d\u00e9faut UI.actions.zoom_out = Zoom arri\u00E8re @@ -181,9 +181,9 @@ UI.dialog.wf.open_failed_no_workflow = Impossible d''ouvrir un UI.dialog.wf.open_failed_no_workspace = Impossible d''ouvrir un workflow: aucun workspace n''est disponible ! UI.dialog.wf.open_failed_xml_not_conform_to_DTD = Impossible d''ouvrir le workflow: le xml n''est pas conforme \u00E0 la DTD UI.dialog.wf.open_failure = Une erreur inattendue s''est produite lors de l''ouverture du workflow +UI.dialog.wf.rename_save_before_confirm = Le workflow a \u00e9t\u00e9 modifi\u00e9 et doit \u00eatre sauvegard\u00e9 avant d''\u00eatre renomm\u00e9.\n\ UI.dialog.wf.open_failure_title = \u00C9chec de l''ouverture d''un workflow UI.dialog.wf.open_select_workflows = S\u00e9lectionnez le(s) workflow(s) \u00e0 ouvrir: -UI.dialog.wf.rename_save_before_confirm = Le workflow a \u00e9t\u00e9 modifi\u00e9 et doit \u00eatre sauvegard\u00e9 avant d''\u00eatre renomm\u00e9.\n\ Souhaitez-vous le faire maintenant? UI.dialog.wf.rename_enter_new_name = Veuillez entrer le nouveau nom de ce workflow : UI.dialog.wf.rename_failure_title = \u00C9chec du renommage d''un workflow @@ -350,9 +350,9 @@ UI.menu_items.ws_open_tt = Demande l''ouverture d'' UI.menu_items.ws_rename = Renommer... UI.menu_items.ws_rename_tt = Change le nom de l''espace de travail actuel UI.menu_items.ws_save = Sauvegarder +UI.menu_items.ws_save_tt = Sauvegarde l''ensemble des workflows de l''espace de travail actuel UI.menu_items.ws_save_as = Sauvegarder sous... UI.menu_items.ws_save_as_tt = Sauvegarde l''espace de travail actuel (et tous ses workflows !) dans un nouvel espace de travail -UI.menu_items.ws_save_tt = Sauvegarde l''ensemble des workflows de l''espace de travail actuel UI.menu_items.License = Licence... UI.menu_items.OtherLicenses = Licences des programmes tiers... diff --git a/src/eu/telecom_bretagne/praxis/client/SimpleCommandLine.java b/src/eu/telecom_bretagne/praxis/client/SimpleCommandLine.java index 2304e16ddf5de96ea8884ada62f4d64d886043e8..30d01df560cef2254e64ff173337bf27b49be484 100644 --- a/src/eu/telecom_bretagne/praxis/client/SimpleCommandLine.java +++ b/src/eu/telecom_bretagne/praxis/client/SimpleCommandLine.java @@ -46,7 +46,7 @@ import eu.telecom_bretagne.praxis.core.workflow.WorkflowInput; * @implementation The main() in this class is a very simple command-line executing a workflow and retrieving the * results as a zip file. All other methods are here temporarily; they should be moved in a "façade", * client-side, encapsulating the communication level (using class {@link Client} and interface - * {@link ServerMessageEvent}). + * {@link ServerToClientEvent}). * @author Sébastien Bigaret */ public class SimpleCommandLine extends StorageListenerAdapter diff --git a/src/eu/telecom_bretagne/praxis/client/event/ApplicationListener.java b/src/eu/telecom_bretagne/praxis/client/event/ApplicationListener.java index 0a5f135a4c3d9e0f6d07d6786898939fa523f859..61a307ca43341d629e0b930b777331edbdf14575 100644 --- a/src/eu/telecom_bretagne/praxis/client/event/ApplicationListener.java +++ b/src/eu/telecom_bretagne/praxis/client/event/ApplicationListener.java @@ -12,7 +12,7 @@ public interface ApplicationListener extends EventListener /** * Invoked when the application exits. At this point there is no way to interrupt the process. * Code needing to know whether this event has already been fired will check - * {@link eu.telecom_bretagne.praxis.common.Application.Application#exiting()}. + * {@link eu.telecom_bretagne.praxis.common.Application#exiting()}. */ public void applicationExiting(); } diff --git a/src/eu/telecom_bretagne/praxis/common/Configuration.java b/src/eu/telecom_bretagne/praxis/common/Configuration.java index a1f073b3118a93bcf62262b2653e44eca5b2e0ea..99d7fe2e0a9bce110ac5cba007d42a083ebee32a 100644 --- a/src/eu/telecom_bretagne/praxis/common/Configuration.java +++ b/src/eu/telecom_bretagne/praxis/common/Configuration.java @@ -9,6 +9,7 @@ import java.security.KeyStore; import java.util.ArrayList; import java.util.Locale; import java.util.Properties; +import java.util.Scanner; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.regex.Pattern; @@ -27,6 +28,7 @@ import eu.telecom_bretagne.praxis.core.resource.ProgramDescription; public final class Configuration { + private static final String REVISION = "revision"; /* * Java par.8.7 Static Initializers The static initializers and class variable initializers are executed in * textual order. @@ -255,10 +257,16 @@ public final class Configuration // last: application_revision try { - configuration.setProperty("revision", - ""+Integer.parseInt(Configuration.get("revision").substring(6).replace('$', ' ').trim())); + String revision = Configuration.get(REVISION).trim(); + if (revision.startsWith("$Rev: ")) + { + // Old format: "$Rev: nnn$" + revision = revision.substring(6).replace('$', ' ').trim(); + } + set(REVISION, revision); + checkInteger(REVISION, errors); } - catch (Exception e) + catch (NullPointerException | NumberFormatException e) { errors.add("Invalid revision"); } @@ -406,13 +414,26 @@ public final class Configuration */ private static void checkInteger(String key, ArrayList<String> errors) { - try + final String value = get(key); + if ( value == null ) { - getInt(key); + errors.add("Key "+key+": not an integer (it is null)"); + return; } - catch (NumberFormatException e) + try (Scanner scanner = new Scanner(value.trim())) { - errors.add("Key "+key+": not an integer (current value: "+get(key)+")"); + boolean error = false; + if ( !scanner.hasNextInt() ) + error = true; + else + scanner.nextInt(); // Let the scanner advance to the next token + + error = ( !error ) && scanner.hasNext(); + if ( error ) + { + errors.add("Key " + key + ": not an integer (current value: " + value + ")"); + return; + } } } @@ -521,13 +542,14 @@ public final class Configuration /** * Returns the color stored as a RGB hexadecimal string (e.g. 0xFF00FF). - * @param key + * @param hexRGBColor the hexadecimal RGB string * @return The corresponding color, or null if the key is {@link #isDefined(String) not defined} or if it is * invalid. + * @throws IllegalArgumentException if {@hexRGBColor} is invalid */ - public static Color getColor(String key) throws IllegalArgumentException + public static Color getColor(String hexRGBColor) throws IllegalArgumentException { - String color_rgb_hex=get(key); + String color_rgb_hex=get(hexRGBColor); return decodeColor(color_rgb_hex); } @@ -555,7 +577,7 @@ public final class Configuration /** * A key is declared if and only if it is present in one of the configuration files - * @param key + * @param key the key * @return true if the key is declared */ public static boolean isDeclared(String key) @@ -565,7 +587,7 @@ public final class Configuration /** * A key is said to be defined if and only if it is declared and it has a non-empty value - * @param key + * @param key the key to check * @return true if the key is defined */ public static boolean isDefined(String key) @@ -581,7 +603,7 @@ public final class Configuration /** * Resets the locale used in the application. * - * @param locale + * @param language * the lowercase two-letter ISO-639 code of the local to use. If {@code null}, "en" is used instead. * @see java.util.Locale * @see I18N diff --git a/src/eu/telecom_bretagne/praxis/common/Launcher.java b/src/eu/telecom_bretagne/praxis/common/Launcher.java index 54937114cabf9df69e09016c51bc0274451faa61..a3dae182eb7381c85f15621e519bd4ea39e25099 100644 --- a/src/eu/telecom_bretagne/praxis/common/Launcher.java +++ b/src/eu/telecom_bretagne/praxis/common/Launcher.java @@ -20,7 +20,7 @@ public class Launcher * This is the "root" delegate: "one delegate to rule them all"! Praxis projects defining their own delegates * should: * <ul> - * <li>Subclass this class and override {@link #initialize()}; + * <li>Subclass this class and override {@link #initialize(boolean, boolean, boolean)}; * <li>register the delegates within the <code>initialize()</code> method; * <li>declare the class in the configuration file, using key <code>"application.init"</code>. * </ul> @@ -101,8 +101,11 @@ public class Launcher } /** - * @param args - * @throws + * This is the launcher for all praxis projects. It is responsible to launch the elements declared in the + * configuration, such as: a regular client, a "bridge" client, the {@link Serveur server} and/or {@link Platform + * platforms}. + * + * @param args the options supplied when executing the launcher. */ public static void main(String[] args) throws Exception { diff --git a/src/eu/telecom_bretagne/praxis/common/NetUtils.java b/src/eu/telecom_bretagne/praxis/common/NetUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..0124292a76d22b496a63df91eb81f810c69412ba --- /dev/null +++ b/src/eu/telecom_bretagne/praxis/common/NetUtils.java @@ -0,0 +1,170 @@ +/** + * + */ +package eu.telecom_bretagne.praxis.common; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author Sébastien Bigaret + */ +public class NetUtils +{ + static private final String CLASS_NAME = NetUtils.class.getName(); + + /** + * This map caches the result computed by {@link #isLocal(String)} and {@link #isLocal(String, boolean)}. + */ + static private ConcurrentHashMap<String, Boolean> isLocalCache = new ConcurrentHashMap<>(); + + + /** + * Stores {@link InetAddress#getLocalHost()}: when a machine has a misconfigured DNS, one call can take several + * seconds. At the time of writing (September 2017), this happens on some Mac OS X. + * + * @see <a href= + * "https://stackoverflow.com/questions/33289695/inetaddress-getlocalhost-slow-to-run-30-seconds/41847289#41847289"> + * InetAddress.getLocalHost() slow to run (30+ seconds)</a> + * @see <a href="https://github.com/thoeni/inetTester">inetTester, by Antonio Troina</a> + */ + static private InetAddress localhostInetAddress; + + /** + * Same as {@link #localhostInetAddress}, but for {@code InetAddress.getAllByName("localhost")}. + */ + static private InetAddress[] allLocalhostInetAddress; + + static + { + try + { + localhostInetAddress = InetAddress.getLocalHost(); + } + catch (UnknownHostException e) + { + localhostInetAddress = null; + } + try + { + allLocalhostInetAddress = InetAddress.getAllByName("localhost"); + } + catch (UnknownHostException e) + { + allLocalhostInetAddress = new InetAddress[] {}; + } + } + + /** + * The real logic behind {@link #isLocal(String)} and {@link #isLocal(String, boolean)}. Exceptions like + * {@link UnknownHostException} or {@link SocketException} are ignored (and the return value is false). + * + * @param host + * the host name or its IP address. + * @return {@code true} if the supplied host corresponds to the local machine. + */ + static private boolean _isLocal(final String host) + { + if ( host == null || host.startsWith("127.") || "localhost".equals(host) + || "::1".equals(host) || "0:0:0:0:0:0:0:1".equals(host) ) + return true; + // from this point on, isLocal cannot be null + InetAddress hostAddr = null; + try + { + hostAddr = InetAddress.getByName(host); + } + catch (UnknownHostException e) + { + return false; /* We cannot do anything if we can't get the InetAdress */ + } + + /* loopback or any-local: this is local */ + if ( hostAddr.isLoopbackAddress() || hostAddr.isAnyLocalAddress() ) + return true; + + /* Does it match the localhost? */ + if ( hostAddr.equals(localhostInetAddress) ) + { + Log.log.finest("This is InetAddress.getLocalHost()"); + return true; + } + + /* If we can find an interface for this hostAddr, it is local */ + try + { + final NetworkInterface localInterface = NetworkInterface.getByInetAddress(hostAddr); + if ( localInterface != null ) + { + Log.log.finest("Found a local interface"); + return true; + } + } + catch (SocketException e) + { /* it could not be determined: let's continue */ } + + /* last try: compare to every InetAddress associated to the hostname "localhost" */ + for (InetAddress local: allLocalhostInetAddress) + { + Log.log.finest(() -> "Testing localhost: " + local); + if ( local.equals(hostAddr) ) + { + Log.log.finest(() -> "Found localhost: " + local); + return true; + } + } + return false; + } + + /** + * Determines whether a given host (either a host name or an IP address) corresponds to the local host. Equivalent + * to {@code isLocal(host, false)}.<br/> + * + * @param host + * a host name, or an IP address. If {@code null}, returns {@code true} (same semantics as in + * {@link java.net.Socket#Socket(String, int)}). + * @return {@code true} if the host was found to be the local machine. When returning {@code false}, the method only + * indicates that the supplied {@code host} name could not be determined as the local host: it does + * <b>NOT</b> mean that the {@code host} is a valid host name or IP. + */ + static public boolean isLocal(final String host) + { + return isLocal(host, false); + } + + /** + * Determines whether a given host (either a host name or an IP address) corresponds to the local host. + * + * @param host + * a host name, or an IP address. If {@code null}, returns {@code true} (same semantics as in + * {@link java.net.Socket#Socket(String, int)}). + * @param cached + * If {@code true}, and if the method has already been called for the same host, the returned value is + * the one that was computed on the previous call. If {@code false}, the cache value for this + * {@code host} is invalidated and re-computed. + * @return {@code true} if the host was found to be the local machine.<br /> + * When returning {@code false}, the method only indicates that the supplied {@code host} name could not be + * determined as the local host: it does <b>NOT</b> mean that the {@code host} is a valid host name or IP. + */ + static public boolean isLocal(final String host, final boolean cached) + { + Boolean isLocal = null; + Log.log.entering(CLASS_NAME, "isLocal", new Object[] { host, cached }); + if ( host == null ) + isLocal = true; + else + isLocal = cached ? isLocalCache.get(host) : null; + + if ( isLocal == null ) + { + isLocal = _isLocal(host); + isLocalCache.put(host, isLocal); + } + Log.log.exiting(CLASS_NAME, "isLocal", isLocal); + return isLocal; + } + +} diff --git a/src/eu/telecom_bretagne/praxis/common/RMIMasterSocketFactory.java b/src/eu/telecom_bretagne/praxis/common/RMIMasterSocketFactory.java index 2550fb54f3308b06e4c32a4905cb5b33f13d85ef..54725bc95b3427ad6ba2383b1c83153ad0842437 100644 --- a/src/eu/telecom_bretagne/praxis/common/RMIMasterSocketFactory.java +++ b/src/eu/telecom_bretagne/praxis/common/RMIMasterSocketFactory.java @@ -5,8 +5,6 @@ package eu.telecom_bretagne.praxis.common; import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.rmi.server.RMISocketFactory; import java.util.Vector; @@ -86,42 +84,23 @@ class RMIMasterSocketFactory * @exception IOException * if an I/O error occurs during server socket creation */ - public java.net.Socket createSocket(String host, int port) throws java.io.IOException + public java.net.Socket createSocket(final String host, final int port) throws java.io.IOException { - boolean isLocal = host==null || host.startsWith("127.") || "localhost".equals(host); - if (!isLocal) - { - try - { - InetAddress hostAddr = InetAddress.getByName(host); - if (InetAddress.getLocalHost().equals(hostAddr)) - { - Log.log.finest("This is localhost"); - isLocal = true; - } - else - { - for (InetAddress local: InetAddress.getAllByName("localhost")) - { - Log.log.finest(()->"Testing localhost: "+local); - if (local.equals(hostAddr)) - isLocal = true; - } - } - } - catch (UnknownHostException e) {} - } + final String hostname = (host==null?"<null>":host); + Log.log.finer(()->"Looking for "+hostname+":"+port); + + final boolean isLocal = NetUtils.isLocal(host, true); if (isLocal) { - Log.log.finest(()->"direct connection to localhost: "+host+":"+port); + Log.log.finest(()->"direct connection to localhost: "+hostname+":"+port); return new java.net.Socket(host, port); } if (factory != null) { - Log.log.finest(()->"Using stored factory "+factory+" for "+host+":"+port); + Log.log.finest(()->"Using stored factory "+factory+" for "+hostname+":"+port); return factory.createSocket(host, port); } - Log.log.finest(()->"Calling super.createSocket <- "+host+":"+port); + Log.log.finest(()->"Calling super.createSocket <- "+hostname+":"+port); java.net.Socket s = super.createSocket(host, port); Log.log.finest(()->"super.createSocket returned -> "+( (s!=null)?s.getClass():"<null>") ); return s; diff --git a/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java b/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java index 5cdb26e109006691fa9e56add1b6601fffbd98b7..fe2277fb77467d7e246e9f0d16d1f00b73a9abea 100644 --- a/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java +++ b/src/eu/telecom_bretagne/praxis/common/ReleaseInfo.java @@ -7,13 +7,13 @@ package eu.telecom_bretagne.praxis.common; */ public abstract class ReleaseInfo { - public static final String release = "2.1"; + public static final String release = "2.2"; public static final int revision = 0; public static final int application_revision = Configuration.getInt("revision"); - public static final String release_date = "2017-09-07"; + public static final String release_date = "2017-10-18"; /** The date of the packaging. It has always been the same as {@link #release_date}: use the latter field instead */ @Deprecated diff --git a/src/eu/telecom_bretagne/praxis/common/XMLConstants.java b/src/eu/telecom_bretagne/praxis/common/XMLConstants.java index f8ab126609dfa890d939541d11e8351a53a2f4af..87afee059556d12e778941f5d436acce9529c58c 100644 --- a/src/eu/telecom_bretagne/praxis/common/XMLConstants.java +++ b/src/eu/telecom_bretagne/praxis/common/XMLConstants.java @@ -180,7 +180,7 @@ public interface XMLConstants /** * Path of the local file where the DTD specified by - * {@link #SC_DTD_PUBID} can be found. + * {@link #EXT_VIEWERS_DTD_PUBID} can be found. */ public static final String EXT_VIEWERS_DTD_FILE = "data/dtd/external_viewers.dtd"; diff --git a/src/eu/telecom_bretagne/praxis/core/execution/Activity.java b/src/eu/telecom_bretagne/praxis/core/execution/Activity.java index 43bdf8da455a5937b860f0ea87129272e02a4588..20da507ced6e26044f1b167f7f86bd9959573a60 100644 --- a/src/eu/telecom_bretagne/praxis/core/execution/Activity.java +++ b/src/eu/telecom_bretagne/praxis/core/execution/Activity.java @@ -43,7 +43,6 @@ public class Activity /** * * @param process - * @param program */ public Activity(Process process) { diff --git a/src/eu/telecom_bretagne/praxis/core/execution/ResultStore.java b/src/eu/telecom_bretagne/praxis/core/execution/ResultStore.java index cba5f5d421e291fb518eacd598dec809ccc3990f..36d08889885790d85bd4961915a87893d1bca450 100644 --- a/src/eu/telecom_bretagne/praxis/core/execution/ResultStore.java +++ b/src/eu/telecom_bretagne/praxis/core/execution/ResultStore.java @@ -5,9 +5,11 @@ import java.io.File; import java.io.IOException; import java.io.InvalidClassException; import java.sql.Connection; +import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -18,6 +20,7 @@ import java.util.List; import java.util.logging.Level; import eu.telecom_bretagne.praxis.common.Log; +import eu.telecom_bretagne.praxis.common.PraxisPreferences; import eu.telecom_bretagne.praxis.common.Utile; import eu.telecom_bretagne.praxis.core.execution.Result.Status; import eu.telecom_bretagne.praxis.core.workflow.WorkflowID; @@ -66,7 +69,7 @@ public class ResultStore */ private static transient final DateFormat RESULT_date_fmt = new SimpleDateFormat("yyyyMMdd_HHmmss.SSSZ"); - protected Connection db_connection; + private Connection db_connection; /** * Take care of deserializing the Result object. @@ -82,33 +85,37 @@ public class ResultStore return (Result) Utile.deserializeObject(result_asHexStr); } - /** - * @param c - * the connection to use - * @throws NullPointerException - * if c is null - */ - public ResultStore(Connection c) throws NullPointerException, java.sql.SQLException + public ResultStore() throws java.sql.SQLException { - if (c == null) - throw new NullPointerException("Invalid null connection"); - db_connection = c; + final String workspace = PraxisPreferences.get(PraxisPreferences.rootNode, "prefix"); + final String path = workspace + "/serverResultStore.bdb"; + boolean createDB = !new File(path).exists(); + try + { + Class.forName("org.sqlite.JDBC").newInstance(); + } + catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) + { + Log.log.log(Level.SEVERE, "Could not load or create sqlite JDBC driver", e); + } + db_connection = DriverManager.getConnection("jdbc:sqlite:/" + path); + if (createDB) + { + db_connection.createStatement().execute(ResultStore.RESULT_db_schema); + } + try ( final Statement statement = db_connection.createStatement() ) + { + statement.execute("PRAGMA synchronous = NORMAL;"); + statement.execute("PRAGMA journal_mode=WAL;"); + } + catch(SQLException e) + { + Log.log.log(Level.WARNING, "Unable to set journal_mode to WAL w/ synchronous=normal", e); + } db_connection.setAutoCommit(false); this.consistencyCheck(); } - /** - * Returns the connection with the underlying database. Callers must acquire a lock on the object before using it; - * callers should NOT attempt to close the connection. <br> - * Note: this method is currently only here so that the standalone version of praxis can upgrade the db schema, - * see {@link eu.telecom_bretagne.praxis.common.ReleaseInfo#update_ServerDB_0_686()}. - * @return the connection to the database - */ - public Connection getConnection() - { - return db_connection; - } - /** * Checks basic features in the DB, and removes elements that are invalid. * See source code for details. diff --git a/src/eu/telecom_bretagne/praxis/core/workflow/Parameter.java b/src/eu/telecom_bretagne/praxis/core/workflow/Parameter.java index fa1763d8aaa2804afec80e7de8441eb4de779390..87f96840854b58492fd4c5b3880a70b288838fa2 100644 --- a/src/eu/telecom_bretagne/praxis/core/workflow/Parameter.java +++ b/src/eu/telecom_bretagne/praxis/core/workflow/Parameter.java @@ -27,7 +27,7 @@ import eu.telecom_bretagne.praxis.core.workflow.Workflow.XMLWarnings; */ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Serializable { - + private static final long serialVersionUID = -7236633502138745978L; public static final String INPUT_PROPERTY = "input"; public static final String OUTPUT_PROPERTY = "outputs"; @@ -36,41 +36,41 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser public boolean isInput() { return getDescription().getType().isInput(); } - + public boolean isOutput() { return getDescription().getType().isOutput(); } - + public List<IOType> types() { return getDescription().getTypes(); } - - - + + + protected static final String PARAM_ID = "idref"; public static final String INFO = "info"; public static final String INFO_NAME = "name"; public static final String INFO_VALUE = "value"; - + /** Id pointing to the corresponding ParameterDescription */ protected String ref_id; - + /** The enclosing Program */ protected Program program; - + /** Value for the parameter, only for {@link ParameterType#INT}, * {@link ParameterType#FLOAT}, {@link ParameterType#STRING}, {@link ParameterType#TEXT}, * and {@link ParameterType#BOOLEAN} parameters */ String data = null; - + /** Used only by {@link ParameterType#ENUM} parameters */ Item item; - + /** Used only by {@link ParameterType#isInput() input} parameters * @see #io */ WorkflowInput input; - + /** Used only by {@link ParameterType#isInput() input} and * {@link ParameterType#isOutput() output} parameters. * @@ -94,19 +94,26 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser protected PropertyChangeSupport propChgSupport = new PropertyChangeSupport(this); /** - * @throws InvalidXMLException */ + * @throws InvalidXMLException + * if the object can not be built from the informations included in the supplied XML node + * @throws NullPointerException + * if parameter parent_prg is {@code null}. + */ public Parameter(Element xml, Program parent_prg, XMLWarnings warnings) throws InvalidXMLException { + if ( parent_prg == null ) + throw new NullPointerException("Parameter parent_prg cannot be null"); + InvalidXMLException xml_exc = new InvalidXMLException(ELEMENT_TYPE.PARAMETER); - + ref_id = xml.getAttributeValue(PARAM_ID); if (ref_id == null) throw xml_exc; xml_exc.setName(ref_id); program = parent_prg; Element info = xml.getChild(INFO); - + if ( getDescription() == null ) { if (info!=null) /* if null, the parameter was not activated, so it is not use to report it */ @@ -116,7 +123,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser info.getAttributeValue(INFO_VALUE), }); throw xml_exc.setMsg("Unable to find a valid description for parameter").setIsFatal(false); } - + switch (getDescription().getType()) { case FLOAT: case INT: @@ -167,16 +174,22 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser case COMMAND: break; } - } /** - * - * @param description the corresponding parameter + * Builds a new parameter. + * + * @param description + * the corresponding description * @param parent_prg + * the program this parameter belongs to + * @throws NullPointerException + * if parameter parent_prg is {@code null}. */ public Parameter(ParameterDescription description, Program parent_prg) { + if ( parent_prg == null ) + throw new NullPointerException("Parameter parent_prg cannot be null"); program = parent_prg; init(description); } @@ -213,21 +226,21 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser eu.telecom_bretagne.praxis.common.Utile.unimplemented(); } } - + /** */ public Element toXML() { Element param_xml = new Element("parameter"); - + param_xml.setAttribute(PARAM_ID, ref_id); - + Element data_xml = new Element("data"); - + ParameterDescription param_desc = getDescription(); String param_desc_displayName=param_desc.getDisplayName(); if (param_desc_displayName==null) param_desc_displayName=""; - + if ( isInput() && input != null) data_xml.setAttribute("input_id", ""+program.workflow.getIdForInput(input)); else if ( isInput() ) @@ -259,33 +272,30 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser param_xml.addContent(data_xml); return param_xml; } - - /** Returns the 'id' used in the xml representation of an output parameter: - * @return a string made w/ the concatenation of the program's id, the - * character point <tt>"."</tt> and the receiver's ref_id; it is used in - * {@link #toXML()} - * @throw {@link IllegalStateException} if the receiver is not an - * {@link #isOutput() output parameter}. + + /** + * Returns the 'id' used in the xml representation of an output parameter: + * + * @return a string made w/ the concatenation of the program's id, the character point <tt>"."</tt> and the + * receiver's ref_id; it is used in {@link #toXML()} + * @throws IllegalStateException + * if the receiver is not an {@link #isOutput() output parameter}. */ public String output_xml_id() { // TODO make it visibility-package again (same for workflow.getIdForProgram()) if ( ! isOutput() ) throw new IllegalStateException("receiver is not an output"); return program.workflow.getIdForProgram(program)+"."+ref_id; } - + /** Returns the corresponding ParameterDescription * * @return the corresponding ParameterDescription - * @throws IllegalStateException */ - public ParameterDescription getDescription() throws IllegalStateException + public ParameterDescription getDescription() { - if ( program == null ) - throw new IllegalStateException(""); - return program.getDescription().getParameterWithId(this.ref_id); } - + /** * Evaluates the dependencies of the receiver and, given the values of * the other parameters in the {@link #getProgram() receiver's program}, @@ -305,7 +315,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser throw new UnsupportedOperationException("isActivated() raised on "+prg_param, e); } } - + /** * Tells whether the value hold by this parameter is valid with respect to the parameter's description. Depending on * the context, callers may be also interested in knowing whether the parameter is {@link #isActivated() activated} @@ -323,22 +333,24 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser public String getData() { return data; } - + public void setData(String data) { propChgSupport.firePropertyChange("data", this.data, this.data = data); } - + /** Returns the selected item for a {@link ParameterType#ENUM} parameter. * @return one of the receiver's {@link ParameterDescription#getItems() possible items}. */ public Item getItem() { return item; } - - /** Sets the selected item - * @throw {@link IllegalArgumentException} if the item is not compatible - * with the {@link ParameterDescription#hasItem(Item) parameter's description}, - * or if the receiver is not a {@link ParameterType#ENUM} parameter + + /** + * Sets the selected item + * + * @throws IllegalArgumentException + * if the item is not compatible with the {@link ParameterDescription#hasItem(Item) parameter's + * description}, or if the receiver is not a {@link ParameterType#ENUM} parameter */ public void setItem(Item item) { if ( getDescription().hasItem(item) ) @@ -346,14 +358,14 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser else throw new IllegalArgumentException("parameter item is not valid"); } - + /** * @return Returns the program. */ public Program getProgram() { return program; } - + /** Tells whether an input parameter and an output parameter are compatible * @see ParameterDescription#isCompatibleWith(ParameterDescription) the * corresponding method in ParameterDescription @@ -361,11 +373,11 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser public boolean isCompatibleWith(Parameter parameter) { return getDescription().isCompatibleWith(parameter.getDescription()); } - + public WorkflowInput getInput() { return input; } - + public void setInput(WorkflowInput input) { if (this.input!=null) { @@ -375,8 +387,8 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser input.addOutput(this); propChgSupport.firePropertyChange(INPUT_PROPERTY, this.input, this.input = input); } - - + + /** * Returns the input parameter connected to this (output) parameter. * @return the connected parameter, or null if it is not connected. @@ -384,7 +396,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser public Parameter getPrgInput() { return prg_input; } - + /** * Returns the output parameters connected to this (input) parameter. * @return An array of the connected parameters. @@ -455,7 +467,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser throw new IllegalArgumentException("setPrgInput() only for input parameters"); if ( output_parameter!=null && !output_parameter.isOutput() ) throw new IllegalArgumentException("setPrgInput() param must be an output parameter"); - + Parameter old_input = prg_input; /* disconnect any existing link */ if ( prg_input != null ) @@ -469,7 +481,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser } propChgSupport.firePropertyChange(PRG_INPUT_PROPERTY, old_input, this.input); } - + /** * Adds the supplied parameter from the list of this parameter's outputs. This method also takes care of calling * {@link #setPrgInput(Parameter)} with <code>this</code> as its parameter.<br> @@ -481,7 +493,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser * @throws IllegalArgumentException * if <code>this</code> is not an output parameter or if the supplied input parameter is not an input * parameter - * @throws NullPointerExcoutput_parametereption + * @throws NullPointerException * if input_parameter is null * @see #setPrgInput(Parameter) * @see #removeOutput(Parameter) @@ -492,10 +504,10 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser throw new IllegalArgumentException("addOutput() only for output parameters"); if ( !input_parameter.isInput() ) // NullPointerExc. if null throw new IllegalArgumentException("addOutput() param must be an input parameter"); - + input_parameter.setPrgInput(this); } - + /** * Internally used to simply add the supplied input parameter to the outputs of this object; no extra operation is * done, except that property change listeners are notified.<br> @@ -513,7 +525,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser propChgSupport.firePropertyChange(OUTPUT_PROPERTY, null, getOutputs()); } } - + /** * Removes the supplied parameter from the list of this parameter's outputs. This method also takes care of * resetting the input parameter by calling {@link #setPrgInput(Parameter)} with a null value.<br> @@ -538,7 +550,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser input_parameter.setPrgInput(null); } - + /** * Internally used to simply remove the supplied input parameter from this' outputs; no extra operation is done, * except that property change listeners are notified.<br> @@ -553,7 +565,7 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser if ( outputs.remove(input_parameter) ) propChgSupport.firePropertyChange(OUTPUT_PROPERTY, null, getOutputs()); } - + /** * Sets this program's {@link #getInput() "workflow input"} to <code>null</code>, and removes any * {@link #getPrgInput() input connections} and {@link #getOutputs() output connections} this parameter may model.<br> @@ -570,9 +582,18 @@ public class Parameter implements Cloneable, PropertyChangeListener, java.io.Ser for (Parameter p: outputs_copy) // we need a copy here: p.setPrgInput() modifies this.outputs p.setPrgInput(null); } - - /** TODO: add big fat warning, do not use, for GUI only */ + + /** + * TODO: add big fat warning, do not use, for GUI only + * + * @param prg + * the program to which the shallow copy should be attached. It must be non-null. + * @throws NullPointerException + * if parameter prg is {@code null}. + */ public Parameter shallowCopyFor(Program prg) { + if ( prg == null ) + throw new NullPointerException("parameter prg cannot be null"); Parameter p = null; try { p = (Parameter) this.clone(); diff --git a/src/eu/telecom_bretagne/praxis/core/workflow/Program.java b/src/eu/telecom_bretagne/praxis/core/workflow/Program.java index 6b61e6f0daa543b2c193bb9d3f43e20bf2f74852..af302180535dc55fb0b2d9ab73c560f1d40669d0 100644 --- a/src/eu/telecom_bretagne/praxis/core/workflow/Program.java +++ b/src/eu/telecom_bretagne/praxis/core/workflow/Program.java @@ -88,12 +88,17 @@ public class Program /** * Builds a new program + * * @param xml_node + * the XML element describing the program * @param warnings + * the object is which warnings aimed at the user are stored * @param parent * the workflow containing the program. It cannot be {@code null}. * @throws InvalidXMLException - * @throws NullPointerException if {@code parent} is {@code null}. + * if the object cannot be created from the supplied XML element. + * @throws NullPointerException + * if {@code parent} is {@code null}. */ public Program(Element xml_node, Workflow parent, XMLWarnings warnings) throws InvalidXMLException { @@ -103,7 +108,9 @@ public class Program /** * Builds a new program + * * @param prgDesc + * this program's description * @param parent * the workflow containing the program. It cannot be {@code null}. * @throws NullPointerException @@ -235,12 +242,16 @@ public class Program /** * Reads the provided xml element and builds the corresponding Program. During this operation, the receiver is * completely reinitialized. + * * @param xml_node + * the XML element describing the program + * @param warnings + * the object is which warnings aimed at the user are stored * @throws InvalidXMLException * TODO pointer to DTD * @see #toXML() */ - public Map<String, String> fromXML(Element xml_node, XMLWarnings warnings) throws InvalidXMLException + public void fromXML(Element xml_node, XMLWarnings warnings) throws InvalidXMLException { List<Element> params; InvalidXMLException xml_exc = new InvalidXMLException(ELEMENT_TYPE.PROGRAM); @@ -335,14 +346,13 @@ public class Program if (p.getDescription().getId().equals(paramDesc.getId())) parameters.add(p); } - return null; } /** * Builds and returns the XML representation of self. * This is equivalent to {@link #toXML(boolean) toXML(false)} * @return the xml equivalent for <tt>this</tt> - * @see #fromXML(Element) + * @see #fromXML(Element, XMLWarnings) */ public Element toXML() { @@ -357,7 +367,7 @@ public class Program * are included. * @return the xml equivalent for <tt>this</tt>, minus parameters that should not be exported if * {@code includeUserBoundParameters} is {@code true}. - * @see #fromXML(Element) + * @see #fromXML(Element, XMLWarnings) */ public Element toXML(boolean includeUserBoundParameters) { @@ -392,7 +402,6 @@ public class Program * from XML) expect that the receiver always returns the same object --see * {@link RemoteComponents#cacheResourceRepositoryAnswers} for details. * @return the description attached to this program. - * @see #description */ public ProgramDescription getDescription() { @@ -515,7 +524,7 @@ public class Program /** * Returns the ExecutionSet this activity belongs to. Execution sets are built when the execution is planned.<br/> * Activities are assigned to or removed from an execution set by the sets themselves, see - * {@link ExecutionSet#add(eu.telecom_bretagne.praxis.core.execution.Activity)} and {@link ExecutionSet#remove(Object)}. + * {@link ExecutionSet#add(eu.telecom_bretagne.praxis.core.workflow.Program)} and {@link ExecutionSet#remove(Object)}. * @return the execution set this activity belongs to */ public ExecutionSet getExecutionSet() diff --git a/src/eu/telecom_bretagne/praxis/core/workflow/ProgramDelegate.java b/src/eu/telecom_bretagne/praxis/core/workflow/ProgramDelegate.java index 28cd9f88fbb5fe9e349da0280095ec567e123696..1848d6cea2b322007966de43d037133bb39a2981 100644 --- a/src/eu/telecom_bretagne/praxis/core/workflow/ProgramDelegate.java +++ b/src/eu/telecom_bretagne/praxis/core/workflow/ProgramDelegate.java @@ -14,7 +14,7 @@ import eu.telecom_bretagne.praxis.core.resource.ProgramDescription; import eu.telecom_bretagne.praxis.core.workflow.Workflow.XMLWarnings; /** - * A delegate for the class {@link eu.telecom_bretagne.praxis.core.resource.Program}. + * A delegate for the class {@link eu.telecom_bretagne.praxis.core.workflow.Program}. * @author Sébastien Bigaret */ public class ProgramDelegate @@ -68,12 +68,10 @@ public class ProgramDelegate * null is sufficient. * @return the requested description, or null if none can be found. When non-null, the returned description will * be used to build the program. - * @throws InvalidXMLException */ public ProgramDescription findAlternateProgramDescription(String prg_description_id, String prg_description_full_name, XMLWarnings warnings, InvalidXMLException xml_exc) - throws InvalidXMLException { ProgramDescription prgDesc = null; diff --git a/src/eu/telecom_bretagne/praxis/core/workflow/Workflow.java b/src/eu/telecom_bretagne/praxis/core/workflow/Workflow.java index 32a2643c66f08f4b44a1833ceadc943f44a24a9a..36a734ed0917bf1da87c1b1f9ac569682216cd77 100644 --- a/src/eu/telecom_bretagne/praxis/core/workflow/Workflow.java +++ b/src/eu/telecom_bretagne/praxis/core/workflow/Workflow.java @@ -96,8 +96,8 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable private ArrayList<I18NCouple> warnings = new ArrayList<I18NCouple>(); /** * Adds a new warning. - * @param warning - * @param params + * @param warning a string describing the warning, with placeholders for the params + * @param params the parameters to insert into the warning's placeholders */ public void add(String warning, String[] params) { @@ -304,7 +304,7 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable } /** Returns the program corresponding to the supplied id - * @param prg_id + * @param prg_id a program id * @return {@code null} if no such program exists */ public Program getProgramWithId(String prg_id) { @@ -324,7 +324,7 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable /** Returns the input (file or database) corresponding to the supplied id. * Note that ids are internal stuff, only needed when storing and restoring * from xml files. - * @param input_id + * @param input_id an input id * @return {@code null} if no such input exists */ public WorkflowInput getInputWithId(long input_id) { // TODO back to: package-visibility, not public @@ -338,9 +338,11 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable * from xml files. * @param input the {@link WorkflowInput} * @return the corresponding id - * @throw {@link IllegalArgumentException} if no such WorkflowInput object is referenced within this Workflow. + * @throws IllegalArgumentException if no such WorkflowInput object is referenced within this Workflow. */ - public long getIdForInput(WorkflowInput input) { // TODO back to: package-visibility, not public + public long getIdForInput(WorkflowInput input) // TODO back to: package-visibility, not public + throws IllegalArgumentException + { for (long input_id: inputs.keySet()) if ( inputs.get(input_id)==input ) return input_id; @@ -355,9 +357,11 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable * from xml files. * @param program the {@link Program} for which the id is needed * @return the corresponding id - * @throw {@link IllegalArgumentException} if no such Program object is referenced within this Workflow. + * @throws IllegalArgumentException if no such Program object is referenced within this Workflow. */ - public String getIdForProgram(Program program) { + public String getIdForProgram(Program program) + throws IllegalArgumentException + { for (String prg_id: programs.keySet()) if ( programs.get(prg_id)==program ) return prg_id; @@ -399,6 +403,9 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable return prg; } + /* (non-Javadoc) + * @see java.lang.Object#clone() + */ @Override public Workflow clone() { Workflow clone; @@ -720,9 +727,10 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable * Returns the workflow serialized as XML, in a {@link Document} * * @param includeUserBoundParameters - * Indicates whether parameters that are marked as "userBound" should be included. + * Indicates whether parameters that are marked as + * {@link eu.telecom_bretagne.praxis.core.resource.ParameterDescription#isUserBound() "userBound"} should + * be included. * @return the serialized workflow. - * @see #toXML() */ public Document toXMLDocument(boolean includeUserBoundParameters) { @@ -743,7 +751,7 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable /** * Save the workflow in a zipped file, along with all its (valid) input files. * The zip contains the workflow, named workflow.<ext>, and its input files - * @param zipFile + * @param zipFile the file into which the workflow and its inputs are zipped. * @throws IOException in case any error occurs when writing the zip. When this happens, the * zipFile, is created, is deleted before the exception is raised. */ @@ -759,6 +767,7 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable * <ul> * <li>can contain the workflow itself, * <li>can put everything at the top-level, or within a specified directory the workflow itself + * * @param zipFile * the zip file to be created * @param zipDirectory @@ -771,13 +780,19 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable * if non-null, the workflow is also put in the zip with the provided filename. If {@code null}, the * workflow is not put into the zip. * @param abortOnErrors - * if {@code true}, any error happening when trying to add an input file is fatal. Otherwise, the zip - * is build and ignores input files that cannot be found or read. NBote that this does not avoid + * if {@code true}, any error happening when trying to add an input file is fatal. Otherwise, the zip is + * build and ignores input files that cannot be found or read. NBote that this does not avoid * {@code IOException} at all: if the zip could not be written, the exception is always thrown. + * @param includeUserBoundParameters + * Indicates whether parameters that are marked as + * {@link eu.telecom_bretagne.praxis.core.resource.ParameterDescription#isUserBound() "userBound"} should + * be included. * @return the workflow that was saved. Note that this workflow is <b>not</b> the same as {@code this}, it is a * clone of this object where input files are adapted so that they refer to the same filenames as those * stored in the zip, relative to the zip's root directory. * @throws IOException + * in case any error occurs when writing the zip. When this happens, the zipFile, is created, is deleted + * before the exception is raised. */ public Workflow exportWorkflowWithInput(File zipFile, String zipDirectory, File copyToDirectory, String workflow_filenameInZip, boolean abortOnErrors, @@ -1004,6 +1019,10 @@ public class Workflow implements java.lang.Cloneable, java.io.Serializable return true; } + /** + * Returns the workflow's {@link #getName() name}. + * @see java.lang.Object#toString() + */ @Override public String toString() { diff --git a/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/ProgramParser.java b/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/ProgramParser.java index 485c11289fec1e60987eb2bcf5c0cf579a209c08..aebf2b45519eea037b8491f11720c430934ffedd 100644 --- a/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/ProgramParser.java +++ b/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/ProgramParser.java @@ -29,15 +29,21 @@ public class ProgramParser static final String PARAMETER = "parameter"; /** - * @param workflow - * The attached workflow. It must not be {@code null}. If the method is successful, this workflow is - * <b>modified</b>: the return program is added to the workflow just before being returned. - * @param startElement - * @param eventReader - * @param warnings - * @return - * @throws InvalidXMLException - */ + * Builds a program from the informations stored in an XML structure. + * + * @param workflow + * The attached workflow. It must not be {@code null}. If the method is successful, this workflow is + * <b>modified</b>: the return program is added to the workflow just before being returned. + * @param startElement + * the root element {@code <program>} containing the informations + * @param eventReader + * the event reader with which the parsing of the supplied workflow has begun + * @param warnings + * the object is which warnings intended for the user should be stored. + * @return the built Program object + * @throws InvalidXMLException + * if case the XML is not valid + */ public static Program fromXML(Workflow workflow, final StartElement startElement, XMLEventReader eventReader, XMLWarnings warnings) throws InvalidXMLException diff --git a/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/WorkflowParser.java b/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/WorkflowParser.java index c1162f94de4c7b3a033e988a2bba612935ffde78..f0157e0e86b61e799477490d84cfc6ab5649c40b 100644 --- a/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/WorkflowParser.java +++ b/src/eu/telecom_bretagne/praxis/core/workflow/io/xml/WorkflowParser.java @@ -38,12 +38,32 @@ public abstract class WorkflowParser static final String INPUTS = "inputs"; - public static Workflow create(String filename, Workflow.XMLWarnings xmlWarnings) throws Throwable + /** + * Builds a new workflow by reading a file + * + * @param filename + * the path of the xml file to read + * @param xmlWarnings + * the object is which warnings intended for the user should be stored. + * @return the new workflow + */ + public static Workflow create(String filename, Workflow.XMLWarnings xmlWarnings) + throws InvalidXMLException, IOException, XMLStreamException { return create(new File(filename), xmlWarnings); } - public static Workflow create(File file, Workflow.XMLWarnings xmlWarnings) throws Throwable + /** + * Builds a new workflow by reading an XML file. + * + * @param file + * the file containing the workflow + * @param xmlWarnings + * the object is which warnings intended for the user should be stored. + * @return the new workflow + */ + public static Workflow create(File file, Workflow.XMLWarnings xmlWarnings) + throws InvalidXMLException, IOException, XMLStreamException { if ( ! (file.exists() && file.isFile() && file.canRead()) ) throw new IllegalArgumentException("invalid workflow file"); @@ -342,7 +362,8 @@ public abstract class WorkflowParser } /** - * @param args + * Simple test for Workflow read/write + * @param args (ignored) */ public static void main(String[] args) throws Throwable { diff --git a/src/eu/telecom_bretagne/praxis/server/Server.java b/src/eu/telecom_bretagne/praxis/server/Server.java index 6b43a53a89154bd0aa55db220ea057a4ef7e55f8..5fca1c8de241750c70c27eb3462dbcccc0013d4a 100644 --- a/src/eu/telecom_bretagne/praxis/server/Server.java +++ b/src/eu/telecom_bretagne/praxis/server/Server.java @@ -73,11 +73,13 @@ implements PlatformToServerEventListener, ClientToServerEventListener /* **** Communicating w/ the platform **** */ /** - * The zipped file is deleted after the event has been sent. + * Request an execution. Note that the zipped file is deleted after the event has been sent. + * * @param execEngine + * the execution engine prepared for executing the task * @param zip - * A zip file containing the necessary input files. If no file is needed for the execution, it equals - * to <code>null</code>. <br> + * A zip file containing the necessary input files. If no file is needed for the execution, it equals to + * <code>null</code>. <br> * <b>Please note that the zip file is deleted after the event has been sent</b>. */ public void requestExecution(ExecutionEngine execEngine, File zip) diff --git a/src/eu/telecom_bretagne/praxis/server/Serveur.java b/src/eu/telecom_bretagne/praxis/server/Serveur.java index ff8e0be2e3b3c3ad65cbd883f23f31049ad93039..bb7a22186f0c3d220583090d15e41984e7af9752 100644 --- a/src/eu/telecom_bretagne/praxis/server/Serveur.java +++ b/src/eu/telecom_bretagne/praxis/server/Serveur.java @@ -7,10 +7,6 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -68,8 +64,6 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac */ static private List<Server> platforms = Collections.synchronizedList(new ArrayList<Server>()); - static private final String resultStoreDBFilename; - static private ResultStore resultStore; static private String tmpDir; @@ -87,9 +81,7 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac static { - String workspace = PraxisPreferences.get(PraxisPreferences.rootNode, "prefix"); - tmpDir = workspace + "/tmp"; - resultStoreDBFilename = workspace + "/serverResultStore.bdb"; + tmpDir = PraxisPreferences.get(PraxisPreferences.rootNode, "prefix") + "/tmp"; try { @@ -98,26 +90,7 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac serveur = new Serveur("unused_use_ssl"); // moved here because of RemoteException else serveur = new Serveur(); - boolean createDB = !new File(resultStoreDBFilename).exists(); - Class.forName("org.sqlite.JDBC").newInstance(); - @SuppressWarnings("resource") // does not leak! it is used by the ResultStore object! do NOT close it! - Connection c = DriverManager.getConnection("jdbc:sqlite:/" + resultStoreDBFilename); - if (createDB) - { - c.createStatement().execute(ResultStore.RESULT_db_schema); - } - try - { - final Statement statement = c.createStatement(); - statement.execute("PRAGMA synchronous = NORMAL;"); - statement.execute("PRAGMA journal_mode=WAL;"); - statement.close(); - } - catch(SQLException e) - { - Log.log.log(Level.WARNING, "Unable to set journal_mode to WAL w/ synchronous=normal", e); - } - resultStore = new ResultStore(c); + resultStore = new ResultStore(); } catch (Exception e) { @@ -330,7 +303,7 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac /** * Tells whether there is a client currently connected to the server with the supplied login. - * @param login + * @param login a client's login * @return {@code true} if such a client exists, {@code false} otherwise */ public static boolean isClientRegistered(String login) @@ -376,7 +349,6 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac /** * Starts the socket server on the specified port. - * @return true if the server was successfully launched, false otherwise */ public static void startSocketServer() { @@ -400,7 +372,6 @@ public class Serveur extends UnicastRemoteObject implements RemoteServerInterfac /** * Starts the SSL socket server on the specified port. - * @return true if the server was successfully launched, false otherwise */ public static void startSSLSocketServer() { diff --git a/src/eu/telecom_bretagne/praxis/server/execution/ExecutionEngine.java b/src/eu/telecom_bretagne/praxis/server/execution/ExecutionEngine.java index d1d7cd7a5a3f6afa6b8960ea032d4dae34450682..df304aee153b808056c3ffa15613359554c8e29b 100644 --- a/src/eu/telecom_bretagne/praxis/server/execution/ExecutionEngine.java +++ b/src/eu/telecom_bretagne/praxis/server/execution/ExecutionEngine.java @@ -17,7 +17,6 @@ import eu.telecom_bretagne.praxis.core.workflow.Program; import eu.telecom_bretagne.praxis.core.workflow.WorkflowID; import eu.telecom_bretagne.praxis.server.execution.platform.PlatformDescription; import eu.telecom_bretagne.praxis.server.execution.platform.ProgramExecutionEngine; -import eu.telecom_bretagne.praxis.server.execution.platform.SGEExecutionEngine; import eu.telecom_bretagne.praxis.server.execution.platform.ShellExecutionEngine; import eu.telecom_bretagne.praxis.server.execution.platform.WorkflowExecutionEngine; import eu.telecom_bretagne.praxis.server.execution.platform.PlatformDescription.CannotExecuteException; @@ -104,7 +103,7 @@ public abstract class ExecutionEngine */ private static Map<String, ExecutionEngineConfigurationFactory> factories = null; - /** An executionprogress monitor doing nothing whose operations are no-op */ + /** An execution progress monitor doing nothing whose operations are no-op */ public static final ExecutionProgressMonitor noopProgressMonitor = new ExecutionProgressMonitor() { @Override public void setProgress(Result result) { } @@ -115,14 +114,13 @@ public abstract class ExecutionEngine * <ul> * <li> {@link ProgramExecutionEngine.ProgramExecutionEngineConfigurationFactory}, * <li> {@link ShellExecutionEngine.ShellExecutionEngineConfigurationFactory}, - * <li> {@link SGEExecutionEngine.SGEExecutionEngineConfigurationFactory}. + * <li> {@link WorkflowExecutionEngine.WorkflowExecutionEngineConfigurationFactory}. * </ul> */ static { factories = new Hashtable<String, ExecutionEngineConfigurationFactory>(); registerConfigurationFactory(new ShellExecutionEngine.ShellExecutionEngineConfigurationFactory()); - registerConfigurationFactory(new SGEExecutionEngine.SGEExecutionEngineConfigurationFactory()); registerConfigurationFactory(new ProgramExecutionEngine.ProgramExecutionEngineConfigurationFactory()); registerConfigurationFactory(new WorkflowExecutionEngine.WorkflowExecutionEngineConfigurationFactory()); } @@ -223,6 +221,7 @@ public abstract class ExecutionEngine targetName = targetName.trim().toUpperCase(Locale.ENGLISH); return Enum.valueOf(getTargets(), targetName); + //return Target.valueOf(targetName); } /** diff --git a/src/eu/telecom_bretagne/praxis/server/execution/SimpleFormatterPlatform.java b/src/eu/telecom_bretagne/praxis/server/execution/SimpleFormatterPlatform.java index 7ced7f21ea40c3953d5b948a61b40d8244676745..7c692c56b6fddabf9a7adb8924f023be158be5ad 100644 --- a/src/eu/telecom_bretagne/praxis/server/execution/SimpleFormatterPlatform.java +++ b/src/eu/telecom_bretagne/praxis/server/execution/SimpleFormatterPlatform.java @@ -404,7 +404,7 @@ public abstract class SimpleFormatterPlatform * offered to subclasses, since subclasses may as well override {@link #generateScript(Resource)}, and iterate on * the {@link Resource#getAllConcreteResources() concrete resources} after calling super implementation. */ - public void generateScript_justProcessed(Activity activity) {} + protected void generateScript_justProcessed(Activity activity) {} protected Enum<?> getTarget(ParameterDescription description, Parameter parameter) { diff --git a/src/eu/telecom_bretagne/praxis/server/execution/platform/SGEExecutionEngine.java b/src/eu/telecom_bretagne/praxis/server/execution/platform/SGEExecutionEngine.java deleted file mode 100644 index 9a160d39e17f79ad7625005107e7139459ba0ee0..0000000000000000000000000000000000000000 --- a/src/eu/telecom_bretagne/praxis/server/execution/platform/SGEExecutionEngine.java +++ /dev/null @@ -1,446 +0,0 @@ -/* License: please refer to the file README.license located at the root directory of the project */ -package eu.telecom_bretagne.praxis.server.execution.platform; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.logging.Level; - -import org.ggf.drmaa.DrmaaException; -import org.ggf.drmaa.ExitTimeoutException; -import org.ggf.drmaa.JobInfo; -import org.ggf.drmaa.JobTemplate; -import org.ggf.drmaa.Session; -import org.ggf.drmaa.SessionFactory; - -import eu.telecom_bretagne.praxis.common.Environment; -import eu.telecom_bretagne.praxis.common.Log; -import eu.telecom_bretagne.praxis.common.Utile; -import eu.telecom_bretagne.praxis.core.execution.ExecutionID; -import eu.telecom_bretagne.praxis.core.execution.ProgramResult; -import eu.telecom_bretagne.praxis.core.execution.Result; -import eu.telecom_bretagne.praxis.core.workflow.WorkflowID; -import eu.telecom_bretagne.praxis.server.execution.ExecutionEngine; - - - -public class SGEExecutionEngine - extends ShellExecutionEngine -{ - private static final long serialVersionUID = -6531803324180143746L; - - /** - * In addition to the keys accepted by the superclass, the configuration file for the SGE execution engine accepts - * the following key: - * <ul> - * <li> {@value #JOB_CATEGORY}: if set, the jobs will be launched in the SGE queue corresponding to this - * category.</li> - * </ul> - * @author Sébastien Bigaret - */ - @SuppressWarnings("serial") - public static final class SGEExecutionEngineConfiguration - extends ShellExecutionEngineConfiguration - { - /** The name of the configuration item for {@link #getJobCategory()} is {@value}. */ - public static final String JOB_CATEGORY = "job-category"; - - public SGEExecutionEngineConfiguration(PlatformDescription platform) - { - super(platform); - } - - /** - * Returns the DRMAA job category to use for all jobs launched by the SGE exec. engine. - * @return the job category as specified in the platform's descriptions. It may be null or empty. When it is - * non-null, the returned value is {@link String#trim() trimmed}. - */ - public String getJobCategory() - { - final String category = platform.getConfiguration(JOB_CATEGORY); - return category!=null ? category.trim() : null; - } - - @Override - public ExecutionEngine getEngine(WorkflowID workflowID, ExecutionID executionID) - { - return new SGEExecutionEngine(this, workflowID, executionID); - } - } - - public static class SGEExecutionEngineConfigurationFactory - implements ExecutionEngine.ExecutionEngineConfigurationFactory - { - /** Returns <code>"SGE"</code> */ - public String key() { return "SGE"; } - - /** - * Builds and returns a new SGE Platform - * @exception IllegalArgumentException - * if the supplied document's root element has no attribute <code>os</code> or if its value - * is not a valid argument for {@link SGEExecutionEngine#set_OS(String)}. - */ - public ExecutionEngineConfiguration build(PlatformDescription platform) - { - return new SGEExecutionEngineConfiguration(platform); - } - } - - /* ---- static methods for managing the only Session objet that can be created ---- */ - protected static ArrayList<String> runningJobsIDs = new ArrayList<String>(); - protected static Session session; - - /** The file into which the SGE job will dump the standard output */ - protected static final String stdout_filename = "praxis_capexbio_sge.stdout"; - /** The file into which the SGE job will dump the standard error */ - protected static final String stderr_filename = "praxis_capexbio_sge.stderr"; - - /** - * Runs a new job.<br> - * <b>IMPORTANT</b> any job created by this method must be correctly handled; this implies that the caller must - * make sure that it calls the two following methods: <li> - * <ul> {@link #getJobInfo(String)} </ul> - * <ul> {@link #forgetJob(String)} </ul> - * </li> - * @param scriptPath the path of the script that should be executed - * @param executionDir the path of the directory where the script should be executed - * @return the job's ID, or null if the job couldn't be started. - * @see #getJobInfo(String) - * @see #forgetJob(String) - */ - protected static synchronized String runJob(String scriptPath, String executionDir, String jobCategory) - { - String jobID; - boolean init_session = false; - if (session==null) - { - Log.log.fine("Opening a org.ggf.drmaa.Session"); - SessionFactory factory = SessionFactory.getFactory(); - session = factory.getSession(); - init_session = true; - } - else - { - Log.log.fine("A org.ggf.drmaa.Session is already opened, fine"); - } - try - { - if (init_session) - session.init(""); - JobTemplate jt = session.createJobTemplate(); - jt.setRemoteCommand(scriptPath); - jt.setArgs(Arrays.asList()); - jt.setWorkingDirectory(executionDir); - jt.setErrorPath(":"+stderr_filename); - jt.setOutputPath(":"+stdout_filename); - if (jobCategory!=null && !"".equals(jobCategory)) - jt.setJobCategory(jobCategory); - jobID = session.runJob(jt); - - //System.out.println("Your job has been submitted with id " + id); - session.deleteJobTemplate(jt); - } - catch (DrmaaException e) - { - Log.log.log(Level.SEVERE, "Exception raised", e); - /* ignore */ - return null; - } - runningJobsIDs.add(jobID); - return jobID; - } - - /** - * Returns the JobInfo object corresponding to the requested job, or null if the job is not terminated yet. - * @param jobID - * id of a job, as returned by {@link #runJob(String, String)} - * @return the JobInfo object, or null if the job isn't terminated yet - */ - protected static synchronized JobInfo getJobInfo(String jobID) - { - if (session==null) - throw new IllegalStateException("session is null: this should not happen!?!"); - JobInfo info = null; - try - { - info = session.wait(jobID, Session.TIMEOUT_NO_WAIT); - } - catch (ExitTimeoutException e) - { - /* not yet */ - } - catch (DrmaaException e) - { - Log.log.log(Level.SEVERE, "session.wait() failed", e); - } - /* Implementation note: - * we /may/ session.exit() if runningJobs.isEmpty()... but we don't really know if a JobInfo object can - * safely be accessed once the session has exited (JobInfo.methods throw DrmaaException). Since we couldn't - * find this information, we choose to wait until the execution has examined the JobInfo before forgetJob() - * is called and as a result, before the session is ended. - */ - return info; - } - - /** - * Callers should call this method when they are finished with the handling of a job, i.e. when the job is finished - * <b>AND</b> after they do not need anymore the JobInfo object returned by {@link #getJobInfo(String)}. - * If there is no more jobs waiting, the method takes care of ending the session. - * @param jobID the finished job's id, as returned by {@link #runJob(String, String)}. - */ - protected static synchronized void forgetJob(String jobID) - { - runningJobsIDs.remove(jobID); - if ( runningJobsIDs.isEmpty() ) - { - try - { - Log.log.fine("No more jobs running, closing our org.ggf.drmaa.Session"); - session.exit(); - } - catch (DrmaaException e) - { - // 1. NoActiveSessionException won't happen, - // 2. don't really know what to do on DrmsExitException... - Log.log.log(Level.SEVERE, "session.exit() failed", e); - } - session=null; - } - } - - /* ---- SGEExecutionEngine instance method ---- */ - /** - * - * @param configuration - * @param workflowID - * @param executionID - */ - protected SGEExecutionEngine(ExecutionEngineConfiguration configuration, WorkflowID workflowID, ExecutionID executionID) - { - super(configuration, workflowID, executionID); - } - - @Override - public SGEExecutionEngineConfiguration configuration() - { - return (SGEExecutionEngineConfiguration) configuration; - } - - @Override - public Result execute(File executionDirectory, File zippedInputFiles) throws InterruptedException, - InterruptedIOException - { - // this is only used to identify the current exec. within log messages - String log_exec_id = executionDirectory.toString(); - - // uncompress the script and the related files into the appropriate dir - if (zippedInputFiles!=null) // do not remove it, we need to restore it before every execution - Utile.unzip(zippedInputFiles, executionDirectory, false, false); - - List<String> sentFiles = new ArrayList<String>(Arrays.asList(executionDirectory.list())); - // sentFiles.remove("script.txt"); - - // time to execute the script - // TODO: treat IOException + InterruptedException individually AND return a useful status to the server!! - Log.log.info(()->"Executing workflow: " + log_exec_id); - - for (String prgID: scripts_for_prg.keySet()) - { - result.setExecStatus(prgID, ProgramResult.ProgramStatus.RUNNING); - getProgressMonitor().setRunningExecutionProgress(result); - - Result prgResult = new Result(result.workflowID(), null); - - /* Write the script */ - // dos2unix = Runtime.getRuntime().exec("dos2unix "+scriptFile); - File scriptFile = new File(executionDirectory, "script.txt"); - try - { - FileOutputStream out = new FileOutputStream(scriptFile); - out.write(scriptForID(prgID).getBytes()); - out.write("\n".getBytes()); // tcsh peculiarity: it does not execute the last line, if not terminated by EOL - out.flush(); - out.close(); - } - catch (IOException ioe) - { - ioe.printStackTrace(); - } - - /* Move input files */ - File[] createdFiles = prepareInputFiles(prgID, executionDirectory, prgResult); - // TODO check prg_result.status - - /* Submit the new task to SGE */ - prgResult.setResultForPrg(prgID, "start", ""+new java.util.Date()); - StringBuilder msgs = new StringBuilder(); - int exitStatus = sge_execute(scriptFile.getAbsolutePath(), executionDirectory.getAbsolutePath(), msgs); - prgResult.setResultForPrg(prgID, "end", ""+new java.util.Date()); - - Log.log.fine(()->"SGE process finished. Exit value for prg_id: "+prgID+": " + exitStatus); - - /* Put into result the relevant informations */ - - // IllegalStateException will be raised by stdout()/stderr() if the process couldn't be executed - //prg_result.addResultForPrg(prg_id, "stdout", logs.toString()); - //prg_result.addResultForPrg(prg_id, "stderr", errs.toString()); - prgResult.setResultForPrg(prgID, "script", scriptForID(prgID)); - prgResult.setResultForPrg(prgID, "exit_value", ""+exitStatus); - prgResult.setResultForPrg(prgID, "files_not_found", ""); - if (msgs.length()!=0) - prgResult.setResultForPrg(prgID, "sge_messages", msgs.toString()); - - // get back stdout and stderr - String str = Utile.getContentOfTextFile(new File(executionDirectory, stdout_filename)); - if ( str != null ) - prgResult.addInfoForPrg(prgID, "stdout", str); - str = Utile.getContentOfTextFile(new File(executionDirectory, stderr_filename)); - if ( str != null ) - prgResult.addInfoForPrg(prgID, "stderr", str); - - if (exitStatus == 0) - { - prgResult.setStatus(Result.Status.OK); - prgResult.setExecStatus(prgID, ProgramResult.ProgramStatus.OK); - } - else - { - prgResult.setStatus(Result.Status.ERROR); - prgResult.setExecStatus(prgID, ProgramResult.ProgramStatus.ERROR); - prgResult.setResultForPrg(prgID, "failure_reason", - "Voir les sorties stderr/stdout pour plus de détails sur l'échec\n"+ - "Refer to sections stderr & stdout for further details on the failure"); // i18n devrait être fait côté client, cf. note similaire dans Resource - } - - /* time to move the files */ - renameOutputFiles(prgID, executionDirectory, prgResult); - for (File createdFile: createdFiles) - Utile.deleteRecursively(createdFile); // may be a directory - - /* move all EXTRA files into the prgID/ directory (i.e. that were not identified as output files) */ - // TODO quick fix here, renameOutputFiles() should probably take care of this, e.g. being cleanup/handleOutputFiles() instead - // TODO voir aussi ShellExecEngine... et mettre tout ça ensemble plutôt que de répliquer le execute()... - for (File f: executionDirectory.listFiles()) - if (f.isFile() && ( ! "script.txt".equals(f.getName()) ) && (!sentFiles.contains(f.getName()))) - Utile.renameFile(f, new File(new File(executionDirectory, prgID), f.getName())); // TODO set WARNING state if it returns false? - result.mergeWith(prgResult); - getProgressMonitor().setRunningExecutionProgress(result); - prgResult.dumpContent(executionDirectory); - - if (zippedInputFiles!=null) // Restore the input files before the next program begins - Utile.unzip(zippedInputFiles, executionDirectory, false, false); - } - - - - Log.log.info(()->"End of execution: " + log_exec_id + "status: " + result.getStatus()); - if (zippedInputFiles!=null) - zippedInputFiles.delete(); - // TODO if false, this means that the execution has been stopped - // if(platform.executeWorkflow(executionID)) - { - File zippedResults = new File(executionDirectory, "resultat.zip"); - Log.log.info(()->"Sending results to the server: " + zippedResults); - - // add to 'sentFiles' any file you do NOT want to send back - sentFiles.add("script.txt"); - sentFiles.add(stdout_filename); - sentFiles.add(stderr_filename); - Utile.zipDirectory(executionDirectory, zippedResults, sentFiles); - result.setZipFile(zippedResults); - return result; - } - // else return null; - } - - protected int sge_execute(String scriptPath, String executionDir, StringBuilder messages) - { - String jobID = null; - try { - new File(scriptPath).setExecutable(true); - - jobID = runJob(scriptPath, executionDir, configuration().getJobCategory()); - if ( jobID==null ) - return Integer.MIN_VALUE; - - Log.log.log(Level.FINE, "Job has been submitted with id %s", jobID); - - JobInfo info = getJobInfo(jobID); - while (info == null) - { - try { Thread.sleep(100); } - catch (InterruptedException e) { /* ignore */ } - info = getJobInfo(jobID); - } - - if (info.wasAborted()) { - messages.append("Job ").append(info.getJobId()).append(" never ran"); - Log.log.fine(messages.toString()); - return Integer.MIN_VALUE; - } else if (info.hasExited()) { - messages.append("Job ").append(info.getJobId()).append(" finished regularly with exit status ").append(info.getExitStatus()); - Log.log.fine(messages.toString()); - return info.getExitStatus(); - } else if (info.hasSignaled()) { - messages.append("Job ").append(info.getJobId()).append(" finished due to signal ").append(info.getTerminatingSignal()); - Log.log.fine(messages.toString()); - return Integer.MIN_VALUE; - } else { - messages.append("Job ").append(info.getJobId()).append(" finished with unclear conditions"); - Log.log.fine(messages.toString()); - return Integer.MIN_VALUE; - } - - /* - * from http://gridengine.sunsource.net/howto/drmaa_java.html - */ - /* - System.out.println("Job Usage:"); - - Map<String, String> rmap = info.getResourceUsage(); - Iterator<String> i = rmap.keySet().iterator(); - - while (i.hasNext()) { - String name = i.next(); - String value = rmap.get(name); - - System.out.println(" " + name + "=" + value); - } - */ - } catch (DrmaaException e) { - messages.append("Unhandled error: ").append(e.getMessage()); - Log.log.log(Level.SEVERE, "Unhandled error", e.getMessage()); - return Integer.MIN_VALUE; - } - finally - { - if (jobID!=null) - forgetJob(jobID); - } - } - - /** - * Waits until the current process is cancelled - */ - @Override - public void cancel() - { - Utile.unimplemented(); - } - - /** - * Returns an execution directory located in the user's home directory: a script run by the Sun Grid Engine should - * be accessible from every node in the grid (we suppose that the user's home directory has this property) - * @return the execution directory - */ - @Override - public File getExecutionDirectory() - { - return Utile.createTempDirectory("tmp.exec", ".bsx", new File(Environment.getUserHome())); - } - -} diff --git a/src/eu/telecom_bretagne/praxis/server/execution/platform/WorkflowExecutionEngine.java b/src/eu/telecom_bretagne/praxis/server/execution/platform/WorkflowExecutionEngine.java index 333b8cdb23a67501d0191bf8f7781c0266495a2b..81f07d0d3b88f0736e4caf2960ec7f59d2900347 100644 --- a/src/eu/telecom_bretagne/praxis/server/execution/platform/WorkflowExecutionEngine.java +++ b/src/eu/telecom_bretagne/praxis/server/execution/platform/WorkflowExecutionEngine.java @@ -34,8 +34,7 @@ public class WorkflowExecutionEngine extends ExecutionEngine /** * - * @param platform - * @param xml the xml description of the platform. + * @param platform the description of the platform */ public WorkflowExecutionEngineConfiguration(PlatformDescription platform) {