From: Mathieu Baudier Date: Fri, 4 May 2018 14:13:13 +0000 (+0200) Subject: Introduce A2 provisioning and Eclipse 4 packaging. X-Git-Tag: argeo-commons-2.1.74~48 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=1091271b89f2d12e9898e01f6639c48831b1bc4b;p=lgpl%2Fargeo-commons.git Introduce A2 provisioning and Eclipse 4 packaging. --- diff --git a/dep/org.argeo.dep.cms.client/pom.xml b/dep/org.argeo.dep.cms.client/pom.xml index ec63ecae4..44ba00c55 100644 --- a/dep/org.argeo.dep.cms.client/pom.xml +++ b/dep/org.argeo.dep.cms.client/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.commons @@ -240,27 +242,44 @@ - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-argeo + prepare-source package - copy-dependencies + single - jar - ${project.build.directory}/lib-argeo - org.argeo.commons - true - jar - runtime - true + + a2-source + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo rpm-maven-plugin @@ -282,20 +301,20 @@ false - ${project.build.directory}/lib-argeo + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source **/*.jar - - /usr/share/osgi/org/argeo/commons/${project.artifactId}/${project.version} - root - root - false - - + + + + + + + argeo-cms-client-tp @@ -313,27 +332,44 @@ - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-tp + prepare-source-tp package - copy-dependencies + single - jar - ${project.build.directory}/lib-tp - org.argeo.commons - true - jar - runtime - true + + a2-source-tp + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo rpm-maven-plugin @@ -356,7 +392,7 @@ false - ${project.build.directory}/lib-tp + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source-tp **/*.jar diff --git a/dep/org.argeo.dep.cms.e4.rap/pom.xml b/dep/org.argeo.dep.cms.e4.rap/pom.xml index d3fa560c8..3cd7a20ef 100644 --- a/dep/org.argeo.dep.cms.e4.rap/pom.xml +++ b/dep/org.argeo.dep.cms.e4.rap/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.commons @@ -16,6 +18,7 @@ org.argeo.commons org.argeo.dep.cms.node 2.1.74-SNAPSHOT + pom org.argeo.commons @@ -271,30 +274,47 @@ - + rpmbuild + + + + + + + + + + + + + + + + + + + + + + + - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-argeo + prepare-source package - copy-dependencies + single - jar - ${project.build.directory}/lib-argeo - org.argeo.commons - true - org.argeo.dep.cms.node - jar - runtime - true + + a2-source + @@ -320,20 +340,20 @@ false - ${project.build.directory}/lib-argeo + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source **/*.jar - - /usr/share/osgi/org/argeo/commons/${project.artifactId}/${project.version} - root - root - false - - + + + + + + + argeo-cms-node @@ -350,24 +370,41 @@ rpmbuild-tp + + + + + + + + + + + + + + + + + + + + + + - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-tp + prepare-source-tp package - copy-dependencies + single - jar - ${project.build.directory}/lib-tp - org.argeo.commons - true - jar - runtime - true + + a2-source-tp + @@ -394,7 +431,7 @@ false - ${project.build.directory}/lib-tp + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source-tp **/*.jar @@ -413,5 +450,5 @@ - + \ No newline at end of file diff --git a/dep/org.argeo.dep.cms.node/pom.xml b/dep/org.argeo.dep.cms.node/pom.xml index e59761e58..8fd3a3a96 100644 --- a/dep/org.argeo.dep.cms.node/pom.xml +++ b/dep/org.argeo.dep.cms.node/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.commons @@ -16,6 +18,7 @@ org.argeo.commons org.argeo.dep.cms.client 2.1.74-SNAPSHOT + pom @@ -234,10 +237,6 @@ - - org.argeo.tp.equinox - org.eclipse.equinox.http.registry - org.argeo.tp.equinox org.eclipse.equinox.http.servlet @@ -248,10 +247,10 @@ - - - - + + + + org.argeo.tp.jetty org.eclipse.jetty.continuation @@ -264,10 +263,10 @@ org.argeo.tp.jetty org.eclipse.jetty.io - - - - + + + + org.argeo.tp.jetty org.eclipse.jetty.security @@ -280,10 +279,10 @@ org.argeo.tp.jetty org.eclipse.jetty.servlet - - - - + + + + org.argeo.tp.jetty org.eclipse.jetty.util @@ -297,28 +296,46 @@ - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-argeo + prepare-source package - copy-dependencies + single - jar - ${project.build.directory}/lib-argeo - org.argeo.commons - true - org.argeo.dep.cms.client - jar - runtime - true + + a2-source + + + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo rpm-maven-plugin @@ -340,20 +357,20 @@ false - ${project.build.directory}/lib-argeo + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source **/*.jar - - /usr/share/osgi/org/argeo/commons/${project.artifactId}/${project.version} - root - root - false - - + + + + + + + argeo-cms-client @@ -371,27 +388,44 @@ - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-tp + prepare-source-tp package - copy-dependencies + single - jar - ${project.build.directory}/lib-tp - org.argeo.commons - true - jar - runtime - true + + a2-source-tp + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo rpm-maven-plugin @@ -414,7 +448,7 @@ false - ${project.build.directory}/lib-tp + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source-tp **/*.jar diff --git a/dep/org.argeo.dep.cms.platform/pom.xml b/dep/org.argeo.dep.cms.platform/pom.xml index 5e4241203..cafe26ee1 100644 --- a/dep/org.argeo.dep.cms.platform/pom.xml +++ b/dep/org.argeo.dep.cms.platform/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.commons @@ -16,6 +18,7 @@ org.argeo.commons org.argeo.dep.cms.node 2.1.74-SNAPSHOT + pom @@ -95,6 +98,13 @@ org.springframework.web.servlet + + + org.argeo.tp.equinox + org.eclipse.equinox.http.registry + + org.argeo.tp.rap.platform @@ -268,28 +278,45 @@ - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-argeo + prepare-source package - copy-dependencies + single - jar - ${project.build.directory}/lib-argeo - org.argeo.commons - true - org.argeo.dep.cms.node - jar - runtime - true + + a2-source + + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo rpm-maven-plugin @@ -311,20 +338,20 @@ false - ${project.build.directory}/lib-argeo + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source **/*.jar - - /usr/share/osgi/org/argeo/commons/${project.artifactId}/${project.version} - root - root - false - - + + + + + + + argeo-cms-node @@ -342,27 +369,44 @@ - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-tp + prepare-source-tp package - copy-dependencies + single - jar - ${project.build.directory}/lib-tp - org.argeo.commons - true - jar - runtime - true + + a2-source-tp + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo rpm-maven-plugin @@ -385,7 +429,7 @@ false - ${project.build.directory}/lib-tp + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source-tp **/*.jar diff --git a/dep/org.argeo.dep.cms.sdk/pom.xml b/dep/org.argeo.dep.cms.sdk/pom.xml index 1aad9fe4d..1c7cfbb66 100644 --- a/dep/org.argeo.dep.cms.sdk/pom.xml +++ b/dep/org.argeo.dep.cms.sdk/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.commons @@ -15,6 +17,7 @@ org.argeo.commons org.argeo.dep.cms.platform 2.1.74-SNAPSHOT + pom @@ -101,28 +104,45 @@ - org.apache.maven.plugins - maven-dependency-plugin + maven-assembly-plugin - copy-tp + prepare-source-tp package - copy-dependencies + single - jar - ${project.build.directory}/lib-tp - org.argeo.commons - true - org.argeo.dep.cms.platform - jar - runtime - true + + a2-source-tp + + + + + + + + + + + + + + + + + + + + + + + + org.codehaus.mojo rpm-maven-plugin @@ -145,7 +165,7 @@ false - ${project.build.directory}/lib-tp + ${project.build.directory}/${project.artifactId}-${project.version}-a2-source-tp **/*.jar diff --git a/dep/pom.xml b/dep/pom.xml index a91dd5d67..458039456 100644 --- a/dep/pom.xml +++ b/dep/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.commons @@ -41,6 +43,19 @@ + + maven-assembly-plugin + + + org.argeo.commons + assembly-descriptors + 2.1.74-SNAPSHOT + + + + false + + diff --git a/dist/argeo-node/assembly/cms-e4-rap.xml b/dist/argeo-node/assembly/cms-e4-rap.xml new file mode 100644 index 000000000..20383ce2a --- /dev/null +++ b/dist/argeo-node/assembly/cms-e4-rap.xml @@ -0,0 +1,38 @@ + + dist + argeo-node + + dir + + + + base + + 0644 + + ** + + + offline.bat + + + + + + false + ${artifact.groupId}/${artifact.artifactId}-${artifact.version}.${artifact.extension} + share/osgi + + + true + true + + + org.argeo.commons:osgi-boot:zip:*:* + + + + \ No newline at end of file diff --git a/dist/argeo-node/base/bin/argeo-cms b/dist/argeo-node/base/bin/argeo-cms new file mode 100755 index 000000000..9819b7e77 --- /dev/null +++ b/dist/argeo-node/base/bin/argeo-cms @@ -0,0 +1,133 @@ +#!/bin/sh +APP=argeo + +JVM=java + +BIN_DIR=`dirname "$0"` +BASE_DIR=$BIN_DIR/.. + +# Directories and files +CONF_DIR=$BASE_DIR/etc/$APP +CONF_DIRS=$CONF_DIR/conf.d +#BASE_POLICY_ALL=/usr/share/$APP/all.policy +BASE_CONFIG_INI=$BASE_DIR/share/$APP/config.ini + +#EXEC_DIR=$BASE_DIR/var/lib/$APP +EXEC_DIR=. +DATA_DIR=$EXEC_DIR/data +CONF_RW=$EXEC_DIR/state +CONFIG_INI=$CONF_RW/config.ini + +OSGI_INSTALL_AREA=$BASE_DIR/share/osgi/boot +OSGI_FRAMEWORK=$OSGI_INSTALL_AREA/org.eclipse.osgi.jar + +# Overwrite variables +if [ -f $CONF_DIR/settings.sh ];then + . $CONF_DIR/settings.sh +fi + +RETVAL=0 + +start() { + mkdir -p $CONF_RW + mkdir -p $DATA_DIR + + # Merge config files + printf "## Equinox configuration - Generated by /usr/sbin/nodectl ##\n\n" > $CONFIG_INI + cat $BASE_CONFIG_INI >> $CONFIG_INI + printf "\n##\n## $CONF_DIR/$APP.ini\n##\n\n" >> $CONFIG_INI + cat $CONF_DIR/$APP.ini >> $CONFIG_INI + for file in `ls -v $CONF_DIRS/*.ini`; do + printf "\n##\n## $file\n##\n\n" >> $CONFIG_INI + cat $file >> $CONFIG_INI + done; + + cd $EXEC_DIR + $JVM \ + -Dlog4j.configuration="file:$CONF_DIR/log4j.properties" \ + $JAVA_OPTS -jar $OSGI_FRAMEWORK \ + -configuration "$CONF_RW" \ + -data "$DATA_DIR" +} + +reload() { + echo Not yet implemented +} + +stop() { + if [ -f $PID_FILE ];then + PID=`cat $PID_FILE` + kill -0 $PID &> /dev/null + PID_EXISTS=$? + if [ $PID_EXISTS -ne 0 ]; then + echo Dead $APP process with pid $PID, removing $PID_FILE + rm -f $PID_FILE + RETVAL=1 + return $RETVAL + fi + else + echo $APP is not running + RETVAL=1 + return $RETVAL + fi + + # notifies application by removing the shutdown file +# rm -f $SHUTDOWN_FILE + kill $PID + + # wait 10 min for application to shutdown, then kill it + TIMEOUT=$((10*60)) + BEGIN=$(date +%s) + while kill -0 $PID &> /dev/null + do + sleep 1 + NOW=$(date +%s) + DURATION=$(($NOW-$BEGIN)) + if [ $DURATION -gt $TIMEOUT ]; then + kill -9 $PID + echo Forcibly killed $APP with pid $PID + RETVAL=1 + fi + done + + # remove pid file + rm -f $PID_FILE + return $RETVAL +} + +status() { + if [ -f $PID_FILE ];then + PID=`cat $PID_FILE` + else + echo $APP is not running + return $RETVAL + fi + kill -0 $PID &> /dev/null + PID_EXISTS=$? + if [ $PID_EXISTS -eq 0 ]; then + echo $APP is running with pid $PID ... + else + echo No $APP process with pid $PID, removing $PID_FILE + rm -f $PID_FILE + fi + return $RETVAL +} + +# main +case "$1" in + start) + start + ;; + reload) + reload + ;; + stop) + stop + ;; + status) + status + ;; + *) + echo $"Usage: $0 {start|stop|status}" + exit 1 +esac \ No newline at end of file diff --git a/dist/argeo-node/base/etc/argeo/argeo.ini b/dist/argeo-node/base/etc/argeo/argeo.ini new file mode 100644 index 000000000..527fbf831 --- /dev/null +++ b/dist/argeo-node/base/etc/argeo/argeo.ini @@ -0,0 +1,5 @@ +## HTTP server +org.osgi.service.http.port=8080 + +## System management +osgi.console=2323 diff --git a/dist/argeo-node/base/etc/argeo/log4j.properties b/dist/argeo-node/base/etc/argeo/log4j.properties new file mode 100644 index 000000000..45acf1f67 --- /dev/null +++ b/dist/argeo-node/base/etc/argeo/log4j.properties @@ -0,0 +1,15 @@ +log4j.rootLogger=WARN, console + +log4j.logger.org.argeo=DEBUG + +## Appenders +log4j.appender.console=org.apache.log4j.ConsoleAppender +log4j.appender.console.layout=org.apache.log4j.PatternLayout +log4j.appender.console.layout.ConversionPattern=%-5p %m%n + +log4j.appender.file=org.apache.log4j.DailyRollingFileAppender +log4j.appender.file.File=/var/log/node/node.csv +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=%d{ISO8601};"%m";%c;%p%n +log4j.appender.file.bufferedIO=true +log4j.appender.file.immediateFlush=false diff --git a/dist/argeo-node/base/share/argeo/all.policy b/dist/argeo-node/base/share/argeo/all.policy new file mode 100644 index 000000000..facb61327 --- /dev/null +++ b/dist/argeo-node/base/share/argeo/all.policy @@ -0,0 +1,3 @@ +grant { + permission java.security.AllPermission; +}; \ No newline at end of file diff --git a/dist/argeo-node/base/share/argeo/cms.js b/dist/argeo-node/base/share/argeo/cms.js new file mode 100755 index 000000000..446747f55 --- /dev/null +++ b/dist/argeo-node/base/share/argeo/cms.js @@ -0,0 +1,46 @@ +var System = Java.type("java.lang.System"); +var OsgiBuilder = Java.type("org.argeo.osgi.boot.OsgiBuilder"); + +var osgi = new OsgiBuilder(); +// default bundles +osgi.start(2, "org.eclipse.equinox.http.servlet"); +osgi.start(2, "org.eclipse.equinox.http.jetty"); +osgi.start(2, "org.eclipse.equinox.metatype"); +osgi.start(2, "org.eclipse.equinox.cm"); +osgi.start(2, "org.eclipse.rap.rwt.osgi"); +osgi.start(3, "org.argeo.cms"); +osgi.start(4, "org.eclipse.gemini.blueprint.extender"); +osgi.start(4, "org.eclipse.equinox.http.registry"); +// specific properties +osgi.conf("org.eclipse.rap.workbenchAutostart", "false"); +osgi.conf("org.eclipse.equinox.http.jetty.autostart", "false"); +osgi.conf("org.osgi.framework.bootdelegation", "com.sun.jndi.ldap," + + "com.sun.jndi.ldap.sasl," + "com.sun.security.jgss," + + "com.sun.jndi.dns," + "com.sun.nio.file," + "com.sun.nio.sctp"); + +var homeUri = java.nio.file.Paths + .get(java.lang.System.getProperty("user.home")).toUri().toString(); +if (typeof app !== 'undefined') { + if (typeof appHome == 'undefined') { + var appHome = homeUri + "/.a2/var/lib/" + app; + } + if (typeof appConf == 'undefined') { + var appConf = homeUri + "/.a2/etc/" + app; + } + if (typeof policyFile == 'undefined') { + var policyFile = "node.policy"; + } + osgi.conf("osgi.configuration.area", appHome + "/state"); + osgi.conf("osgi.instance.area", appHome + "/data"); + System.setProperty("java.security.manager", ""); + System.setProperty("java.security.policy", appConf + "/" + policyFile); + System.setProperty("log4j.configuration", appConf + "/log4j.properties"); +} + +function openWorkbench() { + osgi.spring("org.argeo.cms.ui.workbench.rap"); + var appUrl = "http://127.0.0.1:" + osgi.httpPort + "/ui/node"; + $EXEC("chrome --app=" + appUrl); + // shutdown when the window is closed + osgi.shutdown(); +} \ No newline at end of file diff --git a/dist/argeo-node/base/share/argeo/config.ini b/dist/argeo-node/base/share/argeo/config.ini new file mode 100644 index 000000000..88ae8ee3c --- /dev/null +++ b/dist/argeo-node/base/share/argeo/config.ini @@ -0,0 +1,36 @@ +# Only Argeo OSGi Boot is explicitly started +osgi.bundles=org.argeo.osgi.boot@start + +# Required standard bundles to start +argeo.osgi.start.2.node=\ +org.eclipse.equinox.http.servlet,\ +org.eclipse.equinox.http.jetty,\ +org.eclipse.equinox.metatype,\ +org.eclipse.equinox.cm,\ +org.eclipse.rap.rwt.osgi + +# Required CMS bundles to start +argeo.osgi.start.3.node=\ +org.argeo.cms + +# Extension managers +argeo.osgi.start.4.node=\ +org.argeo.cms.e4.rap + +# Packages provided by the OpenJDK JVM +org.osgi.framework.bootdelegation=com.sun.jndi.ldap,\ +com.sun.jndi.ldap.sasl,\ +com.sun.security.jgss,\ +com.sun.jndi.dns,\ +com.sun.nio.file,\ +com.sun.nio.sctp + +# Security manager +#java.security.manager= +#java.security.policy=file:/usr/share/node/all.policy + +# Required properties +eclipse.ignoreApp=true +osgi.noShutdown=true +org.eclipse.equinox.http.jetty.autostart=false +#org.eclipse.rap.workbenchAutostart=false diff --git a/dist/argeo-node/pom.xml b/dist/argeo-node/pom.xml index b856d333f..4b0f4a810 100644 --- a/dist/argeo-node/pom.xml +++ b/dist/argeo-node/pom.xml @@ -1,4 +1,6 @@ - + 4.0.0 org.argeo.commons @@ -10,6 +12,46 @@ pom Argeo Node + + dist + + + org.argeo.commons + org.argeo.dep.cms.e4.rap + 2.1.74-SNAPSHOT + + + org.argeo.commons + osgi-boot + zip + 2.1.74-SNAPSHOT + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + argeo-node-${project.version} + false + + assembly/cms-e4-rap.xml + + + + + assembly-base + package + + single + + + + + + + rpmbuild diff --git a/dist/argeo-node/rpm/etc/node/node.ini b/dist/argeo-node/rpm/etc/node/node.ini index e1c3d8fa2..37cf1b4cb 100644 --- a/dist/argeo-node/rpm/etc/node/node.ini +++ b/dist/argeo-node/rpm/etc/node/node.ini @@ -1,8 +1,9 @@ ## Provisioning -argeo.osgi.bundles=\ -/etc/node/modules;in=*/*,\ -/usr/local/share/osgi;in=**/*.jar,\ -/usr/share/osgi;in=**/*.jar;ex=boot/*.jar +#osgi.clean=true +#argeo.osgi.bundles=\ +#/etc/node/modules;in=*/*,\ +#/usr/local/share/osgi;in=**/*.jar,\ +#/usr/share/osgi;in=**/*.jar;ex=boot/*.jar ## HTTP server org.osgi.service.http.port=8080 diff --git a/dist/argeo-node/rpm/usr/share/node/config.ini b/dist/argeo-node/rpm/usr/share/node/config.ini index dc42a45b1..ae7a66494 100644 --- a/dist/argeo-node/rpm/usr/share/node/config.ini +++ b/dist/argeo-node/rpm/usr/share/node/config.ini @@ -7,6 +7,7 @@ org.eclipse.equinox.http.servlet,\ org.eclipse.equinox.http.jetty,\ org.eclipse.equinox.metatype,\ org.eclipse.equinox.cm,\ +org.eclipse.equinox.ds,\ org.eclipse.rap.rwt.osgi # Required CMS bundles to start @@ -16,7 +17,7 @@ org.argeo.cms # Extension managers argeo.osgi.start.4.node=\ org.eclipse.gemini.blueprint.extender,\ -org.eclipse.equinox.http.registry +org.argeo.cms.e4.rap # Packages provided by the OpenJDK JVM org.osgi.framework.bootdelegation=com.sun.jndi.ldap,\ diff --git a/dist/osgi-boot/assembly/osgi-boot.xml b/dist/osgi-boot/assembly/osgi-boot.xml new file mode 100644 index 000000000..adad22b8a --- /dev/null +++ b/dist/osgi-boot/assembly/osgi-boot.xml @@ -0,0 +1,34 @@ + + dist + + + zip + + + + base/bin + bin + 0755 + + * + + + offline.sh + + + + + + false + ${artifact.artifactId}.${artifact.extension} + share/osgi/boot + + org.argeo.tp.equinox:org.eclipse.osgi + org.argeo.commons:org.argeo.osgi.boot + + + + \ No newline at end of file diff --git a/dist/osgi-boot/base/bin/a2jjs b/dist/osgi-boot/base/bin/a2jjs new file mode 100755 index 000000000..62762a858 --- /dev/null +++ b/dist/osgi-boot/base/bin/a2jjs @@ -0,0 +1,13 @@ +#!/bin/sh + +export A2_HOME=$HOME/.a2 +if [ -d "$A2_HOME/share/osgi/boot" ]; then + PREFIX=$A2_HOME +else + PREFIX=/usr +fi + +EQUINOX=$PREFIX/share/osgi/boot/org.eclipse.osgi.jar +OSGI_BOOT=$PREFIX/share/osgi/boot/org.argeo.osgi.boot.jar + +/usr/bin/jjs -cp "$EQUINOX:$OSGI_BOOT" $* diff --git a/dist/osgi-boot/pom.xml b/dist/osgi-boot/pom.xml index 8b4348fc5..fa62c884f 100644 --- a/dist/osgi-boot/pom.xml +++ b/dist/osgi-boot/pom.xml @@ -27,6 +27,33 @@ + + dist + + + + org.apache.maven.plugins + maven-assembly-plugin + + osgi-boot-${project.version} + false + + assembly/osgi-boot.xml + + + + + assembly-base + package + + single + + + + + + + rpmbuild diff --git a/maven/assembly-descriptors/.gitignore b/maven/assembly-descriptors/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/maven/assembly-descriptors/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/maven/assembly-descriptors/META-INF/.gitignore b/maven/assembly-descriptors/META-INF/.gitignore new file mode 100644 index 000000000..4854a41b9 --- /dev/null +++ b/maven/assembly-descriptors/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/maven/assembly-descriptors/assemblies/a2-source-tp.xml b/maven/assembly-descriptors/assemblies/a2-source-tp.xml new file mode 100644 index 000000000..99423f7f3 --- /dev/null +++ b/maven/assembly-descriptors/assemblies/a2-source-tp.xml @@ -0,0 +1,22 @@ + + a2-source-tp + + + dir + + + + false + ${artifact.groupId}/${artifact.artifactId}-${artifact.version}.${artifact.extension} + + false + runtime + + org.argeo.tp.*:* + + + + \ No newline at end of file diff --git a/maven/assembly-descriptors/assemblies/a2-source.xml b/maven/assembly-descriptors/assemblies/a2-source.xml new file mode 100644 index 000000000..9019917ff --- /dev/null +++ b/maven/assembly-descriptors/assemblies/a2-source.xml @@ -0,0 +1,22 @@ + + a2-source + + + dir + + + + false + ${artifact.groupId}/${artifact.artifactId}-${artifact.version}.${artifact.extension} + + false + runtime + + org.argeo.tp.*:* + + + + \ No newline at end of file diff --git a/maven/assembly-descriptors/bnd.bnd b/maven/assembly-descriptors/bnd.bnd new file mode 100644 index 000000000..e69de29bb diff --git a/maven/assembly-descriptors/pom.xml b/maven/assembly-descriptors/pom.xml new file mode 100644 index 000000000..81c65cd11 --- /dev/null +++ b/maven/assembly-descriptors/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + org.argeo.commons + 2.1.74-SNAPSHOT + maven + .. + + assembly-descriptors + Assembly Descriptors + \ No newline at end of file diff --git a/maven/pom.xml b/maven/pom.xml new file mode 100644 index 000000000..94c3de3b9 --- /dev/null +++ b/maven/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + org.argeo.commons + argeo-commons + 2.1.74-SNAPSHOT + .. + + maven + Maven Helpers and Templates + pom + + assembly-descriptors + + \ No newline at end of file diff --git a/maven/target/antrun/build-main.xml b/maven/target/antrun/build-main.xml new file mode 100644 index 000000000..ac929d682 --- /dev/null +++ b/maven/target/antrun/build-main.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/Activator.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/Activator.java index cd9f3583d..9e22b7bd6 100644 --- a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/Activator.java +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/Activator.java @@ -19,11 +19,12 @@ import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; /** - * An OSGi configurator. See http: + * An OSGi configurator. See + * http: * //wiki.eclipse.org/Configurator */ public class Activator implements BundleActivator { + private Long checkpoint = null; public void start(final BundleContext bundleContext) throws Exception { // admin thread @@ -32,7 +33,13 @@ public class Activator implements BundleActivator { // bootstrap OsgiBoot osgiBoot = new OsgiBoot(bundleContext); - osgiBoot.bootstrap(); + if (checkpoint == null) { + osgiBoot.bootstrap(); + checkpoint = System.currentTimeMillis(); + } else { + osgiBoot.update(); + checkpoint = System.currentTimeMillis(); + } } public void stop(BundleContext context) throws Exception { diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java index effdcf3ba..8ca9be77b 100644 --- a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java @@ -31,6 +31,7 @@ import java.util.SortedMap; import java.util.StringTokenizer; import java.util.TreeMap; +import org.argeo.osgi.boot.a2.ProvisioningManager; import org.argeo.osgi.boot.internal.springutil.AntPathMatcher; import org.argeo.osgi.boot.internal.springutil.PathMatcher; import org.argeo.osgi.boot.internal.springutil.SystemPropertyUtils; @@ -50,6 +51,8 @@ import org.osgi.framework.wiring.FrameworkWiring; */ public class OsgiBoot implements OsgiBootConstants { public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start"; + public final static String PROP_ARGEO_OSGI_SOURCES = "argeo.osgi.sources"; + public final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles"; public final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl"; public final static String PROP_ARGEO_OSGI_LOCAL_CACHE = "argeo.osgi.localCache"; @@ -90,6 +93,8 @@ public class OsgiBoot implements OsgiBootConstants { private final BundleContext bundleContext; private final String localCache; + private final ProvisioningManager provisioningManager; + /* * INITIALIZATION */ @@ -98,6 +103,16 @@ public class OsgiBoot implements OsgiBootConstants { this.bundleContext = bundleContext; String homeUri = Paths.get(System.getProperty("user.home")).toUri().toString(); localCache = getProperty(PROP_ARGEO_OSGI_LOCAL_CACHE, homeUri + ".m2/repository/"); + + provisioningManager = new ProvisioningManager(bundleContext); + String sources = getProperty(PROP_ARGEO_OSGI_SOURCES); + if (sources == null) { + provisioningManager.registerDefaultSource(); + } else { + for (String source : sources.split(",")) { + provisioningManager.registerSource(source); + } + } } /* @@ -113,6 +128,7 @@ public class OsgiBoot implements OsgiBootConstants { .info("OSGi bootstrap starting" + (osgiInstancePath != null ? " (" + osgiInstancePath + ")" : "")); installUrls(getBundlesUrls()); installUrls(getDistributionUrls()); + provisioningManager.install(null); startBundles(); long duration = System.currentTimeMillis() - begin; OsgiBootUtils.info("OSGi bootstrap completed in " + Math.round(((double) duration) / 1000) + "s (" @@ -143,6 +159,9 @@ public class OsgiBoot implements OsgiBootConstants { System.out.println(); } + public void update() { + provisioningManager.update(); + } /* * INSTALLATION */ diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Branch.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Branch.java new file mode 100644 index 000000000..ae715ecea --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Branch.java @@ -0,0 +1,80 @@ +package org.argeo.osgi.boot.a2; + +import java.util.Collections; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.argeo.osgi.boot.OsgiBootUtils; +import org.osgi.framework.Version; + +class A2Branch implements Comparable { + private final A2Component component; + private final String id; + + final SortedMap modules = Collections.synchronizedSortedMap(new TreeMap<>()); + + A2Branch(A2Component component, String id) { + this.component = component; + this.id = id; + component.branches.put(id, this); + } + + A2Module getOrAddModule(Version version, Object locator) { + if (modules.containsKey(version)) { + A2Module res = modules.get(version); + if (OsgiBootUtils.isDebug() && !res.getLocator().equals(locator)) { + OsgiBootUtils.debug("Inconsistent locator " + locator + " (registered: " + res.getLocator() + ")"); + } + return res; + } else + return new A2Module(this, version, locator); + } + + A2Module last() { + return modules.get(modules.lastKey()); + } + + A2Module first() { + return modules.get(modules.firstKey()); + } + + A2Component getComponent() { + return component; + } + + String getId() { + return id; + } + + @Override + public int compareTo(A2Branch o) { + return id.compareTo(id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof A2Branch) { + A2Branch o = (A2Branch) obj; + return component.equals(o.component) && id.equals(o.id); + } else + return false; + } + + @Override + public String toString() { + return getCoordinates(); + } + + public String getCoordinates() { + return component + ":" + id; + } + + static String versionToBranchId(Version version) { + return version.getMajor() + "." + version.getMinor(); + } +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Component.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Component.java new file mode 100644 index 000000000..5d8dc87cf --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Component.java @@ -0,0 +1,95 @@ +package org.argeo.osgi.boot.a2; + +import java.util.Collections; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.osgi.framework.Version; + +class A2Component implements Comparable { + private final A2Contribution contribution; + private final String id; + + final SortedMap branches = Collections.synchronizedSortedMap(new TreeMap<>()); + + public A2Component(A2Contribution contribution, String id) { + this.contribution = contribution; + this.id = id; + contribution.components.put(id, this); + } + + A2Branch getOrAddBranch(String branchId) { + if (branches.containsKey(branchId)) + return branches.get(branchId); + else + return new A2Branch(this, branchId); + } + + A2Module getOrAddModule(Version version, Object locator) { + A2Branch branch = getOrAddBranch(A2Branch.versionToBranchId(version)); + A2Module module = branch.getOrAddModule(version, locator); + return module; + } + + A2Branch last() { + return branches.get(branches.lastKey()); + } + + A2Contribution getContribution() { + return contribution; + } + + String getId() { + return id; + } + + @Override + public int compareTo(A2Component o) { + return id.compareTo(o.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof A2Component) { + A2Component o = (A2Component) obj; + return contribution.equals(o.contribution) && id.equals(o.id); + } else + return false; + } + + @Override + public String toString() { + return contribution.getId() + ":" + id; + } + + void asTree(String prefix, StringBuffer buf) { + if (prefix == null) + prefix = ""; + A2Branch lastBranch = last(); + SortedMap displayMap = new TreeMap<>(Collections.reverseOrder()); + displayMap.putAll(branches); + for (String branchId : displayMap.keySet()) { + A2Branch branch = displayMap.get(branchId); + if (!lastBranch.equals(branch)) { + buf.append('\n'); + buf.append(prefix); + } else { + buf.append(" -"); + } + buf.append(prefix); + buf.append(branchId); + A2Module first = branch.first(); + A2Module last = branch.last(); + buf.append(" (").append(last.getVersion()); + if (!first.equals(last)) + buf.append(" ... ").append(first.getVersion()); + buf.append(')'); + } + } + +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Contribution.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Contribution.java new file mode 100644 index 000000000..9e6ca3084 --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Contribution.java @@ -0,0 +1,74 @@ +package org.argeo.osgi.boot.a2; + +import java.util.Collections; +import java.util.Map; +import java.util.TreeMap; + +class A2Contribution implements Comparable { + final static String BOOT = "boot"; + final static String RUNTIME = "runtime"; + + private final ProvisioningSource source; + private final String id; + + final Map components = Collections.synchronizedSortedMap(new TreeMap<>()); + + public A2Contribution(ProvisioningSource context, String id) { + this.source = context; + this.id = id; + if (context != null) + context.contributions.put(id, this); + } + + A2Component getOrAddComponent(String componentId) { + if (components.containsKey(componentId)) + return components.get(componentId); + else + return new A2Component(this, componentId); + } + + public ProvisioningSource getSource() { + return source; + } + + public String getId() { + return id; + } + + @Override + public int compareTo(A2Contribution o) { + return id.compareTo(o.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof A2Contribution) { + A2Contribution o = (A2Contribution) obj; + return id.equals(o.id); + } else + return false; + } + + @Override + public String toString() { + return id; + } + + void asTree(String prefix, StringBuffer buf) { + if (prefix == null) + prefix = ""; + for (String componentId : components.keySet()) { + buf.append(prefix); + buf.append(componentId); + A2Component component = components.get(componentId); + component.asTree(prefix, buf); + buf.append('\n'); + } + } + +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Module.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Module.java new file mode 100644 index 000000000..1108cd72b --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/A2Module.java @@ -0,0 +1,58 @@ +package org.argeo.osgi.boot.a2; + +import org.osgi.framework.Version; + +class A2Module implements Comparable { + private final A2Branch branch; + private final Version version; + private final Object locator; + + public A2Module(A2Branch branch, Version version, Object locator) { + this.branch = branch; + this.version = version; + this.locator = locator; + branch.modules.put(version, this); + } + + A2Branch getBranch() { + return branch; + } + + Version getVersion() { + return version; + } + + Object getLocator() { + return locator; + } + + @Override + public int compareTo(A2Module o) { + return version.compareTo(o.version); + } + + @Override + public int hashCode() { + return version.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof A2Module) { + A2Module o = (A2Module) obj; + return branch.equals(o.branch) && version.equals(o.version); + } else + return false; + } + + @Override + public String toString() { + return getCoordinates(); + } + + public String getCoordinates() { + return branch.getComponent() + ":" + version; + } + + +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsA2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsA2Source.java new file mode 100644 index 000000000..b9f9193ff --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsA2Source.java @@ -0,0 +1,82 @@ +package org.argeo.osgi.boot.a2; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.argeo.osgi.boot.OsgiBootUtils; +import org.osgi.framework.Version; + +public class FsA2Source extends ProvisioningSource { + private final Path base; + + public FsA2Source(Path base) { + super(); + this.base = base; + } + + void load() throws IOException { + DirectoryStream contributionPaths = Files.newDirectoryStream(base); + SortedSet contributions = new TreeSet<>(); + contributions: for (Path contributionPath : contributionPaths) { + if (Files.isDirectory(contributionPath)) { + String contributionId = contributionPath.getFileName().toString(); + if (A2Contribution.BOOT.equals(contributionId))// skip boot + continue contributions; + A2Contribution contribution = new A2Contribution(this, contributionId); + contributions.add(contribution); + } + } + + for (A2Contribution contribution : contributions) { + DirectoryStream modulePaths = Files.newDirectoryStream(base.resolve(contribution.getId())); + modules: for (Path modulePath : modulePaths) { + if (!Files.isDirectory(modulePath)) { + // OsgiBootUtils.debug("Registering " + modulePath); + String moduleFileName = modulePath.getFileName().toString(); + int lastDot = moduleFileName.lastIndexOf('.'); + String ext = moduleFileName.substring(lastDot + 1); + if (!"jar".equals(ext)) + continue modules; + String moduleName = moduleFileName.substring(0, lastDot); + int firstDash = moduleName.indexOf('-'); + String versionStr = moduleName.substring(firstDash + 1); + String componentName = moduleName.substring(0, firstDash); + // if(versionStr.endsWith("-SNAPSHOT")) { + // versionStr = readVersionFromModule(modulePath); + // } + Version version; + try { + version = new Version(versionStr); + } catch (Exception e) { + versionStr = readVersionFromModule(modulePath); + version = new Version(versionStr); + // OsgiBootUtils.debug("Ignore " + modulePath + " (" + e.getMessage() + ")"); + // continue modules; + } + A2Component component = contribution.getOrAddComponent(componentName); + A2Module module = component.getOrAddModule(version, modulePath); + if (OsgiBootUtils.isDebug()) + OsgiBootUtils.debug("Registered " + module); + } + } + } + + } + + public static void main(String[] args) { + try { + FsA2Source context = new FsA2Source(Paths.get( + "/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.74-SNAPSHOT/argeo-node/share/osgi")); + context.load(); + context.asTree(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsM2Source.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsM2Source.java new file mode 100644 index 000000000..ecf8771a6 --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/FsM2Source.java @@ -0,0 +1,65 @@ +package org.argeo.osgi.boot.a2; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +import org.argeo.osgi.boot.OsgiBootUtils; +import org.osgi.framework.Version; + +public class FsM2Source extends ProvisioningSource { + private final Path base; + + public FsM2Source(Path base) { + super(); + this.base = base; + } + + void load() throws IOException { + Files.walkFileTree(base, new ArtifactFileVisitor()); + } + + class ArtifactFileVisitor extends SimpleFileVisitor { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + // OsgiBootUtils.debug("Processing " + file); + if (file.toString().endsWith(".jar")) { + Version version; + try { + version = new Version(readVersionFromModule(file)); + } catch (Exception e) { + // ignore non OSGi + return FileVisitResult.CONTINUE; + } + String moduleName = readSymbolicNameFromModule(file); + Path groupPath = file.getParent().getParent().getParent(); + Path relGroupPath = base.relativize(groupPath); + String contributionName = relGroupPath.toString().replace(File.separatorChar, '.'); + A2Contribution contribution = getOrAddContribution(contributionName); + A2Component component = contribution.getOrAddComponent(moduleName); + A2Module module = component.getOrAddModule(version, file); + if (OsgiBootUtils.isDebug()) + OsgiBootUtils.debug("Registered " + module); + } + return super.visitFile(file, attrs); + } + + } + + public static void main(String[] args) { + try { + FsM2Source context = new FsM2Source(Paths.get("/home/mbaudier/.m2/repository")); + context.load(); + context.asTree(); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/OsgiContext.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/OsgiContext.java new file mode 100644 index 000000000..a3ddf55f3 --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/OsgiContext.java @@ -0,0 +1,38 @@ +package org.argeo.osgi.boot.a2; + +import org.argeo.osgi.boot.OsgiBootUtils; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.Version; + +class OsgiContext extends ProvisioningSource { + private final BundleContext bc; + + public OsgiContext(BundleContext bc) { + super(); + this.bc = bc; + } + + public OsgiContext() { + Bundle bundle = FrameworkUtil.getBundle(OsgiContext.class); + if (bundle == null) + throw new IllegalArgumentException( + "OSGi Boot bundle must be started or a bundle context must be specified"); + this.bc = bundle.getBundleContext(); + } + + void load() { + A2Contribution runtimeContribution = new A2Contribution(this, A2Contribution.RUNTIME); + for (Bundle bundle : bc.getBundles()) { + // OsgiBootUtils.debug(bundle.getDataFile("/")); + String componentId = bundle.getSymbolicName(); + Version version = bundle.getVersion(); + A2Component component = runtimeContribution.getOrAddComponent(componentId); + A2Module module = component.getOrAddModule(version, bundle); + if (OsgiBootUtils.isDebug()) + OsgiBootUtils.debug("Registered " + module + " (location id: " + bundle.getLocation() + ")"); + } + + } +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningManager.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningManager.java new file mode 100644 index 000000000..e7a297077 --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningManager.java @@ -0,0 +1,201 @@ +package org.argeo.osgi.boot.a2; + +import java.io.InputStream; +import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.argeo.osgi.boot.OsgiBootException; +import org.argeo.osgi.boot.OsgiBootUtils; +import org.eclipse.osgi.launch.EquinoxFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.Version; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.launch.FrameworkFactory; +import org.osgi.framework.wiring.FrameworkWiring; + +public class ProvisioningManager { + BundleContext bc; + OsgiContext osgiContext; + List sources = Collections.synchronizedList(new ArrayList<>()); + + public ProvisioningManager(BundleContext bc) { + this.bc = bc; + osgiContext = new OsgiContext(bc); + osgiContext.load(); + } + + void addSource(ProvisioningSource context) { + sources.add(context); + } + + void installWholeSource(ProvisioningSource context) { + Set updatedBundles = new HashSet<>(); + for (A2Contribution contribution : context.contributions.values()) { + for (A2Component component : contribution.components.values()) { + A2Module module = component.last().last(); + Bundle bundle = installOrUpdate(module); + if (bundle != null) + updatedBundles.add(bundle); + } + } + FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class); + frameworkWiring.refreshBundles(updatedBundles); + } + + public void registerSource(String uri) { + try { + URI u = new URI(uri); + if ("a2".equals(u.getScheme())) { + if (u.getHost() == null || "".equals(u.getHost())) { + Path base = Paths.get(u.getPath()); + FsA2Source source = new FsA2Source(base); + source.load(); + addSource(source); + } + } + } catch (Exception e) { + throw new OsgiBootException("Cannot add source " + uri, e); + } + } + + public boolean registerDefaultSource() { + String frameworkLocation = bc.getProperty("osgi.framework"); + try { + URI frameworkLocationUri = new URI(frameworkLocation); + if ("file".equals(frameworkLocationUri.getScheme())) { + Path frameworkPath = Paths.get(frameworkLocationUri); + if (frameworkPath.getParent().getFileName().toString().equals(A2Contribution.BOOT)) { + Path base = frameworkPath.getParent().getParent(); + URI baseUri = new URI("a2", null, null, 0, base.toString(), null, null); + registerSource(baseUri.toString()); + OsgiBootUtils.info("Registered " + baseUri + " as default source"); + return true; + } + } + } catch (Exception e) { + OsgiBootUtils.error("Cannot register default source based on framework location " + frameworkLocation, e); + } + return false; + } + + public void install(String spec) { + if (spec == null) { + for (ProvisioningSource source : sources) { + installWholeSource(source); + } + } + } + + /** @return the new/updated bundle, or null if nothign was done. */ + Bundle installOrUpdate(A2Module module) { + try { + ProvisioningSource moduleSource = module.getBranch().getComponent().getContribution().getSource(); + Version moduleVersion = module.getVersion(); + A2Branch osgiBranch = osgiContext.findBranch(module.getBranch().getComponent().getId(), moduleVersion); + if (osgiBranch == null) { + Bundle bundle = bc.installBundle(module.getBranch().getCoordinates(), + moduleSource.newInputStream(module.getLocator())); + if (OsgiBootUtils.isDebug()) + OsgiBootUtils.debug("Installed bundle " + bundle.getLocation() + " with version " + moduleVersion); + return bundle; + } else { + A2Module lastOsgiModule = osgiBranch.last(); + int compare = moduleVersion.compareTo(lastOsgiModule.getVersion()); + if (compare > 0) {// update + Bundle bundle = (Bundle) lastOsgiModule.getLocator(); + bundle.update(moduleSource.newInputStream(module.getLocator())); + OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion); + return bundle; + } + } + } catch (Exception e) { + OsgiBootUtils.error("Could not install module " + module, e); + } + return null; + } + + public Collection update() { + boolean fragmentsUpdated = false; + Set updatedBundles = new HashSet<>(); + bundles: for (Bundle bundle : bc.getBundles()) { + for (ProvisioningSource source : sources) { + String componentId = bundle.getSymbolicName(); + Version version = bundle.getVersion(); + A2Branch branch = source.findBranch(componentId, version); + if (branch == null) + continue bundles; + A2Module module = branch.last(); + Version moduleVersion = module.getVersion(); + int compare = moduleVersion.compareTo(version); + if (compare > 0) {// update + try (InputStream in = source.newInputStream(module.getLocator())) { + bundle.update(in); + String fragmentHost = bundle.getHeaders().get(Constants.FRAGMENT_HOST); + if (fragmentHost != null) + fragmentsUpdated = true; + OsgiBootUtils.info("Updated bundle " + bundle.getLocation() + " to version " + moduleVersion); + updatedBundles.add(bundle); + } catch (Exception e) { + OsgiBootUtils.error("Cannot update with module " + module, e); + } + } + } + } + FrameworkWiring frameworkWiring = bc.getBundle(0).adapt(FrameworkWiring.class); + if (fragmentsUpdated)// refresh all + frameworkWiring.refreshBundles(null); + else + frameworkWiring.refreshBundles(updatedBundles); + return updatedBundles; + } + + private static Framework launch() { + // start OSGi + FrameworkFactory frameworkFactory = new EquinoxFactory(); + Map configuration = new HashMap<>(); + configuration.put("osgi.console", "2323"); + Framework framework = frameworkFactory.newFramework(configuration); + try { + framework.start(); + } catch (BundleException e) { + throw new OsgiBootException("Cannot start OSGi framework", e); + } + return framework; + } + + public static void main(String[] args) { + Framework framework = launch(); + try { + ProvisioningManager pm = new ProvisioningManager(framework.getBundleContext()); + FsA2Source context = new FsA2Source(Paths.get( + "/home/mbaudier/dev/git/apache2/argeo-commons/dist/argeo-node/target/argeo-node-2.1.74-SNAPSHOT/argeo-node/share/osgi")); + context.load(); + if (framework.getBundleContext().getBundles().length == 1) {// initial + pm.install(null); + } else { + pm.update(); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + // framework.stop(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningSource.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningSource.java new file mode 100644 index 000000000..cb122e434 --- /dev/null +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/a2/ProvisioningSource.java @@ -0,0 +1,106 @@ +package org.argeo.osgi.boot.a2; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; + +import org.argeo.osgi.boot.OsgiBootException; +import org.osgi.framework.Constants; +import org.osgi.framework.Version; + +abstract class ProvisioningSource { + final Map contributions = Collections.synchronizedSortedMap(new TreeMap<>()); + + A2Contribution getOrAddContribution(String contributionId) { + if (contributions.containsKey(contributionId)) + return contributions.get(contributionId); + else + return new A2Contribution(this, contributionId); + } + + void asTree(String prefix, StringBuffer buf) { + if (prefix == null) + prefix = ""; + for (String contributionId : contributions.keySet()) { + buf.append(prefix); + buf.append(contributionId); + buf.append('\n'); + A2Contribution contribution = contributions.get(contributionId); + contribution.asTree(prefix + " ", buf); + } + } + + void asTree() { + StringBuffer buf = new StringBuffer(); + asTree("", buf); + System.out.println(buf); + } + + A2Component findComponent(String componentId) { + SortedMap res = new TreeMap<>(); + for (A2Contribution contribution : contributions.values()) { + components: for (String componentIdKey : contribution.components.keySet()) { + if (componentId.equals(componentIdKey)) { + res.put(contribution, contribution.components.get(componentIdKey)); + break components; + } + } + } + if (res.size() == 0) + return null; + // TODO explicit contribution priorities + return res.get(res.lastKey()); + + } + + A2Branch findBranch(String componentId, Version version) { + A2Component component = findComponent(componentId); + if (component == null) + return null; + String branchId = version.getMajor() + "." + version.getMinor(); + if (!component.branches.containsKey(branchId)) + return null; + return component.branches.get(branchId); + } + + protected String readVersionFromModule(Path modulePath) { + try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) { + Manifest manifest = in.getManifest(); + String versionStr = manifest.getMainAttributes().getValue(Constants.BUNDLE_VERSION); + return versionStr; + } catch (IOException e) { + throw new OsgiBootException("Cannot read manifest from " + modulePath, e); + } + } + + protected String readSymbolicNameFromModule(Path modulePath) { + try (JarInputStream in = new JarInputStream(newInputStream(modulePath))) { + Manifest manifest = in.getManifest(); + String symbolicName = manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME); + int semiColIndex = symbolicName.indexOf(';'); + if (semiColIndex >= 0) + symbolicName = symbolicName.substring(0, semiColIndex); + return symbolicName; + } catch (IOException e) { + throw new OsgiBootException("Cannot read manifest from " + modulePath, e); + } + } + + InputStream newInputStream(Object locator) throws IOException { + if (locator instanceof Path) { + return Files.newInputStream((Path) locator); + } else if (locator instanceof URL) { + return ((URL) locator).openStream(); + } else { + throw new IllegalArgumentException("Unsupported module locator type " + locator.getClass()); + } + } +} diff --git a/pom.xml b/pom.xml index a00ddf3b4..6e41168a3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 org.argeo.commons argeo-commons @@ -43,6 +45,7 @@ org.argeo.ext.jackrabbit org.argeo.ext.rap.ui.workbench + maven dep demo doc @@ -268,6 +271,7 @@ limitations under the License. 755 644 + false @@ -612,8 +616,10 @@ limitations under the License. - - + + @@ -638,8 +644,10 @@ limitations under the License. - - + +