From 805e3301575e708491482a2a00dd37bc2b41b851 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Fri, 13 Feb 2015 09:25:26 +0000 Subject: [PATCH] Merge JCR, OSGi and Ant support into SLC Core git-svn-id: https://svn.argeo.org/slc/trunk@7837 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- org.argeo.slc.core/bin/log4j.properties | 22 - .../core/deploy/DefaultResourceSetTest.class | Bin 2242 -> 0 bytes .../org/argeo/slc/core/deploy/data/file1.txt | 0 .../slc/core/deploy/data/subdir/file2.txt | 0 .../slc/core/deploy/relativeResourceSet.xml | 27 - .../AbstractExecutionFlowTestCase.class | Bin 3668 -> 0 bytes .../execution/BasicExecutionFlowTest.class | Bin 5661 -> 0 bytes .../core/execution/DefaultAgentCliTest.class | Bin 1175 -> 0 bytes .../ExceptionIfInitCalledTwice.class | Bin 1749 -> 0 bytes .../FileExecutionResourcesSpringTest.class | Bin 2275 -> 0 bytes .../FileExecutionResourcesTest.class | Bin 2240 -> 0 bytes .../slc/core/execution/ParameterRefTest.class | Bin 1554 -> 0 bytes .../slc/core/execution/applicationContext.xml | 60 -- .../argeo/slc/core/execution/canonic-001.xml | 36 - .../argeo/slc/core/execution/canonic-002.xml | 40 - .../slc/core/execution/canonic-003.error.xml | 39 - .../slc/core/execution/canonic-004.error.xml | 40 - .../org/argeo/slc/core/execution/canonic.xml | 66 -- .../slc/core/execution/executionResources.xml | 98 --- .../org/argeo/slc/core/execution/imports.xml | 36 - .../argeo/slc/core/execution/listSetMap.xml | 309 -------- .../core/execution/listSetMapMultipleFlow.xml | 326 -------- .../org/argeo/slc/core/execution/minimal.xml | 52 -- .../argeo/slc/core/execution/multipleFlow.xml | 137 ---- .../argeo/slc/core/execution/parameterRef.xml | 126 ---- .../execution/placeHolders.cascading.exec.xml | 327 -------- .../core/execution/placeHolders.cascading.xml | 239 ------ .../slc/core/execution/specOverriding.xml | 119 --- .../core/execution/tasks/SystemCallTest.class | Bin 2296 -> 0 bytes .../slc/core/execution/tasks/systemCall.xml | 118 --- .../bin/org/argeo/slc/core/execution/test.xml | 93 --- .../execution/xml/FlowNamespaceTest.class | Bin 1875 -> 0 bytes .../argeo/slc/core/execution/xml/advanced.xml | 110 --- .../slc/core/execution/xml/canonic-ns-001.xml | 34 - .../slc/core/execution/xml/canonic-ns-002.xml | 36 - .../slc/core/execution/xml/canonic-ns.xml | 82 --- .../slc/core/execution/xml/containers.xml | 129 ---- .../argeo/slc/core/execution/xml/tests.xml | 50 -- .../AbstractInternalSpringTestCase.class | Bin 3927 -> 0 bytes .../slc/core/test/context/ContextTest.class | Bin 1657 -> 0 bytes .../core/test/context/applicationContext.xml | 105 --- org.argeo.slc.core/bnd.bnd | 8 +- .../org/argeo/slc/ant/AntFlowGenerator.java | 51 ++ .../src/org/argeo/slc/ant/AntRun.java | 172 +++++ .../org/argeo/slc/jcr/JcrMetadataWriter.java | 79 ++ .../src/org/argeo/slc/jcr/JcrTestResult.java | 289 ++++++++ .../org/argeo/slc/jcr/SlcJcrConstants.java | 27 + .../org/argeo/slc/jcr/SlcJcrResultUtils.java | 166 +++++ .../src/org/argeo/slc/jcr/SlcJcrUtils.java | 266 +++++++ .../src/org/argeo/slc/jcr/SlcNames.java | 128 ++++ .../src/org/argeo/slc/jcr/SlcTypes.java | 83 +++ .../org/argeo/slc/jcr/execution/JcrAgent.java | 137 ++++ .../jcr/execution/JcrAttachmentUploader.java | 37 + .../JcrExecutionModulesListener.java | 416 +++++++++++ .../jcr/execution/JcrExecutionProcess.java | 194 +++++ .../slc/jcr/execution/JcrProcessThread.java | 95 +++ .../slc/jcr/execution/JcrRealizedFlow.java | 143 ++++ .../src/org/argeo/slc/jcr/slc.cnd | 139 ++++ .../org/argeo/slc/osgi/BundleRegister.java | 28 + .../org/argeo/slc/osgi/BundlesManager.java | 441 +++++++++++ .../slc/osgi/FileSystemBundleRegister.java | 124 ++++ .../MultipleServiceExporterPostProcessor.java | 161 ++++ .../src/org/argeo/slc/osgi/OsgiBundle.java | 152 ++++ .../argeo/slc/osgi/OsgiExecutionModule.java | 95 +++ .../slc/osgi/OsgiExecutionModulesManager.java | 696 ++++++++++++++++++ .../slc/osgi/OsgiExecutionResources.java | 104 +++ .../src/org/argeo/slc/osgi/OsgiRuntime.java | 147 ++++ .../AbstractOsgiModularDistribution.java | 177 +++++ .../osgi/build/BundleModularDistribution.java | 97 +++ .../slc/osgi/build/EclipseUpdateSite.java | 32 + .../osgi/build/EclipseUpdateSiteCategory.java | 47 ++ .../osgi/build/EclipseUpdateSiteFeature.java | 41 ++ .../build/OsgiRuntimeModularDistribution.java | 89 +++ .../slc/osgi/deploy/OsgiResourceSet.java | 76 ++ .../src/org/argeo/slc/osgi/execution.xml | 46 ++ 75 files changed, 4977 insertions(+), 2862 deletions(-) delete mode 100644 org.argeo.slc.core/bin/log4j.properties delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/deploy/DefaultResourceSetTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/deploy/data/file1.txt delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/deploy/data/subdir/file2.txt delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/deploy/relativeResourceSet.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/BasicExecutionFlowTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/DefaultAgentCliTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/FileExecutionResourcesTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/ParameterRefTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/applicationContext.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-001.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-002.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-003.error.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-004.error.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/executionResources.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/imports.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMap.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/minimal.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/multipleFlow.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/parameterRef.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/specOverriding.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/tasks/SystemCallTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/tasks/systemCall.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/test.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/FlowNamespaceTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/advanced.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-001.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-002.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/containers.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/tests.xml delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/test/context/ContextTest.class delete mode 100644 org.argeo.slc.core/bin/org/argeo/slc/core/test/context/applicationContext.xml create mode 100644 org.argeo.slc.core/src/org/argeo/slc/ant/AntFlowGenerator.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/ant/AntRun.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/JcrMetadataWriter.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/JcrTestResult.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrConstants.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrResultUtils.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrUtils.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/SlcNames.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/SlcTypes.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAgent.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAttachmentUploader.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionProcess.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrProcessThread.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrRealizedFlow.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/jcr/slc.cnd create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/BundleRegister.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/BundlesManager.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/FileSystemBundleRegister.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/MultipleServiceExporterPostProcessor.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiBundle.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModule.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionResources.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiRuntime.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/build/AbstractOsgiModularDistribution.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/build/BundleModularDistribution.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSite.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteCategory.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteFeature.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/build/OsgiRuntimeModularDistribution.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/deploy/OsgiResourceSet.java create mode 100644 org.argeo.slc.core/src/org/argeo/slc/osgi/execution.xml diff --git a/org.argeo.slc.core/bin/log4j.properties b/org.argeo.slc.core/bin/log4j.properties deleted file mode 100644 index 0133bab88..000000000 --- a/org.argeo.slc.core/bin/log4j.properties +++ /dev/null @@ -1,22 +0,0 @@ -# Set root logger level to DEBUG and its only appender to A1. -log4j.rootLogger=WARN, console - -## Levels -# Slc -log4j.logger.org.argeo=DEBUG - -# Castor -log4j.logger.org.exolab.castor=WARN - -# Spring -log4j.logger.org.springframework=WARN - - -## Appenders -# A1 is set to be a ConsoleAppender. -log4j.appender.console=org.apache.log4j.ConsoleAppender - -# A1 uses PatternLayout. -log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern= %-5p %d{ISO8601} %m - %c%n - diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/deploy/DefaultResourceSetTest.class b/org.argeo.slc.core/bin/org/argeo/slc/core/deploy/DefaultResourceSetTest.class deleted file mode 100644 index 296f6ef99118098808689670d1d3749b77be4026..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2242 zcmb7FYgZFj6x}xvCWJvSDio-SS~NspRQj-hw1Cp44UZa13w>UaOBk4B;>-l0Kc#=5 zU;9`qLc3O%U)#Ua@3s3*5?)1FvR0V6_nybTd!KXW?|*;)6Tm2T3`7L(xL(1MUO~B* z@8qnU>nSU*%8t8hJyh$m;slSC?^e8=%Bo;V`GJ9Efyq<60v^)86sVoRnp*P%Pv(L& zmtILa*|KMs3fg~0`bwb5aSH%G&aq2&FiD@} z;IcsTjGI?+w4vRADKPNr2(!fCdb=jhp+lghpaO;!7)@q2<+ijO$wV`b^!@R{v#_*6 z;Jk?_S_C>Wc1g`wifhVSl4}kxl*qU_=`2gn*6aFa%R~r0jwW=OxQH0x2OG98aIco_ zHFzf%=QYI{+dq)RkD*WCf~OoA*xTxeQgMR4Y~l*83K+cgw2~!(n@6vm4YVY@_aPGt zYnv(;j2pNnFm#HSR4dC9oZ9PL{{pa0`P5lC%wTHx5js zaGNS^sa+P^Nl$Lka~PI^kz<}bFmVTWSu8fIO;T`yu47r#^?e2y#XAPxreKGu8>c4T z#e0;f#0nO;*oY7o$pJO*3v?bbRwK~>)#*ODJ6*Azyz=6>j|V0u@d2gSmQF=2te=pg z9{i{jb#>wx!;~(aX@N_pska=%LjmzX8_t^e2p^L`SuU$mUSRk%k0W~5lGJgAvV3CV zQ)Jj{teLYx)^Y3H^E&s!iIgwBS0knN{LI8-WGP&IwoAX?Ui@Rf;FU!fEmp-8yQzG6aRM(Vfx`*UiV~CJ$1dU+Wfa&t1(K(Cz+%@8_3)iJGVa8F0(kM z%4NsSaqPIIncB?PNc1v>Cv1iW_C_E!>Bvse(JcBV0#pQA?b0IS$^scZYckbqKp>tC zKSr~*9=d&}f1*Y-QMkrbP5jac^y;C_w`Rm(@W<3#-Q`pNwI;+K;=iHu7cL@5@c+5c zv5#)OH1ETO@I;5=46nOeeChzv)H7TSGQHJ_fU=M2=TXT4=E4)4UO^D+vIykXY - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.class b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.class deleted file mode 100644 index 8fdcba1e1caae9ce5ec2f3d6be4d708577f814c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3668 zcmbVP`Fk7H6+KT@GLAfnjUbM*R!K-KE4BpwM$C+2 z(+#?}v@9*qg`IAcu0TPFOTT{owf&Eu1z%$trY^KwI)HQ#b7`H5xEcMa2@Zp_Ts&ibPC{3*ke8j=D7 zmunTv&zD?dO|Cocm3(7Wpv!j30-4#sL)9=>CE?fBoQjv{O4+KE^RrHQOkn4Eix}gy z$PO(DB&VDenL-zObZF>KVK;g;>=Ed@Y+N<+wn4*-%a^6;>*&KR0^MclPuYg&3EY|; znr-e1CdX2^6?-+@CUD}$RAv~d<36UNAN$CPsN^SbI=c;W=%a$#1%drKc3`JK@2pjk z^R=~Q=`I?}wiHOuI;LSS8Lp+q(PYwJwHU$q5c;MvLM?SlJH27bs>&bJ)5?8u)pgdD z$FZR$4Mzp`HKi*0E)z0Yv+Nb=cH=k~?|1x643%+88B=MTNg;z1Dl;bq_O`-@5X4R) zi=2ibhTe1#+pPivwYBIQe$CTSz^5ql!bGt+eSylfP%2b>S(YwO&@ARP z%n97m)Gb=naS;nlsa5fp47L`J2CRvdi%yRpIhzdr7C2+Jos34xjSSdxn z2dlWE!^WDxE|zhaVO4{zU9pkXZm>KLPP?w-W=c-2vXZeXnI_=5jDkC>GU@8@)NxOi z49ixr)O1|Mx`4K7c=G{mCjAlWBR8t-%W|dRSrlkhB{hNLTN2rUKP!JXEzK))Mm6e+ z1Ewo^4koHq+cFK+)TSI(rBZ64V?$6Pc~#ZSns<^Jn&fF(vdT4A^}y|jV;Y_in7k2y zSF2VX*UtydY{BqXA6~P!11ZVArQ_T94%1*&78nrQkHE=}gqtTS?tYKs1Y0*7-^!r4wtT?YbB>G(Rn z(Sv936AjNs&yJg;rQ@e~j-|)?o|FdfxQ~)GK0_}wUI6js+I;D>y>NQ)Jbtd@7wBd; zb88jF`$Ziusqqfec04AtdzsGX`RZZK#xRjETPi(X&bN7CTg~Ei9dF=Q;jI%FO8a?@ zrn&t$_??E|wsqlXQOBF=?oy&CPAR;FKWg|x+nXt@6dixUpSjbORogJhzCSxP)!H87 zDtrrn)$umo;bvY(HF>eLMeD|Gwms?U!u*@Mz~2)%lBk4Q&!{KT5eK&vVIJb$h1ey-hgaD3VACB`$bPRXk_P}X>2pl=33rvtcdnm8c z3z7Q^B&*!(xl`|Ax{goR@tG!aDp(st4~t8M5hCg_qK-v;HbN{$i2oqs4(=_G^wK6i z&-0ml6Q}nlH?b`6FRadwY~r#2eI0rY2ZN9+44Jc4HLC)=jz`sg_T?8p{I{ah6)4*u z01sn7MsO0N7{@RkU|5P;E)by*Q!7N&NCX>rjDhUO348@#CDzxte=iarGF3a6T@4SZ z44Yt$B~@#QBDutoDuvz;@c5-1!};ble0Og6ZBB)m4uwC%ZD&~f_P z;(Pc$L3h*c2lyd>lXwz8irhTOu@Wq!T>N-`WOx%#Cn(hO=aNcDAgdZVW z;2u`zIKS>C?l{u8j}cC=t|kKxcZHZShfKtQe(*BcBxrpgVADn0J$MDLl2uY&G!ZYG zQK;~PBCq4MI)2?Z+Ly26_j4*~!`JZ_rcF(}OX4bRO=ZHunI`f~iz2z0O%Cq|ili~X Nlq)s@*8*Ly{|}+e#5({0 diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/BasicExecutionFlowTest.class b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/BasicExecutionFlowTest.class deleted file mode 100644 index 6a1b8176ab7c385252f6692f9ea0a1b2cc167814..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5661 zcmcIoi+>c=75?rfaVN>iBcfhJQkAhOiCL<0QazU=$m+IRno+V9TH&h92lMEmo{@0Xc-@7#00^PTUU zbC*~C`{K(08t|VmLIMp*Yapsy14c4x$79i0(lVmPm=Q}mW-<}oqT6PyEi-J7Cr9@f zwi8CNz@`~Dw)EPLrN^9Uds}te5V)e*OqkAQfuhQ)9)aT4WS>!nB9y8q!4(3tJI#c# zBR$+}SbOx|ICp5B$(SDR(JfPs{mEiy(6j~CcFu^UuoF$R>Cl<(lo8uGVpx{hXC?*& z%G$b!&6_5CAcPxrG9|knn4xUVwpgAz;L!0dO~1jLBv@ncJ>}HVop;S*9ol14@Oo@ zd0Hq(1(vILhm3ZSl};#FDWDFIOMUG&>~x$es}!irH|EMyMlITH4yUMt;A=^JL`5}f z7?}}0ZuXJ@Wg(RmwACavsp$nG*ZluPNjhp!u93?JA~07X>>?c|-IWPwD`*gy zGn_LerKe!6FM%~>ScUZ}HejQG!VvD#Er-Wyl~tbXnA-7Zr)fJ)hTvSDSb(`7aAh~4WGO9GZp-M!Cr1_NEYsA=#<9uvsk z&-yTKnx^L98&(#-;s#&el3~b=$#&fy?9x+ZxEZAiZWjop)+o^VG}e?O1|y6t zg$zE^a=cc-s2uY-F30N>yibn#yjzafD>x{}eBLX^8x(v{jyK3~e@MlLaX-s}-q)9@ z__W?UHTsw4uPI0Aq{2<;scAREZfZAJW%jTdJ5-8nOL+{lg)GQ#OXI0bYg(KCX>$(Q ze#M_YvzZ3xPgR(dhJud^EW3n8B~mF=fyHuftDZv3C-(URzs7}Ac>9e2$Ntjbl>CEbx#bWskZtwz7js+Gx- z$MX=?dx$=jhp0Z^K$mIT%*u>`PqW!(U23Rf4^LX2na}2#p-4YZ&;cD4iKJ6u8%{-S zg*})|$NMUJjS9<N@KYT{T89Ym=#*+iV^?;~z zH|!a-lB2S7Q-)zYC$L_Y(W#xemyOnr_Vdn^w8o>d?Y7Db1n&(wb_FZg#)3WQGPYA) zvskHPL(B;O0<|P3JbM#EiR5S^U`fH3@(6CsC3qr_U}pVAfok7EMJkgrmnNAVM;9KXtTGCVG|Ozc5QdgE17+Gwzxt)}urdhL3dJ!(of{U*hpJvVnz zVh||pHU|>yZx*@leaj{2G7ErgS}}ZA#rN=i`aWcglODE$yxz?zw(eK(qcDD$SM|A| z;>Y-jY@)1KI;F%CmAALUpQnLW@$)c##*0C=sAX1F`~ttE{1fhdb$-S|Zes}J*KBjy zChnC1iT<}Leuv+)^YHF5NN2_&O>kaXqt4Tj7sabwz3>P?bIETGv2?f2*+&HCTjNEaP)I>QG61 z5<-P%+=mdx_57xehc73TC|2`ufi(qSO>&=v)g965Jy?x1!y>eGlh`By=Q|LoIgfWu zplt&0sh-3Rfvf{{F2s5|&_D+o>A+e#&`5CW=)igc+kh5qL?Hp_w<Jr??-5()g5Ab`LRo=`|&Io+80J*Dta*sr`k9pC4JIH-YG~NJ>PMD-| zh&0AY;}B^arb`LZm?VuU(s(Cnv`C{(8XXcg!naYRF@}SD9wMQKaaRs~M*{i|1@w&s z^d+XzCucnR9-K}eQ%@2Llt#2;+9xLPNH%B7T#?^R==ZqCdo`}qKVIOmna!Qho+x1M zUYa{p(A>!a=2Ao_Q+Z)TJEeVw=CsdU#FM8{+8L>yz|-ek=(AW~&+K3({l$kJ+v;&X#a^er6nB)V?fnT(}$@4-&^Q z;&_NS9_IOvz8M^o1#ldro3d6%Bif6e*uRn~ZCy2P6M2K;7I9g6jQ*Y=w#O;S6O`l= zEOI9)%TrjvXCNS;UAi2swa!c_tzQ*7P_OI!^E~lw{<85v#Pt%!aSgFsj zsXWW3a)#CVES-3c`Sm=T$_s2N=a^sTa~ztfsT9kfsC4XGid0g-Z&nktBad zU=lyz|H2iY#?r;bllZBm;8#1UYinvJ@tY7=|4;Wt+w9iKv3N-#|{*^2m=eDX!X z86BVfQI21d$|&FiFT2_A%kH`C*`L3@eg|*|D+&?}GoD}PmR}bh51bmWdA{J{y{I*% z?YaD+*tMFDT&)XNt~vI)2&94(Lw3LE+LG`3RznpH?h#29{S58X(;>!Fai}6oQj5i+hCy6YaFro{5z0EQV~AX{f{m9Y5FBtLTjY9Re;{Y+3Q8In#&t}1~5Wal$ zwrM$pl{QMH+@^|2hUHzyJDBJHw}YQ`V!36(BB>7v<#kM>K&W*g8TyP;i*{uCi|u_; zlcs_hq7iX+h2*4J1IMgRdA!S@N-w?~hF;_E-Eq|nwcHD}%rQ(DXMH+bi6TfBOlo`1 zF_xTaQbH&mryXYK|2LM0Z~jDc_|(4(@w%nQT%rVO6|d>n#A7?mclMlDR0u7=2rBa?c!oags{unnHjxd(V<&(#lO5g|hXWTwQF@#Jagd9gZjT*WL zG)waU0S*zQflf?Pb&i1N(H&75j$vDr1~7{IctF&KDB|-lN#g>Y6%vmti;?OjswJ@e E8$=`?SO5S3 diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.class b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.class deleted file mode 100644 index e5553236c3275ea8a44fb915df4087029084a77c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1749 zcmb7EZF3V<7(F+s-E`R&2+&f{HkN`(kgiY_p%t)|N;R~VwAEJqaI?8d7dE?@&4w5M ziC_H(zO_YW^t*q_8OL*XLlOvsW7Emz?(;n7oagQS_0R8r0GP*j22ui7gRpMPu&x5T zABz2XNeYp zv=`I`a-~>iQ#yN!8XJv(LA2EAXP1Kdf`IA7;?{jf37jbPG%N*yM<}{v79Gze!wtgb z3)=!i%RyC{IF1trvI6H{PqLDTv~Uuq1cvJ>BD27JzK?9#ldaZ5;lJdLKw!ec2uy*a zCD&JL?M6j~o4QskU@2fS+cI?Zx$|;(F_vy3jW;cv!I+6Dn|4#%9oDSQ*fdX^uDJn<0;Y)4TtEy0| zzi8oITw*s^z_?s&SH53dQbQ9qE*p4{1?qvtCJR?EFEGmZvfF5SYK_AraPkF^gm%Hi z2e@kB!xv^XvFRFpBygd>eaRHFe?7`BP#)KH-I?a8{*aEnu${rj6qO65pKFFeQ-$6W z6M5XUa0{PsUSzYW{HnmES49sHb_&J>@>sU;sm?eP1qs^`tl*A;&jhAkKe859@i|-T z`nBLC-Op3y8f0ZHQsG7{I&xL3tRn7HclTQc*4U$7NxGH{HfYG{!OS&Ov=>x!$rkF_ zyl0_|O#!QtEa0}D#dz~}4UqLrEWJBtWzXru{aRph5H=U-t7p!{7Ou0_K&Tyf(=|R58=U#@GAm>?f zPs9*b5`go#5QDwb1>2yX2AlaArKh-^LXW|WB~3Bs z=|1$CF8UWlPoYFqjeR%H`A4RtdA453v);#3{1xZ+@#PPgeTJ=_K}}yJz6aR(vpCdC uJ{{L@isffAls1ct6m*LT-{G^wx!**gPwrMn?k@c)?QgmWe8WQu-~J0+0Is+I diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.class b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.class deleted file mode 100644 index 59737ac6354d4152c5a29782510900ce54f07d17..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2275 zcmbVN`%@EF6#j0AY_hD#ORS0tR3r}|wp2v|XoyL%4J49~3VqO<%_Uj7WHY-PV5ZZ* zr_fLl7Z`F77zOc9YzcW%dR( zf_Wb%7zU5jb)=`M{TG{5fPw*+j4c)428Ks&nVwGZ3Rw8TaQdbP) zZ3wlYn3oPe)9^q-Rhv+Ac8#Ppibon|;3K+4VG38ID~Wx>B??=OjCG&R4#VZF%k>|Y zd9_h?1@otBk}KQRUQ;CfvWyv%>!NI#MPX+stPf8a{H;noyzj#z)uc@ps;A8;#2IHv zZcq*r1gGWf>5seI{>g{W|JR{3Rq&kQ+Od?H?{BeYNT4dd#Ik}EL(kb88di`dLG5z0 zCem9B_fF?FA}CAv zO2bR6lk|ACDk?>W$#xFjD|(AeR671z!#DU=ChMK!c$wP_EH1fjYWN_^&0kq%H`-;{c^wZegupNLGgXqEl{pe=%KCaT9 z^m~nbdGHadzMFO2N`>nfd4us#U$}3wj!1Jk{WH{Mnm(NPQ;x65 zTEQ^=K(;da6vYI2RB)4!451gdXn%;}-lo|d;xUt)fyu$E)t^H T2{hrB9>{Sc1U+7q8+OLO@rejg diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/FileExecutionResourcesTest.class b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/FileExecutionResourcesTest.class deleted file mode 100644 index 6371da2f7765a9b164c84b077a925e5282d29700..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2240 zcmbVNT~ixX7=8{U*$}oZO{pbH3#F7MAZ($fm84Z$3auKjmXuojT#`dr8nSeEBlOBU zubgqb(_3#GXY``uNYRdZW4-X__yfe}>~2CEsCGJpob#Ud z2%NW_vSB)9X&Y{(XcTQn8gfGxYo29SjcKbQr|QxT>Do1?DBXf|Jq;0ou9aHV@{A?N zT$Ss#bH`AcNz;`Au?rSeuL`uLGxGwGNxLKyXhoZjC}IK!@>W&O)>ap#Q!p1R^hoCI zqFI?Y9ZSjKVZ>XuT!D%FbEcUSIOH*@tJ1sWSe}ZkY7$6HZ4~92D$><(kX9?^C#F#` zt7W61(QruM%yZnFKoV^lUJy9_pWZX(TBEy@cGZ&`UIK^Fru)uX#^wdNN0k( z8C0F*5*UV|VMIXpa|+LOoK}we=y=_9WYu?9wqrVBf0o#k8bB)0s`lBoX0B! zh3UG|@d{3j2#KT@GV@BC)sa)$_CPyrR$M~)B3{!#eE0YhUNei!lCNiVm4GtBL~eRk z#ntgTE(si5C;Vj4u!0>FbRz6!y`DWf%LFcBQpXic33NEpEGgH59Rw2SYYGu|$j5Ow z9aX|r9oO&%`xKNgb+^VM1WxTS%)OF`<1K;C054-cUQ`x!z|5#g&Fyh94{sZv8xApIoUJUwX*1b9btsv62q5Mg22vDX7~PR#k#AKT=lnkzsp!ub5ZDBD zqgxnn$P^|*VR#D{!tE9=XCuR@$QGuDl5cJzpN*wrb>|7S_5EVLOYAZ0Z_%68hBoo` zpXgKz4ZlW0?Y3|urTzXi)qR%LjW75I_Dr?Ip$z_$wOQ~n{vhStJ|OkM zZw2fo&ni}2mFS;{sWAG_ zv!P6)xQQVRgSE!|8@7&H7^dnJgK0UG>|ff{(^iOuj2{m)wFM>3x(_o zskKR4XIM&?&vm4+%%F466RymDtZ9e(OJ=v_3z51SM%8wrLPw{ zUaG#enYN=|ag1M}_oe^Qw$g+kqSF_>=nI=pC5sfCiff9TrT&Q?Dt^mnHK#g^Q7TH1 zK0F{mEBa$-)W|YuW;C}=e?|DS?~c%@+(0j)H0q}ZXud)gNrt=ubkaIRR+kTRLOTln z?Q|@5jO+PitgniJ0DfSkiZO;{Y@%jQt<4-G5v*cXc^9j=$M6M@PVh|ahtBP1Xg^s+ zj-kPA5*>6?KixY(3+zPLDT5s{$qa24g<=kyBPR?i%@4@rqcFlQ3T+?-yf@ I&;nTh4euhPQUCw| diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/applicationContext.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/applicationContext.xml deleted file mode 100644 index d83c2c125..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/applicationContext.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-001.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-001.xml deleted file mode 100644 index a1c59c9b1..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-001.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-002.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-002.xml deleted file mode 100644 index 57f0c8a89..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-002.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-003.error.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-003.error.xml deleted file mode 100644 index 6de881047..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-003.error.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-004.error.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-004.error.xml deleted file mode 100644 index 2638ed6ee..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic-004.error.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic.xml deleted file mode 100644 index 8d6af0ef1..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/canonic.xml +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/executionResources.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/executionResources.xml deleted file mode 100644 index 654f8b420..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/executionResources.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/imports.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/imports.xml deleted file mode 100644 index 7ddb4ea80..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/imports.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMap.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMap.xml deleted file mode 100644 index 8cf72e354..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMap.xml +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - myValue - _myValue_ - - - - - @{testKey} - _@{testKey}_ - - - - - - - - - myValue - _myValue_ - - myValue - - - - - - @{testKey} - _@{testKey}_ - - @{testKey} - - - - - - - - myValue - _myValue_ - - - - - @{testKey} - _@{testKey}_ - - - - - - - - - myValue - _myValue_ - - myValue - - - - - - @{testKey} - _@{testKey}_ - - @{testKey} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - myValue - _myValue_ - - - myValue - _myValue_ - - myValue - - - myValue - - - - - - - - - - - - - - - - - - - - - @{testKey} - _@{testKey}_ - - - @{testKey} - _@{testKey}_ - - @{testKey} - - - @{testKey} - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml deleted file mode 100644 index b8626f851..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - myValue - _myValue_ - - - - - @{testKey} - _@{testKey}_ - - - - - - - - - myValue - _myValue_ - - myValue - - - - - - @{testKey} - _@{testKey}_ - - @{testKey} - - - - - - - - myValue - _myValue_ - - - - - @{testKey} - _@{testKey}_ - - - - - - - - - myValue - _myValue_ - - myValue - - - - - - @{testKey} - _@{testKey}_ - - @{testKey} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - myValue - _myValue_ - - - myValue - _myValue_ - - myValue - - - myValue - - - - - - - - - - - - - - - - - - - - - @{testKey} - _@{testKey}_ - - - @{testKey} - _@{testKey}_ - - @{testKey} - - - @{testKey} - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/minimal.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/minimal.xml deleted file mode 100644 index 5b166970b..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/minimal.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/multipleFlow.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/multipleFlow.xml deleted file mode 100644 index 58a43e418..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/multipleFlow.xml +++ /dev/null @@ -1,137 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/parameterRef.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/parameterRef.xml deleted file mode 100644 index 98cc14d3d..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/parameterRef.xml +++ /dev/null @@ -1,126 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml deleted file mode 100644 index a36b4a167..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml +++ /dev/null @@ -1,327 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.xml deleted file mode 100644 index 893768be3..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/placeHolders.cascading.xml +++ /dev/null @@ -1,239 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/specOverriding.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/specOverriding.xml deleted file mode 100644 index de1dc8504..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/specOverriding.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/tasks/SystemCallTest.class b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/tasks/SystemCallTest.class deleted file mode 100644 index fe381e4922c0c045d0bb5d7a7bc8febe7d20d2de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2296 zcmb7F+g95~6y0OHmNDWIaZ3rIPH4d9<|H)D#pD7mv}p_^HHC&=$MRqVvZP9KfKO?E zpf7!Cy6Vt$t$skiDXXhzB!f-Ea;YC|>CBw7_t|I9_^-cT{|R6YRRs}-8@5}?ass(Egj>%#LD#2D_iOA29cY46M2 zJof}c)U+!MsX|c0;rfms+-lXfyezF$46BkY*p(cEQWo3GhDj+}VVA$)S(DRR(RXPJ zEqCQ9#pjm4!OfaTpp&87JK;KeP&FA6^SWtRhW~(I)0qv1Sl%v+BzmDKxWI6&J&9%N z!gdc;^r4?2UJ*VqW0*^~@X4Fp^KzO0YNrDXgDT!ZoS~;+SYowSEeUs>m%;{Zotqon zHRO9E7@rTQClSRZ74M=;*0`)fL4q3bcMOlHgt-4_f+StPPt$15wP;iw$s)OQpbJNi z-cvBf(AQM`WF<))uBjNu1Wmy3*1TfPactKY$bIR zRBEnRu*#uFMA6ixNf;(trEQG5MeIgIPO_`$bA4}xJI4~9?x|pSegZd6c|yh*E}q^< z9XLWawhcXj4@jCO_2vr0!0Dt-!{4E4C2*VJLNntee3#s7d$Sg=lG$>&uV9{3Y04RD zui^n7GIWx!p1QUpT>p?^{0s#$Z%dHC0%2?#R@vV7lE`C8!AGYtf`g)B86VR@Aklqp zSY(+?tpNEQ?iR)OHDT!@m)T0}dxn#eQm0Bn=QU5H){3c#B%WbI zo`6jnL@WCfJIEc+Rczr)I;Pxlghh6oIcw`%N;dFw34BeCpGX;A%Ch~GcWmofS^HZR z-+_~iz8zwcQPQo=H<)xnhfqM^qwQ}N72BYjB(~38>t9W+m3D>h=cLEuwzo`D3-|)E4cUtBdfa>TMaM``q*K&2wY7PO1uYQW_Q<;kMGlXblR1J%}&TDp!&SveX|3M-FL z50}wHwIsE$a&M#ZY_OO0P@(KOA+DbRafKkR62w@0h@0nxm^%YvoFFC$BHbS1);S?Q zJOg5iAf^dorX55~UhpKBbi-?!hIG%8cIOE93RBvnIu>aX(Ib4a@)Hs<`8!?5>W@gh z#K0eT_FOBz!sk8^S)J780^9ZzAp^T)mJu>*_#}tigXkL!DagM;Ou^$Z>R^w;5t#n~Ui1f` diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/tasks/systemCall.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/tasks/systemCall.xml deleted file mode 100644 index 8d3565040..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/tasks/systemCall.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - echo - Hello - World - - - - - - - - - - - - - - - - - - - - - - - - - dir - - - - - - - ls - - - - - ls - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/test.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/test.xml deleted file mode 100644 index d8bec3df0..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/test.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From basic @{testedComponentId} - - - testData1='@{testData1}' - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/FlowNamespaceTest.class b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/FlowNamespaceTest.class deleted file mode 100644 index 3e0cd7cb5effcbf77f9c1c9777127d8108c0cb0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1875 zcmbtV+g8&+6y4K;iEUI2a`DPdpcf!eP}JfDDeo_Sxs0eJ0<3eEAAs8tV!Y3ZTH#i#4ehwVaHVWHVzqX#Exb*>ZPN|C?3&!(;+`e#Xt6EWvwVh`@*lah zjG@SIDG2#Eu4552Lu%p36jd3vuiz>}=RQB=hRvOd5$~wzWVmed@Y1;BPY`$t3|$(! z(ZkSddV&XHzFM^jRAQA}ClE&g!+NIN0Ne;X%c&HzA#=Yfja`p&{Lb~>QVqf@23_5? zDm70=d>*l=;(9Ze$;qiSZsN9rTTy-f4Ozn-^f4$E5j+>%VHjyiy%EjY_P#KKqJja2 z;pSR2q|_vZH2N{5;jS!p(yKWtM$X1kprZ2@d7S&7oH1y!>hn8?+%d(Diaf3G$dbiW zG0xDwOKP1`VMNn{im7Nitzw#_B0=5=zh+Z2++)Zz2OTz%JYsBE2UU`5d|GN{R>K24 zr05R0ZS9a+8ruxxnO0(MiB*)X(OuGqOp}B4XB@Ae5Wv!7Ys9cIdUcju&~Q?xURy`D4ho z@c*8Ilm3@-damw&tjS+qpEzSrHrctnUWgWEj&Z+1ZxAZM_7lAUqBlq+hA@j^Jj4h} zG%nJLOj4chQcU+*O!rX>x*v$Htj5!rZZY!ycx6m~s(i-$36_$Sw%310GZ$7ZM>NNX w@Hkax44s%jA10~91x(Q|u}I?+%!G9N>+WN^4 - - - - - - - - - - - - - - - - - spec description - - - - - - - flow description - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Would fail if param 2 is not changed at execution - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-001.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-001.xml deleted file mode 100644 index aeef3a3af..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-001.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - Canonic 001 - - - - - - - diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-002.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-002.xml deleted file mode 100644 index ac5f085eb..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns-002.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns.xml deleted file mode 100644 index facb27761..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/canonic-ns.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/containers.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/containers.xml deleted file mode 100644 index 61bfa0703..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/containers.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - val1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - val1 - val2 - - - - - val1 - val2 - - - - - - - - - - - - - - - - - - use default value for parameter "list1" - - - val1 - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/tests.xml b/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/tests.xml deleted file mode 100644 index ee58a1869..000000000 --- a/org.argeo.slc.core/bin/org/argeo/slc/core/execution/xml/tests.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bin/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.class b/org.argeo.slc.core/bin/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.class deleted file mode 100644 index 0cad464a78ffd6f325b270617ab2da3d03525ef5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3927 zcmb_f`F9jm7XDtRr9!8K5Fjwbr2%C+orKmf3X(QLTB6aApdF9|My+&LcM7Vj+UjZy z?#qnJjQfVTJK{bIbIuruoa6lHIsQ!^kKcP$>Fz9qBgbF5s@{F|-Fv_L-CM7J`sMo{ z0PMhjG(-gYU9XrjyrSu*Dt0cFb3HTVn-!mTj&Dx;slAgG-!pRl5Fb6qu(M^)a*AWz zk})c#hN!^CV^zoUQw7f`nGd_(@zk7EpviWN0`XzxrEKJ;Oahlmu2V_TQY2Dp*e&)6 zXrVuWwAx%zZt9S8;bdH=U=^#LF=?B7%Vpcj8NTH@T$a%iXhqs$F#U9$=sYA4&A53p zh9+F8VuAGTf##y=XKbTV5m=k(9Io$Di+wSy z#|91U0@p8}(;zu>y^}gN;t!09s7zE~M`96V=cU+L34snBS73#}>S4<PVnd;A%#?c!y+1Dnwx2ymDrJsbkjjI&?{CbPKF+ ztW9W_8oDy;8@c2AjdDn?Mn?mtLC9@Oz0pwMKv`sQW!5S>hF|qqu%7hT?!|lhmx3A_ zV}KNmjyN{A;3n+UaI?Vf<%nCpLv(CMih7)6{6l%Ep1Q)rlqv1TSOVQQc0w(y-b-hq z-cENhk^a8UFr8a<^y4=2ZM#N3%PQFBpy!rqDm$83Qe-mZN~#d_RchF(_)_q)5Mi(N zHRN*9s5R^r*ra;5))rYiw{JRUmZeTKWCS)WBxRs#*?H4z#y%E3V>piM$32r0GEbOs zBhLBvP}Pjf2;*)c?w>51@fZfsC4cVJF@(Fwxlt~g4ms~>q&Fn9k>8*Wp-T#20K+== zONlr8ZeWaI54t$ra<&{)YZfI=lMH5leQR}VpFc7fZK&)G3xUGQahkGr&A3mXomniH zy4$Bqwv_3(jtLy0*e&M(8^$P7?3e10P;)W-84qZFI!0*JQIPz}&K==bDuyW>(_qc}3v#b#l4m6YhPH7|pX$AgYuh|uaJCTl?|50mOZ*tsaqD&+ui#a7xy7TF!7Qct8bccj z*NO8w-qi30`@4=aXVvi*-e!;v4@3*UdZ8p+a0;h2yen{xnuO(xoy>H+hxY|mS(V$( z$!c+*BS$VfjHypF<3oYXgKpKy$4fjn#{DV7kGoDV1`Dni%)w@SED+fpmrQ-C;~)5p zOdU5*W=%%7W?p_=Vrr-GxsEUJrN9+=>2$$|d9JJYVcvO}-w7fsamnLUoj+N4GQMa8 zDpj+!=Wk6n>O9tchfV)gZ(POSRSM@?M0sFXjcai=*Yw~WT*GH5i}WY) z?&p)l>q!0&TYf}a@&c|KC+xO!NPdSca`i0DO_0#-3=QaHNJ&C=VJ)xi=xK1#5xVG6 z?}&Dy^RU5~Z{R`%H!7dE@h-yW7W(P!n#G?YkUk>H#|jnB4u#nsYzr~@0(RjR+9l|2 z+5*r%1$u_DNdgm+l-{lxr1y9Kh>i=`GkyUB<88N}!ys4hn8DrWF!KLy=`pH2Zc=pb zB*nW(-Yw`L_7+~ZA+4f_2e`E;5*Wn+MiJx6J-C-~WQi5TDs5vm+dv`Xr=WZR(`99~GlU<0jM=sYUFuHox8!;%Rr5zOG|3?^H*x29%L+%FUE zK93SpmJ1ItZ=ZSBJ;dl57~$WY(S{V0wG@+hSP|XEzb@0fi!gAW*LV#mKPeLsQLaXb zlke(oYC4ZcMtWxP6sz+I*75E+fm!@b{=6n|HZ+~VE=p?CEZz|~&Cq$Ts`CLu?Phh_ zK4Pfc`-wnMt67{OOJ_yBT)mVYaEP7{lGyv0!(nX2IEkKMq(^Woj^Zw!B@XlYARfRZ z43%Rth_#kuo-+Q5Trz%D&G;6#hafTgoc62#SJ$3T!X3a`RRMO9d?!WGph{V^}hEnWe?uRM7{2fUo`u zU-f~Dj*id%D94j-fu+DWJCkfql9TgYl0SdH{{k?MWerUXsft@Nxmywy({n7-s<^_G z!jtq@mSS6)Ilo__n1*JC>HlrWu6fesmdw+Bx6Ga5mTQ+wYJZMYv&vmtjqAZ?`P%jvZWaDlPXIuM zaw%}R%I20Mw(Bz*VhqMvX^OU5tIB^Nys9IkXh&-V9SqSrMI+W|6bzj@x^Rg>D+xI( zc$s0yC~WYz+;n)kWEQ2OA(IG%p08~POJ+25GYlU;Usc&CLG~SYiK(mT)zHI`KEC5j zKMW>Lxjj$=B^|q<3^pEDiv%NY)@v|kU&a9lHq)f$io>OY1|_3c=iYK2N@}^ z6fkw%#wdf%Jx{oD?oE|DlsIhU^NH0~vizim35MR|#MO{007c1Vm6*DNyX4a4Y_T}^ zn4u#en6h+9xV5_O>v#Y%REQ9e_(uLzWgjvOoN=6QCk4I@Q<%~52w8?!O6M1%k_K}g z9IlY&6jCZ~IOwptodWgNBR=?f9Zzb==Ck>NLKaoX{VEue4YD5Dsqq33<}i6kNfz_Z zI+TT`x{lw~_ge?|b+TdYRKtOXG92-enWlu%Vx{U@V%}CSK`d~YN0cQnKx~BQJp-EP zj~)d(=LJa({|El^68^w$rxzuLuxLNXrT z!NuRWoZ7>cWV}B(xPCN9?cnBOtR=k - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/bnd.bnd b/org.argeo.slc.core/bnd.bnd index 40b504bd2..3c198f97f 100644 --- a/org.argeo.slc.core/bnd.bnd +++ b/org.argeo.slc.core/bnd.bnd @@ -1,8 +1,4 @@ -Import-Package: org.w3c.dom;version="0.0.0",\ -org.dbunit;resolution:="optional",\ -org.dbunit.database;resolution:="optional",\ -org.dbunit.dataset;resolution:="optional",\ -org.dbunit.dataset.xml;resolution:="optional",\ -org.dbunit.operation;resolution:="optional",\ +Import-Package: javax.jcr.nodetype,\ +org.apache.tools.ant.*;resolution:="optional",\ junit.framework;resolution:="optional",\ * diff --git a/org.argeo.slc.core/src/org/argeo/slc/ant/AntFlowGenerator.java b/org.argeo.slc.core/src/org/argeo/slc/ant/AntFlowGenerator.java new file mode 100644 index 000000000..9dea43e49 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/ant/AntFlowGenerator.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.ant; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.argeo.slc.core.execution.AbstractExecutionFlowGenerator; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.core.io.Resource; + +public class AntFlowGenerator extends AbstractExecutionFlowGenerator { + private List antFiles = new ArrayList(); + + protected Map createExecutionFlowDefinitions( + ConfigurableListableBeanFactory beanFactory) { + Map definitions = new HashMap(); + + for (Resource antFile : antFiles) { + AntRun antRun = new AntRun(); + antRun.setBuildFile(antFile); + + List executables = new ArrayList(); + executables.add(antRun); + definitions.put("ant." + antFile.getFilename(), + createDefaultFlowDefinition(executables)); + } + return definitions; + } + + public void setAntFiles(List antFiles) { + this.antFiles = antFiles; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/ant/AntRun.java b/org.argeo.slc.core/src/org/argeo/slc/ant/AntRun.java new file mode 100644 index 000000000..1e2dcb940 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/ant/AntRun.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.ant; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tools.ant.BuildEvent; +import org.apache.tools.ant.BuildListener; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.ProjectHelper; +import org.apache.tools.ant.helper.ProjectHelper2; +import org.argeo.slc.SlcException; +import org.springframework.core.io.Resource; + +public class AntRun implements Runnable { + private final static Log log = LogFactory.getLog(AntRun.class); + + private Resource buildFile; + private File baseDir; + + private List targets = new ArrayList(); + private Map properties = new HashMap(); + + public void run() { + Project project = new Project(); + + try { + String path = buildFile.getURL().getPath(); + project.setUserProperty("ant.file", path); + project.setBaseDir(extractBaseDir(path)); + + project.init(); + ProjectHelper projectHelper = new ProjectHelper2(); + project.addReference(ProjectHelper.PROJECTHELPER_REFERENCE, + projectHelper); + projectHelper.parse(project, buildFile.getURL()); + } catch (Exception e) { + throw new SlcException("Could not parse " + buildFile, e); + } + + if (properties != null) { + for (Map.Entry entry : properties.entrySet()) { + project.setUserProperty(entry.getKey().toString(), entry + .getValue().toString()); + } + } + + project.fireBuildStarted(); + Throwable exception = null; + try { + project.addBuildListener(new LoggingListener()); + if (targets.size() == 0) { + project.executeTarget(project.getDefaultTarget()); + } else { + project.executeTargets(new Vector(targets)); + } + } catch (Throwable e) { + exception = e; + throw new SlcException("Could not run Ant script " + buildFile, e); + } finally { + project.fireBuildFinished(exception); + } + } + + private File extractBaseDir(String path) { + if(this.baseDir!=null) + return this.baseDir; + + String baseDir = null; + if (path.length() > 1) { + int indx = path.lastIndexOf('/', path.length() - 1); + if (indx == -1 || indx == 0) { + baseDir = "/"; + } else { + baseDir = path.substring(0, indx) + "/"; + } + } else { + baseDir = "/"; + } + File file = new File(baseDir); + if (file.exists()) { + return file; + } else { + return new File(System.getProperty("user.dir")); + } + } + + public void setBuildFile(Resource buildFile) { + this.buildFile = buildFile; + } + + public void setTargets(List targets) { + this.targets = targets; + } + + public void setProperties(Map properties) { + this.properties = properties; + } + + public void setBaseDir(File baseDir) { + this.baseDir = baseDir; + } + + protected static class LoggingListener implements BuildListener { + + public void buildFinished(BuildEvent event) { + if (log.isDebugEnabled()) + log.debug("Ant build finished: " + event); + } + + public void buildStarted(BuildEvent event) { + if (log.isDebugEnabled()) + log.debug("Ant build started: " + event); + } + + public void messageLogged(BuildEvent event) { + if (event.getPriority() == Project.MSG_DEBUG) { + if (log.isTraceEnabled()) + log.trace(event.getMessage()); + } else if (event.getPriority() == Project.MSG_VERBOSE) { + if (log.isDebugEnabled()) + log.debug(event.getMessage()); + } else if (event.getPriority() == Project.MSG_INFO) { + log.info(event.getMessage()); + + } else if (event.getPriority() == Project.MSG_WARN) { + log.warn(event.getMessage()); + + } else if (event.getPriority() == Project.MSG_ERR) { + log.error(event.getMessage()); + } else { + log.error(event.getMessage()); + } + } + + public void targetFinished(BuildEvent event) { + if (log.isTraceEnabled()) + log.debug("Target finished: " + event.getTarget()); + } + + public void targetStarted(BuildEvent event) { + if (log.isTraceEnabled()) + log.debug("Target started: " + event.getTarget()); + } + + public void taskFinished(BuildEvent event) { + } + + public void taskStarted(BuildEvent event) { + } + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrMetadataWriter.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrMetadataWriter.java new file mode 100644 index 000000000..19db9cbf7 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrMetadataWriter.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr; + +import java.util.HashMap; +import java.util.Map; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; + +/** + * Writes arbitrary metadata into a child node of a given node (or the node + * itself if metadata node name is set to null) + */ +public class JcrMetadataWriter implements Runnable { + private final static Log log = LogFactory.getLog(JcrMetadataWriter.class); + + private Node baseNode; + private String metadataNodeName = SlcNames.SLC_METADATA; + + private Map metadata = new HashMap(); + + public void run() { + try { + Node metadataNode; + if (metadataNodeName != null) + metadataNode = baseNode.hasNode(metadataNodeName) ? baseNode + .getNode(metadataNodeName) : baseNode + .addNode(metadataNodeName); + else + metadataNode = baseNode; + + for (String key : metadata.keySet()) + metadataNode.setProperty(key, metadata.get(key)); + + baseNode.getSession().save(); + + if (log.isDebugEnabled()) + log.debug("Wrote " + metadata.size() + " metadata entries to " + + metadataNode); + } catch (RepositoryException e) { + throw new SlcException("Cannot write metadata to " + baseNode, e); + } finally { + JcrUtils.discardUnderlyingSessionQuietly(baseNode); + } + + } + + public void setBaseNode(Node baseNode) { + this.baseNode = baseNode; + } + + public void setMetadataNodeName(String metadataNodeName) { + this.metadataNodeName = metadataNodeName; + } + + public void setMetadata(Map metadata) { + this.metadata = metadata; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrTestResult.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrTestResult.java new file mode 100644 index 000000000..e3394e05c --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrTestResult.java @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr; + +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.jcr.Credentials; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.Repository; +import javax.jcr.Session; +import javax.jcr.query.Query; +import javax.jcr.query.QueryManager; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.attachment.Attachment; +import org.argeo.slc.core.attachment.AttachmentsEnabled; +import org.argeo.slc.test.TestResult; +import org.argeo.slc.test.TestResultPart; +import org.argeo.slc.test.TestRun; +import org.argeo.slc.test.TestStatus; + +/** + * {@link TestResult} wrapping a JCR node of type + * {@link SlcTypes#SLC_TEST_RESULT}. + */ +public class JcrTestResult implements TestResult, SlcNames, AttachmentsEnabled { + private final static Log log = LogFactory.getLog(JcrTestResult.class); + + /** Should only be set for an already existing result. */ + private String uuid; + private Repository repository; + private Session session; + /** + * For testing purposes, best practice is to not set them explicitely but + * via other mechanisms such as JAAS or SPring Security. + */ + private Credentials credentials = null; + private String resultType = SlcTypes.SLC_TEST_RESULT; + + /** cached for performance purposes */ + private String nodeIdentifier = null; + + private Map attributes = new HashMap(); + + public void init() { + try { + session = repository.login(credentials); + if (uuid == null) { + // create new result + uuid = UUID.randomUUID().toString(); + String path = SlcJcrUtils.createResultPath(session, uuid); + Node resultNode = JcrUtils.mkdirs(session, path, resultType); + resultNode.setProperty(SLC_UUID, uuid); + for (String attr : attributes.keySet()) { + String property = attr; + // compatibility with legacy applications + if ("testCase".equals(attr)) + property = SLC_TEST_CASE; + else if ("testCaseType".equals(attr)) + property = SLC_TEST_CASE_TYPE; + resultNode.setProperty(property, attributes.get(attr)); + } + session.save(); + if (log.isDebugEnabled()) + log.debug("Created test result " + uuid); + } + } catch (Exception e) { + JcrUtils.discardQuietly(session); + throw new SlcException("Cannot initialize JCR result", e); + } + } + + public void destroy() { + JcrUtils.logoutQuietly(session); + if (log.isTraceEnabled()) + log.trace("Logged out session for result " + uuid); + } + + public Node getNode() { + try { + Node resultNode; + if (nodeIdentifier != null) { + return session.getNodeByIdentifier(nodeIdentifier); + } else { + QueryManager qm = session.getWorkspace().getQueryManager(); + Query q = qm.createQuery("select * from [" + + SlcTypes.SLC_TEST_RESULT + "] where [slc:uuid]='" + + uuid + "'", Query.JCR_SQL2); + resultNode = JcrUtils.querySingleNode(q); + if (resultNode != null) + nodeIdentifier = resultNode.getIdentifier(); + } + return resultNode; + } catch (Exception e) { + throw new SlcException("Cannot get result node", e); + } + } + + public void notifyTestRun(TestRun testRun) { + // TODO store meta data about the test running + // if (log.isDebugEnabled()) + // log.debug("Running test " + // + testRun.getTestDefinition().getClass().getName() + "..."); + } + + public void addResultPart(TestResultPart testResultPart) { + Node node = getNode(); + + try { + // error : revert all unsaved changes on the resultNode to be sure + // it is in a consistant state + if (testResultPart.getExceptionMessage() != null) + JcrUtils.discardQuietly(node.getSession()); + node.getSession().save(); + + // add the new result part, retrieving status information + Node resultPartNode = node.addNode(SlcNames.SLC_RESULT_PART, + SlcTypes.SLC_CHECK); + resultPartNode.setProperty(SLC_SUCCESS, testResultPart.getStatus() + .equals(TestStatus.PASSED)); + if (testResultPart.getMessage() != null) + resultPartNode.setProperty(SLC_MESSAGE, + testResultPart.getMessage()); + if (testResultPart.getStatus().equals(TestStatus.ERROR)) { + resultPartNode.setProperty(SLC_ERROR_MESSAGE, + (testResultPart.getExceptionMessage() == null) ? "" + : testResultPart.getExceptionMessage()); + } + + // helper update aggregate status node + Node mainStatus; + if (!node.hasNode(SLC_AGGREGATED_STATUS)) { + + mainStatus = node.addNode(SLC_AGGREGATED_STATUS, + SlcTypes.SLC_CHECK); + mainStatus.setProperty(SLC_SUCCESS, + resultPartNode.getProperty(SLC_SUCCESS).getBoolean()); + if (resultPartNode.hasProperty(SLC_MESSAGE)) + mainStatus.setProperty(SLC_MESSAGE, resultPartNode + .getProperty(SLC_MESSAGE).getString()); + if (resultPartNode.hasProperty(SLC_ERROR_MESSAGE)) + mainStatus.setProperty(SLC_ERROR_MESSAGE, resultPartNode + .getProperty(SLC_ERROR_MESSAGE).getString()); + } else { + mainStatus = node.getNode(SLC_AGGREGATED_STATUS); + if (mainStatus.hasProperty(SLC_ERROR_MESSAGE)) { + // main status already in error we do nothing + } else if (resultPartNode.hasProperty(SLC_ERROR_MESSAGE)) { + // main status was not in error and new result part is in + // error; we update main status + mainStatus.setProperty(SLC_SUCCESS, false); + mainStatus.setProperty(SLC_ERROR_MESSAGE, resultPartNode + .getProperty(SLC_ERROR_MESSAGE).getString()); + if (resultPartNode.hasProperty(SLC_MESSAGE)) + mainStatus.setProperty(SLC_MESSAGE, resultPartNode + .getProperty(SLC_MESSAGE).getString()); + else + // remove old message to remain consistent + mainStatus.setProperty(SLC_MESSAGE, ""); + } else if (!mainStatus.getProperty(SLC_SUCCESS).getBoolean()) { + // main status was already failed and new result part is not + // in error, we do nothing + } else if (!resultPartNode.getProperty(SLC_SUCCESS) + .getBoolean()) { + // new resultPart that is failed + mainStatus.setProperty(SLC_SUCCESS, false); + if (resultPartNode.hasProperty(SLC_MESSAGE)) + mainStatus.setProperty(SLC_MESSAGE, resultPartNode + .getProperty(SLC_MESSAGE).getString()); + else + // remove old message to remain consistent + mainStatus.setProperty(SLC_MESSAGE, ""); + } else if (resultPartNode.hasProperty(SLC_MESSAGE) + && (!mainStatus.hasProperty(SLC_MESSAGE) || ("" + .equals(mainStatus.getProperty(SLC_MESSAGE) + .getString().trim())))) { + mainStatus.setProperty(SLC_MESSAGE, resultPartNode + .getProperty(SLC_MESSAGE).getString()); + } + } + JcrUtils.updateLastModified(node); + node.getSession().save(); + } catch (Exception e) { + JcrUtils.discardUnderlyingSessionQuietly(node); + throw new SlcException("Cannot add ResultPart to node " + node, e); + } + } + + public String getUuid() { + Node node = getNode(); + try { + return node.getProperty(SLC_UUID).getString(); + } catch (Exception e) { + throw new SlcException("Cannot get UUID from " + node, e); + } + } + + /** JCR session is NOT logged out */ + public void close() { + Node node = getNode(); + try { + if (node.hasNode(SLC_COMPLETED)) + return; + node.setProperty(SLC_COMPLETED, new GregorianCalendar()); + JcrUtils.updateLastModified(node); + node.getSession().save(); + } catch (Exception e) { + JcrUtils.discardUnderlyingSessionQuietly(node); + throw new SlcException("Cannot get close date from " + node, e); + } + } + + public Date getCloseDate() { + Node node = getNode(); + try { + if (!node.hasNode(SLC_COMPLETED)) + return null; + return node.getProperty(SLC_COMPLETED).getDate().getTime(); + } catch (Exception e) { + throw new SlcException("Cannot get close date from " + node, e); + } + } + + public Map getAttributes() { + Node node = getNode(); + try { + Map map = new HashMap(); + PropertyIterator pit = node.getProperties(); + while (pit.hasNext()) { + Property p = pit.nextProperty(); + if (!p.isMultiple()) + map.put(p.getName(), p.getValue().getString()); + } + return map; + } catch (Exception e) { + throw new SlcException("Cannot get close date from " + node, e); + } + } + + public void addAttachment(Attachment attachment) { + // TODO implement it + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setResultType(String resultType) { + this.resultType = resultType; + } + + public void setAttributes(Map attributes) { + if (uuid != null) + throw new SlcException( + "Attributes cannot be set on an already initialized test result." + + " Update the related JCR node directly instead."); + this.attributes = attributes; + } + + public void setCredentials(Credentials credentials) { + this.credentials = credentials; + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrConstants.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrConstants.java new file mode 100644 index 000000000..179a081f4 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrConstants.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr; + +/** JCR related constants used across SLC */ +public interface SlcJcrConstants { + public final static String PROPERTY_PATH = "argeo.slc.jcr.path"; + + public final static String SLC_BASE_PATH = "/" + SlcNames.SLC_SYSTEM; + public final static String AGENTS_BASE_PATH = SLC_BASE_PATH + "/" + + SlcNames.SLC_AGENTS; + public final static String VM_AGENT_FACTORY_PATH = AGENTS_BASE_PATH + "/" + + SlcNames.SLC_VM; +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrResultUtils.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrResultUtils.java new file mode 100644 index 000000000..729c2d74b --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrResultUtils.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.slc.SlcException; + +/** + * Utilities around the SLC JCR Result model. Note that it relies on fixed base + * paths (convention over configuration) for optimization purposes. + */ +public class SlcJcrResultUtils { + + /** + * Returns the path to the current slc:result node + */ + public static String getSlcResultsBasePath(Session session) { + try { + Node userHome = UserJcrUtils.getUserHome(session); + if (userHome == null) + throw new SlcException("No user home available for " + + session.getUserID()); + return userHome.getPath() + '/' + SlcNames.SLC_SYSTEM + '/' + + SlcNames.SLC_RESULTS; + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while getting Slc Results Base Path.", re); + } + } + + /** + * Returns the base node to store SlcResults. If it does not exists, it is + * created. If a node already exists at the given path with the wrong type, + * it throws an exception. + * + * @param session + * @return + */ + public static Node getSlcResultsParentNode(Session session) { + try { + String absPath = getSlcResultsBasePath(session); + if (session.nodeExists(absPath)) { + Node currNode = session.getNode(absPath); + if (currNode.isNodeType(NodeType.NT_UNSTRUCTURED)) + return currNode; + else + throw new SlcException( + "A node already exists at this path : " + absPath + + " that has the wrong type. "); + } else { + Node slcResParNode = JcrUtils.mkdirs(session, absPath); + slcResParNode.setPrimaryType(NodeType.NT_UNSTRUCTURED); + session.save(); + return slcResParNode; + } + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while creating slcResult root parent node.", + re); + } + } + + /** + * Returns the path to the current Result UI specific node, depending the + * current user + */ + public static String getMyResultsBasePath(Session session) { + try { + Node userHome = UserJcrUtils.getUserHome(session); + if (userHome == null) + throw new SlcException("No user home available for " + + session.getUserID()); + return userHome.getPath() + '/' + SlcNames.SLC_SYSTEM + '/' + + SlcNames.SLC_MY_RESULTS; + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while getting Slc Results Base Path.", re); + } + } + + /** + * Creates a new node with type SlcTypes.SLC_MY_RESULT_ROOT_FOLDER at the + * given absolute path. If a node already exists at the given path, returns + * that node if it has the correct type and throws an exception otherwise. + * + * @param session + * @return + */ + public static Node getMyResultParentNode(Session session) { + try { + String absPath = getMyResultsBasePath(session); + if (session.nodeExists(absPath)) { + Node currNode = session.getNode(absPath); + if (currNode.isNodeType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER)) + return currNode; + else + throw new SlcException( + "A node already exists at this path : " + absPath + + " that has the wrong type. "); + } else { + Node myResParNode = JcrUtils.mkdirs(session, absPath); + myResParNode.setPrimaryType(SlcTypes.SLC_MY_RESULT_ROOT_FOLDER); + session.save(); + return myResParNode; + } + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while creating user MyResult base node.", + re); + } + } + + /** + * Creates a new node with type SlcTypes.SLC_RESULT_FOLDER at the given + * absolute path. If a node already exists at the given path, returns that + * node if it has the correct type and throws an exception otherwise. + * + * @param session + * @param absPath + * @return + */ + public static synchronized Node createResultFolderNode(Session session, + String absPath) { + try { + if (session.nodeExists(absPath)) { + // Sanity check + Node currNode = session.getNode(absPath); + if (currNode.isNodeType(SlcTypes.SLC_RESULT_FOLDER)) + return currNode; + else + throw new SlcException( + "A node already exists at this path : " + absPath + + " that has the wrong type. "); + } + Node rfNode = JcrUtils.mkdirs(session, absPath); + rfNode.setPrimaryType(SlcTypes.SLC_RESULT_FOLDER); + Node statusNode = rfNode.addNode(SlcNames.SLC_AGGREGATED_STATUS, + SlcTypes.SLC_CHECK); + statusNode.setProperty(SlcNames.SLC_SUCCESS, true); + session.save(); + return rfNode; + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while creating Result Folder node.", re); + } + } +} \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrUtils.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrUtils.java new file mode 100644 index 000000000..5c00bcffb --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrUtils.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.argeo.jcr.JcrUtils; +import org.argeo.jcr.UserJcrUtils; +import org.argeo.slc.BasicNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.PrimitiveAccessor; +import org.argeo.slc.core.execution.PrimitiveUtils; +import org.argeo.slc.deploy.ModuleDescriptor; +import org.argeo.slc.test.TestStatus; + +/** + * Utilities around the SLC JCR model. Note that it relies on fixed base paths + * (convention over configuration) for optimization purposes. + */ +public class SlcJcrUtils implements SlcNames { + public final static Integer AGENT_FACTORY_DEPTH = 3; + + /** Extracts the path of a flow relative to its execution module */ + public static String flowRelativePath(String fullFlowPath) { + String[] tokens = fullFlowPath.split("/"); + StringBuffer buf = new StringBuffer(fullFlowPath.length()); + for (int i = AGENT_FACTORY_DEPTH + 3; i < tokens.length; i++) { + buf.append('/').append(tokens[i]); + } + return buf.toString(); + } + + /** Extracts the path to the related execution module */ + public static String modulePath(String fullFlowPath) { + String[] tokens = fullFlowPath.split("/"); + StringBuffer buf = new StringBuffer(fullFlowPath.length()); + for (int i = 0; i < AGENT_FACTORY_DEPTH + 3; i++) { + if (!tokens[i].equals("")) + buf.append('/').append(tokens[i]); + } + return buf.toString(); + } + + /** Extracts the module name from a flow path */ + public static String moduleName(String fullFlowPath) { + String[] tokens = fullFlowPath.split("/"); + String moduleName = tokens[AGENT_FACTORY_DEPTH + 2]; + moduleName = moduleName.substring(0, moduleName.indexOf('_')); + return moduleName; + } + + /** Extracts the module name and version from a flow path */ + public static NameVersion moduleNameVersion(String fullFlowPath) { + String[] tokens = fullFlowPath.split("/"); + String module = tokens[AGENT_FACTORY_DEPTH + 2]; + String moduleName = module.substring(0, module.indexOf('_')); + String moduleVersion = module.substring(module.indexOf('_') + 1); + return new BasicNameVersion(moduleName, moduleVersion); + } + + /** Module node name based on module name and version */ + public static String getModuleNodeName(ModuleDescriptor moduleDescriptor) { + return moduleDescriptor.getName() + "_" + moduleDescriptor.getVersion(); + } + + /** Extracts the agent factory of a flow */ + public static String flowAgentFactoryPath(String fullFlowPath) { + String[] tokens = fullFlowPath.split("/"); + StringBuffer buf = new StringBuffer(fullFlowPath.length()); + // first token is always empty + for (int i = 1; i < AGENT_FACTORY_DEPTH + 1; i++) { + buf.append('/').append(tokens[i]); + } + return buf.toString(); + } + + /** Create a new execution process path based on the current time */ + public static String createExecutionProcessPath(Session session, String uuid) { + Calendar now = new GregorianCalendar(); + return getSlcProcessesBasePath(session) + '/' + + JcrUtils.dateAsPath(now, true) + uuid; + } + + /** Get the base for the user processi. */ + public static String getSlcProcessesBasePath(Session session) { + try { + Node userHome = UserJcrUtils.getUserHome(session); + if (userHome == null) + throw new SlcException("No user home available for " + + session.getUserID()); + return userHome.getPath() + '/' + SlcNames.SLC_SYSTEM + '/' + + SlcNames.SLC_PROCESSES; + } catch (RepositoryException re) { + throw new SlcException( + "Unexpected error while getting Slc Results Base Path.", re); + } + } + + /** + * Create a new execution result path in the user home based on the current + * time + */ + public static String createResultPath(Session session, String uuid) + throws RepositoryException { + Calendar now = new GregorianCalendar(); + StringBuffer absPath = new StringBuffer( + SlcJcrResultUtils.getSlcResultsBasePath(session) + '/'); + // Remove hours and add title property to the result process path on + // request of O. Capillon + // return getSlcProcessesBasePath(session) + '/' + // + JcrUtils.dateAsPath(now, true) + uuid; + String relPath = JcrUtils.dateAsPath(now, false); + List names = JcrUtils.tokenize(relPath); + for (String name : names) { + absPath.append(name + "/"); + Node node = JcrUtils.mkdirs(session, absPath.toString()); + try { + node.addMixin(NodeType.MIX_TITLE); + node.setProperty(Property.JCR_TITLE, name.substring(1)); + } catch (RepositoryException e) { + throw new SlcException( + "unable to create execution process path", e); + } + } + return absPath.toString() + uuid; + } + + /** + * Set the value of the primitive accessor as a JCR property. Does nothing + * if the value is null. + */ + public static void setPrimitiveAsProperty(Node node, String propertyName, + PrimitiveAccessor primitiveAccessor) { + String type = primitiveAccessor.getType(); + Object value = primitiveAccessor.getValue(); + setPrimitiveAsProperty(node, propertyName, type, value); + } + + /** Map a primitive value to JCR property value. */ + public static void setPrimitiveAsProperty(Node node, String propertyName, + String type, Object value) { + if (value == null) + return; + if (value instanceof CharSequence) + value = PrimitiveUtils.convert(type, + ((CharSequence) value).toString()); + if (value instanceof char[]) + value = new String((char[]) value); + + try { + if (type.equals(PrimitiveAccessor.TYPE_STRING)) + node.setProperty(propertyName, value.toString()); + else if (type.equals(PrimitiveAccessor.TYPE_PASSWORD)) + node.setProperty(propertyName, value.toString()); + else if (type.equals(PrimitiveAccessor.TYPE_INTEGER)) + node.setProperty(propertyName, (long) ((Integer) value)); + else if (type.equals(PrimitiveAccessor.TYPE_LONG)) + node.setProperty(propertyName, ((Long) value)); + else if (type.equals(PrimitiveAccessor.TYPE_FLOAT)) + node.setProperty(propertyName, (double) ((Float) value)); + else if (type.equals(PrimitiveAccessor.TYPE_DOUBLE)) + node.setProperty(propertyName, ((Double) value)); + else if (type.equals(PrimitiveAccessor.TYPE_BOOLEAN)) + node.setProperty(propertyName, ((Boolean) value)); + else + throw new SlcException("Unsupported type " + type); + } catch (RepositoryException e) { + throw new SlcException("Cannot set primitive of " + type + + " as property " + propertyName + " on " + node, e); + } + } + + /** Aggregates the {@link TestStatus} of this sub-tree. */ + public static Integer aggregateTestStatus(Node node) { + try { + Integer status = TestStatus.PASSED; + if (node.isNodeType(SlcTypes.SLC_CHECK)) + if (node.getProperty(SLC_SUCCESS).getBoolean()) + status = TestStatus.PASSED; + else if (node.hasProperty(SLC_ERROR_MESSAGE)) + status = TestStatus.ERROR; + else + status = TestStatus.FAILED; + + NodeIterator it = node.getNodes(); + while (it.hasNext()) { + Node curr = it.nextNode(); + + // Manually skip aggregated status + if (!SlcNames.SLC_AGGREGATED_STATUS.equals(curr.getName())) { + Integer childStatus = aggregateTestStatus(curr); + if (childStatus > status) + status = childStatus; + } + } + return status; + } catch (Exception e) { + throw new SlcException("Could not aggregate test status from " + + node, e); + } + } + + /** + * Aggregates the {@link TestStatus} of this sub-tree. + * + * @return the same {@link StringBuffer}, for convenience (typically calling + * toString() on it) + */ + public static StringBuffer aggregateTestMessages(Node node, + StringBuffer messages) { + try { + if (node.isNodeType(SlcTypes.SLC_CHECK)) { + if (node.hasProperty(SLC_MESSAGE)) { + if (messages.length() > 0) + messages.append('\n'); + messages.append(node.getProperty(SLC_MESSAGE).getString()); + } + if (node.hasProperty(SLC_ERROR_MESSAGE)) { + if (messages.length() > 0) + messages.append('\n'); + messages.append(node.getProperty(SLC_ERROR_MESSAGE) + .getString()); + } + } + NodeIterator it = node.getNodes(); + while (it.hasNext()) { + Node child = it.nextNode(); + // Manually skip aggregated status + if (!SlcNames.SLC_AGGREGATED_STATUS.equals(child.getName())) { + aggregateTestMessages(child, messages); + } + } + return messages; + } catch (Exception e) { + throw new SlcException("Could not aggregate test messages from " + + node, e); + } + } + + /** Prevents instantiation */ + private SlcJcrUtils() { + } +} \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcNames.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcNames.java new file mode 100644 index 000000000..15213fc0a --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcNames.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr; + +/** JCR names used by SLC */ +public interface SlcNames { + public final static String SLC_ = "slc:"; + + /* + * GENERAL + */ + public final static String SLC_UUID = "slc:uuid"; + public final static String SLC_STATUS = "slc:status"; + // generic name for result parts of a given test result (slc:testResult) + // note that corresponding nodes can be retrieved using + // myTestResultNode.getNodes(SLC_RESULT_PART+"*") method + public final static String SLC_RESULT_PART = "slc:resultPart"; + // Fixed name of the child node of a slc:testResult of type + // slc:check that aggregate status of all result parts of a given test + // result + public final static String SLC_AGGREGATED_STATUS = "slc:aggregatedStatus"; + + public final static String SLC_TYPE = "slc:type"; + public final static String SLC_NAME = "slc:name"; + public final static String SLC_VERSION = "slc:version"; + public final static String SLC_CATEGORY = "slc:category"; + public final static String SLC_VALUE = "slc:value"; + public final static String SLC_ADDRESS = "slc:address"; + public final static String SLC_METADATA = "slc:metadata"; + + public final static String SLC_TIMESTAMP = "slc:timestamp"; + public final static String SLC_STARTED = "slc:started"; + public final static String SLC_COMPLETED = "slc:completed"; + + public final static String SLC_VM = "slc:vm"; + /* + * SLC RUNTIME + */ + // execution + public final static String SLC_SPEC = "slc:spec"; + public final static String SLC_EXECUTION_SPECS = "slc:executionSpecs"; + public final static String SLC_FLOW = "slc:flow"; + public final static String SLC_LOG = "slc:log"; + public final static String SLC_AGENTS = "slc:agents"; + + // spec attribute + public final static String SLC_IS_IMMUTABLE = "slc:isImmutable"; + public final static String SLC_IS_CONSTANT = "slc:isConstant"; + public final static String SLC_IS_HIDDEN = "slc:isHidden"; + + // base directories + public final static String SLC_SYSTEM = "slc:system"; + public final static String SLC_RESULTS = "slc:results"; + public final static String SLC_MY_RESULTS = "slc:myResults"; + public final static String SLC_PROCESSES = "slc:processes"; + + // result + public final static String SLC_SUCCESS = "slc:success"; + public final static String SLC_MESSAGE = "slc:message"; + public final static String SLC_TAG = "slc:tag"; + public final static String SLC_ERROR_MESSAGE = "slc:errorMessage"; + public final static String SLC_TEST_CASE = "slc:testCase"; + public final static String SLC_TEST_CASE_TYPE = "slc:testCaseType"; + + // diff result + public final static String SLC_SUMMARY = "slc:summary"; + public final static String SLC_ISSUES = "slc:issues"; + + /* + * SLC REPO + */ + // shared + public final static String SLC_URL = "slc:url"; + public final static String SLC_OPTIONAL = "slc:optional"; + public final static String SLC_AS_STRING = "slc:asString"; + + // origin + public final static String SLC_ORIGIN = "slc:origin"; + public final static String SLC_PROXY = "slc:proxy"; + + // slc:artifact + public final static String SLC_ARTIFACT_ID = "slc:artifactId"; + public final static String SLC_GROUP_ID = "slc:groupId"; + public final static String SLC_GROUP_BASE_ID = "slc:groupBaseId"; + public final static String SLC_ARTIFACT_VERSION = "slc:artifactVersion"; + public final static String SLC_ARTIFACT_EXTENSION = "slc:artifactExtension"; + public final static String SLC_ARTIFACT_CLASSIFIER = "slc:artifactClassifier"; + + // slc:jarArtifact + public final static String SLC_MANIFEST = "slc:manifest"; + + // shared OSGi + public final static String SLC_SYMBOLIC_NAME = "slc:symbolic-name"; + public final static String SLC_BUNDLE_VERSION = "slc:bundle-version"; + + // slc:osgiBaseVersion + public final static String SLC_MAJOR = "slc:major"; + public final static String SLC_MINOR = "slc:minor"; + public final static String SLC_MICRO = "slc:micro"; + // slc:osgiVersion + public final static String SLC_QUALIFIER = "slc:qualifier"; + + // slc:exportedPackage + public final static String SLC_USES = "slc:uses"; + + // slc:modularDistribution + public final static String SLC_MODULES = "slc:modules"; + + // RPM + // slc:rpm + public final static String SLC_RPM_VERSION = "slc:rpmVersion"; + public final static String SLC_RPM_RELEASE = "slc:rpmRelease"; + public final static String SLC_RPM_ARCH = "slc:rpmArch"; + public final static String SLC_RPM_ARCHIVE_SIZE = "slc:rpmArchiveSize"; +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcTypes.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcTypes.java new file mode 100644 index 000000000..5cb6a1361 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcTypes.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr; + +/** JCR node types used by SLC */ +public interface SlcTypes { + + public final static String SLC_NAME_VERSION = "slc:nameVersion"; + public final static String SLC_CATEGORIZED_NAME_VERSION = "slc:categorizedNameVersion"; + + public final static String SLC_AGENT_FACTORY = "slc:agentFactory"; + public final static String SLC_AGENT = "slc:agent"; + public final static String SLC_MODULE = "slc:module"; + public final static String SLC_EXECUTION_MODULE = "slc:executionModule"; + public final static String SLC_EXECUTION_SPEC = "slc:executionSpec"; + public final static String SLC_EXECUTION_FLOW = "slc:executionFlow"; + public final static String SLC_PROCESS = "slc:process"; + public final static String SLC_REALIZED_FLOW = "slc:realizedFlow"; + + public final static String SLC_EXECUTION_SPEC_ATTRIBUTE = "slc:executionSpecAttribute"; + public final static String SLC_PRIMITIVE_SPEC_ATTRIBUTE = "slc:primitiveSpecAttribute"; + public final static String SLC_REF_SPEC_ATTRIBUTE = "slc:refSpecAttribute"; + + public final static String SLC_TEST_RESULT = "slc:testResult"; + public final static String SLC_CHECK = "slc:check"; + public final static String SLC_PROPERTY = "slc:property"; + public final static String SLC_DIFF_RESULT = "slc:diffResult"; + + // Node types used for user defined and managed result UI tree + public final static String SLC_MY_RESULT_ROOT_FOLDER = "slc:myResultRootFolder"; + public final static String SLC_RESULT_FOLDER = "slc:resultFolder"; + + // Log levels + public final static String SLC_LOG_ENTRY = "slc:logEntry"; + public final static String SLC_LOG_TRACE = "slc:logTrace"; + public final static String SLC_LOG_DEBUG = "slc:logDebug"; + public final static String SLC_LOG_INFO = "slc:logInfo"; + public final static String SLC_LOG_WARNING = "slc:logWarning"; + public final static String SLC_LOG_ERROR = "slc:logError"; + + /* + * REPO + */ + public final static String SLC_ARTIFACT = "slc:artifact"; + public final static String SLC_ARTIFACT_VERSION_BASE = "slc:artifactVersion"; + public final static String SLC_ARTIFACT_BASE = "slc:artifactBase"; + public final static String SLC_GROUP_BASE = "slc:groupBase"; + public final static String SLC_JAR_FILE = "slc:jarFile"; + public final static String SLC_BUNDLE_ARTIFACT = "slc:bundleArtifact"; + public final static String SLC_OSGI_VERSION = "slc:osgiVersion"; + public final static String SLC_JAVA_PACKAGE = "slc:javaPackage"; + public final static String SLC_EXPORTED_PACKAGE = "slc:exportedPackage"; + public final static String SLC_IMPORTED_PACKAGE = "slc:importedPackage"; + public final static String SLC_DYNAMIC_IMPORTED_PACKAGE = "slc:dynamicImportedPackage"; + public final static String SLC_REQUIRED_BUNDLE = "slc:requiredBundle"; + public final static String SLC_FRAGMENT_HOST = "slc:fragmentHost"; + + // Distribution management + // public final static String SLC_CATEGORY = "slc:category"; + public final static String SLC_MODULAR_DISTRIBUTION_BASE = "slc:modularDistributionBase"; + public final static String SLC_MODULAR_DISTRIBUTION = "slc:modularDistribution"; + public final static String SLC_MODULE_COORDINATES = "slc:moduleCoordinates"; + + // origin + public final static String SLC_KNOWN_ORIGIN = "slc:knownOrigin"; + public final static String SLC_PROXIED = "slc:proxied"; + + // rpm + public final static String SLC_RPM = "slc:rpm"; +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAgent.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAgent.java new file mode 100644 index 000000000..1c00b47fd --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAgent.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr.execution; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.UUID; + +import javax.jcr.Node; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.DefaultAgent; +import org.argeo.slc.core.execution.ProcessThread; +import org.argeo.slc.execution.ExecutionModulesManager; +import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.jcr.SlcJcrConstants; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; + +/** SLC VM agent synchronizing with a JCR repository. */ +public class JcrAgent extends DefaultAgent implements SlcNames { + // final static String ROLE_REMOTE = "ROLE_REMOTE"; + final static String NODE_REPO_URI = "argeo.node.repo.uri"; + + private Repository repository; + + private String agentNodeName = "default"; + + /* + * LIFECYCLE + */ + protected String initAgentUuid() { + Session session = null; + try { + session = repository.login(); + + String agentFactoryPath = getAgentFactoryPath(); + Node vmAgentFactoryNode = JcrUtils.mkdirsSafe(session, + agentFactoryPath, SlcTypes.SLC_AGENT_FACTORY); + if (!vmAgentFactoryNode.hasNode(agentNodeName)) { + String uuid = UUID.randomUUID().toString(); + Node agentNode = vmAgentFactoryNode.addNode(agentNodeName, + SlcTypes.SLC_AGENT); + agentNode.setProperty(SLC_UUID, uuid); + } + session.save(); + return vmAgentFactoryNode.getNode(agentNodeName) + .getProperty(SLC_UUID).getString(); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + throw new SlcException("Cannot find JCR agent UUID", e); + } finally { + JcrUtils.logoutQuietly(session); + } + } + + @Override + public void destroy() { + super.destroy(); + } + + /* + * SLC AGENT + */ + @Override + protected ProcessThread createProcessThread( + ThreadGroup processesThreadGroup, + ExecutionModulesManager modulesManager, ExecutionProcess process) { + if (process instanceof JcrExecutionProcess) + return new JcrProcessThread(processesThreadGroup, modulesManager, + (JcrExecutionProcess) process); + else + return super.createProcessThread(processesThreadGroup, + modulesManager, process); + } + + /* + * UTILITIES + */ + public String getNodePath() { + return getAgentFactoryPath() + '/' + getAgentNodeName(); + } + + public String getAgentFactoryPath() { + try { + Boolean isRemote = System.getProperty(NODE_REPO_URI) != null; + String agentFactoryPath; + if (isRemote) { + InetAddress localhost = InetAddress.getLocalHost(); + agentFactoryPath = SlcJcrConstants.AGENTS_BASE_PATH + "/" + + localhost.getCanonicalHostName(); + + if (agentFactoryPath + .equals(SlcJcrConstants.VM_AGENT_FACTORY_PATH)) + throw new SlcException("Unsupported hostname " + + localhost.getCanonicalHostName()); + } else {// local + agentFactoryPath = SlcJcrConstants.VM_AGENT_FACTORY_PATH; + } + return agentFactoryPath; + } catch (UnknownHostException e) { + throw new SlcException("Cannot find agent factory base path", e); + } + } + + /* + * BEAN + */ + public String getAgentNodeName() { + return agentNodeName; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setAgentNodeName(String agentNodeName) { + this.agentNodeName = agentNodeName; + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAttachmentUploader.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAttachmentUploader.java new file mode 100644 index 000000000..105d549cd --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAttachmentUploader.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr.execution; + +import javax.jcr.Session; + +import org.argeo.slc.core.attachment.Attachment; +import org.argeo.slc.core.attachment.AttachmentUploader; +import org.springframework.core.io.Resource; + +/** JCR based attachment uploader */ +public class JcrAttachmentUploader implements AttachmentUploader { + private Session session; + + public void upload(Attachment attachment, Resource resource) { + session.toString(); + // not yet implemented, need to review the interface + } + + public void setSession(Session session) { + this.session = session; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java new file mode 100644 index 000000000..ea734a8bb --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr.execution; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.PrimitiveSpecAttribute; +import org.argeo.slc.core.execution.PrimitiveValue; +import org.argeo.slc.core.execution.RefSpecAttribute; +import org.argeo.slc.core.execution.RefValueChoice; +import org.argeo.slc.deploy.ModuleDescriptor; +import org.argeo.slc.execution.ExecutionFlowDescriptor; +import org.argeo.slc.execution.ExecutionModuleDescriptor; +import org.argeo.slc.execution.ExecutionModulesListener; +import org.argeo.slc.execution.ExecutionModulesManager; +import org.argeo.slc.execution.ExecutionSpec; +import org.argeo.slc.execution.ExecutionSpecAttribute; +import org.argeo.slc.jcr.SlcJcrUtils; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; + +/** + * Synchronizes the local execution runtime with a JCR repository. For the time + * being the state is completely reset from one start to another. + */ +public class JcrExecutionModulesListener implements ExecutionModulesListener, + SlcNames { + private final static String SLC_EXECUTION_MODULES_PROPERTY = "slc.executionModules"; + + private final static Log log = LogFactory + .getLog(JcrExecutionModulesListener.class); + private JcrAgent agent; + + private ExecutionModulesManager modulesManager; + + private Repository repository; + /** + * We don't use a thread bound session because many different threads will + * call this critical component and we don't want to login each time. We + * therefore rather protect access to this session via synchronized. + */ + private Session session; + + /* + * LIFECYCLE + */ + public void init() { + try { + session = repository.login(); + clearAgent(); + if (modulesManager != null) { + Node agentNode = session.getNode(agent.getNodePath()); + + List moduleDescriptors = modulesManager + .listModules(); + + // scan SLC-ExecutionModule metadata + for (ModuleDescriptor md : moduleDescriptors) { + if (md.getMetadata().containsKey( + ExecutionModuleDescriptor.SLC_EXECUTION_MODULE)) { + String moduleNodeName = SlcJcrUtils + .getModuleNodeName(md); + Node moduleNode = agentNode.hasNode(moduleNodeName) ? agentNode + .getNode(moduleNodeName) : agentNode + .addNode(moduleNodeName); + moduleNode.addMixin(SlcTypes.SLC_EXECUTION_MODULE); + moduleNode.setProperty(SLC_NAME, md.getName()); + moduleNode.setProperty(SLC_VERSION, md.getVersion()); + moduleNode.setProperty(Property.JCR_TITLE, + md.getTitle()); + moduleNode.setProperty(Property.JCR_DESCRIPTION, + md.getDescription()); + moduleNode.setProperty(SLC_STARTED, md.getStarted()); + } + } + + // scan execution modules property + String executionModules = System + .getProperty(SLC_EXECUTION_MODULES_PROPERTY); + if (executionModules != null) { + for (String executionModule : executionModules.split(",")) { + allModules: for (ModuleDescriptor md : moduleDescriptors) { + String moduleNodeName = SlcJcrUtils + .getModuleNodeName(md); + if (md.getName().equals(executionModule)) { + Node moduleNode = agentNode + .hasNode(moduleNodeName) ? agentNode + .getNode(moduleNodeName) : agentNode + .addNode(moduleNodeName); + moduleNode + .addMixin(SlcTypes.SLC_EXECUTION_MODULE); + moduleNode.setProperty(SLC_NAME, md.getName()); + moduleNode.setProperty(SLC_VERSION, + md.getVersion()); + moduleNode.setProperty(Property.JCR_TITLE, + md.getTitle()); + moduleNode.setProperty( + Property.JCR_DESCRIPTION, + md.getDescription()); + moduleNode.setProperty(SLC_STARTED, + md.getStarted()); + break allModules; + } + } + } + + // save if needed + if (session.hasPendingChanges()) + session.save(); + } + } + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + JcrUtils.logoutQuietly(session); + throw new SlcException("Cannot initialize modules", e); + } + } + + public void destroy() { + clearAgent(); + JcrUtils.logoutQuietly(session); + } + + protected synchronized void clearAgent() { + try { + Node agentNode = session.getNode(agent.getNodePath()); + for (NodeIterator nit = agentNode.getNodes(); nit.hasNext();) + nit.nextNode().remove(); + session.save(); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + throw new SlcException("Cannot clear agent " + agent, e); + } + } + + /* + * EXECUTION MODULES LISTENER + */ + + public synchronized void executionModuleAdded( + ModuleDescriptor moduleDescriptor) { + syncExecutionModule(moduleDescriptor); + } + + protected void syncExecutionModule(ModuleDescriptor moduleDescriptor) { + try { + Node agentNode = session.getNode(agent.getNodePath()); + String moduleNodeName = SlcJcrUtils + .getModuleNodeName(moduleDescriptor); + Node moduleNode = agentNode.hasNode(moduleNodeName) ? agentNode + .getNode(moduleNodeName) : agentNode + .addNode(moduleNodeName); + moduleNode.addMixin(SlcTypes.SLC_EXECUTION_MODULE); + moduleNode.setProperty(SLC_NAME, moduleDescriptor.getName()); + moduleNode.setProperty(SLC_VERSION, moduleDescriptor.getVersion()); + moduleNode.setProperty(Property.JCR_TITLE, + moduleDescriptor.getTitle()); + moduleNode.setProperty(Property.JCR_DESCRIPTION, + moduleDescriptor.getDescription()); + moduleNode.setProperty(SLC_STARTED, moduleDescriptor.getStarted()); + session.save(); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + throw new SlcException("Cannot sync module " + moduleDescriptor, e); + } + } + + public synchronized void executionModuleRemoved( + ModuleDescriptor moduleDescriptor) { + try { + String moduleName = SlcJcrUtils.getModuleNodeName(moduleDescriptor); + Node agentNode = session.getNode(agent.getNodePath()); + if (agentNode.hasNode(moduleName)) { + Node moduleNode = agentNode.getNode(moduleName); + for (NodeIterator nit = moduleNode.getNodes(); nit.hasNext();) { + nit.nextNode().remove(); + } + moduleNode.setProperty(SLC_STARTED, false); + } + session.save(); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + throw new SlcException("Cannot remove module " + moduleDescriptor, + e); + } + } + + public synchronized void executionFlowAdded(ModuleDescriptor module, + ExecutionFlowDescriptor efd) { + try { + Node agentNode = session.getNode(agent.getNodePath()); + Node moduleNode = agentNode.getNode(SlcJcrUtils + .getModuleNodeName(module)); + String relativePath = getExecutionFlowRelativePath(efd); + @SuppressWarnings("unused") + Node flowNode = null; + if (!moduleNode.hasNode(relativePath)) { + flowNode = createExecutionFlowNode(moduleNode, relativePath, + efd); + session.save(); + } else { + flowNode = moduleNode.getNode(relativePath); + } + + if (log.isTraceEnabled()) + log.trace("Flow " + efd + " added to JCR"); + } catch (RepositoryException e) { + JcrUtils.discardQuietly(session); + throw new SlcException("Cannot add flow " + efd + " from module " + + module, e); + } + + } + + protected Node createExecutionFlowNode(Node moduleNode, + String relativePath, ExecutionFlowDescriptor efd) + throws RepositoryException { + Node flowNode = null; + List pathTokens = Arrays.asList(relativePath.split("/")); + + Iterator names = pathTokens.iterator(); + // create intermediary paths + Node currNode = moduleNode; + while (names.hasNext()) { + String name = names.next(); + if (currNode.hasNode(name)) + currNode = currNode.getNode(name); + else { + if (names.hasNext()) + currNode = currNode.addNode(name); + else + flowNode = currNode.addNode(name, + SlcTypes.SLC_EXECUTION_FLOW); + } + } + + // name, description + flowNode.setProperty(SLC_NAME, efd.getName()); + String endName = pathTokens.get(pathTokens.size() - 1); + flowNode.setProperty(Property.JCR_TITLE, endName); + if (efd.getDescription() != null + && !efd.getDescription().trim().equals("")) { + flowNode.setProperty(Property.JCR_DESCRIPTION, efd.getDescription()); + } else { + flowNode.setProperty(Property.JCR_DESCRIPTION, endName); + } + + // execution spec + ExecutionSpec executionSpec = efd.getExecutionSpec(); + String esName = executionSpec.getName(); + if (esName == null || esName.equals(ExecutionSpec.INTERNAL_NAME) + || esName.contains("#")/* automatically generated bean name */) { + // internal spec node + mapExecutionSpec(flowNode, executionSpec); + } else { + // reference spec node + Node executionSpecsNode = moduleNode.hasNode(SLC_EXECUTION_SPECS) ? moduleNode + .getNode(SLC_EXECUTION_SPECS) : moduleNode + .addNode(SLC_EXECUTION_SPECS); + Node executionSpecNode = executionSpecsNode.addNode(esName, + SlcTypes.SLC_EXECUTION_SPEC); + executionSpecNode.setProperty(SLC_NAME, esName); + executionSpecNode.setProperty(Property.JCR_TITLE, esName); + if (executionSpec.getDescription() != null + && !executionSpec.getDescription().trim().equals("")) + executionSpecNode.setProperty(Property.JCR_DESCRIPTION, + executionSpec.getDescription()); + mapExecutionSpec(executionSpecNode, executionSpec); + flowNode.setProperty(SLC_SPEC, executionSpecNode); + } + + // flow values + for (String attr : efd.getValues().keySet()) { + ExecutionSpecAttribute esa = executionSpec.getAttributes() + .get(attr); + if (esa instanceof PrimitiveSpecAttribute) { + PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa; + // if spec reference there will be no node at this stage + Node valueNode = JcrUtils.getOrAdd(flowNode, attr); + valueNode.setProperty(SLC_TYPE, psa.getType()); + SlcJcrUtils.setPrimitiveAsProperty(valueNode, SLC_VALUE, + (PrimitiveValue) efd.getValues().get(attr)); + } + } + + return flowNode; + } + + /** + * Base can be either an execution spec node, or an execution flow node (in + * case the execution spec is internal) + */ + protected void mapExecutionSpec(Node baseNode, ExecutionSpec executionSpec) + throws RepositoryException { + for (String attrName : executionSpec.getAttributes().keySet()) { + ExecutionSpecAttribute esa = executionSpec.getAttributes().get( + attrName); + Node attrNode = baseNode.addNode(attrName); + // booleans + attrNode.addMixin(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE); + attrNode.setProperty(SLC_IS_IMMUTABLE, esa.getIsImmutable()); + attrNode.setProperty(SLC_IS_CONSTANT, esa.getIsConstant()); + attrNode.setProperty(SLC_IS_HIDDEN, esa.getIsHidden()); + + if (esa instanceof PrimitiveSpecAttribute) { + attrNode.addMixin(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE); + PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa; + SlcJcrUtils.setPrimitiveAsProperty(attrNode, SLC_VALUE, psa); + attrNode.setProperty(SLC_TYPE, psa.getType()); + } else if (esa instanceof RefSpecAttribute) { + attrNode.addMixin(SlcTypes.SLC_REF_SPEC_ATTRIBUTE); + RefSpecAttribute rsa = (RefSpecAttribute) esa; + attrNode.setProperty(SLC_TYPE, rsa.getTargetClassName()); + Object value = rsa.getValue(); + if (rsa.getChoices() != null) { + Integer index = null; + int count = 0; + for (RefValueChoice choice : rsa.getChoices()) { + String name = choice.getName(); + if (value != null && name.equals(value.toString())) + index = count; + Node choiceNode = attrNode.addNode(choice.getName()); + choiceNode.addMixin(NodeType.MIX_TITLE); + choiceNode.setProperty(Property.JCR_TITLE, + choice.getName()); + if (choice.getDescription() != null + && !choice.getDescription().trim().equals("")) + choiceNode.setProperty(Property.JCR_DESCRIPTION, + choice.getDescription()); + count++; + } + + if (index != null) + attrNode.setProperty(SLC_VALUE, index); + } + } + } + } + + public synchronized void executionFlowRemoved(ModuleDescriptor module, + ExecutionFlowDescriptor executionFlow) { + try { + Node agentNode = session.getNode(agent.getNodePath()); + Node moduleNode = agentNode.getNode(SlcJcrUtils + .getModuleNodeName(module)); + String relativePath = getExecutionFlowRelativePath(executionFlow); + if (moduleNode.hasNode(relativePath)) + moduleNode.getNode(relativePath).remove(); + agentNode.getSession().save(); + } catch (RepositoryException e) { + throw new SlcException("Cannot remove flow " + executionFlow + + " from module " + module, e); + } + } + + /* + * UTILITIES + */ + /** @return the relative path, never starts with '/' */ + @SuppressWarnings("deprecation") + protected String getExecutionFlowRelativePath( + ExecutionFlowDescriptor executionFlow) { + String relativePath = executionFlow.getPath() == null ? executionFlow + .getName() : executionFlow.getPath() + '/' + + executionFlow.getName(); + // we assume that it is more than one char long + if (relativePath.charAt(0) == '/') + relativePath = relativePath.substring(1); + // FIXME quick hack to avoid duplicate '/' + relativePath = relativePath.replaceAll("//", "/"); + return relativePath; + } + + /* + * BEAN + */ + public void setAgent(JcrAgent agent) { + this.agent = agent; + } + + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setModulesManager(ExecutionModulesManager modulesManager) { + this.modulesManager = modulesManager; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionProcess.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionProcess.java new file mode 100644 index 000000000..180d8f008 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionProcess.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr.execution; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.ProcessThread; +import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.ExecutionStep; +import org.argeo.slc.execution.RealizedFlow; +import org.argeo.slc.jcr.SlcJcrUtils; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; + +/** Execution process implementation based on a JCR node. */ +public class JcrExecutionProcess implements ExecutionProcess, SlcNames { + private final static Log log = LogFactory.getLog(JcrExecutionProcess.class); + private final Node node; + + private Long nextLogLine = 1l; + + public JcrExecutionProcess(Node node) { + this.node = node; + } + + public synchronized String getUuid() { + try { + return node.getProperty(SLC_UUID).getString(); + } catch (RepositoryException e) { + throw new SlcException("Cannot get uuid for " + node, e); + } + } + + public synchronized String getStatus() { + try { + return node.getProperty(SLC_STATUS).getString(); + } catch (RepositoryException e) { + log.error("Cannot get status: " + e); + // we should re-throw exception because this information can + // probably used for monitoring in case there are already unexpected + // exceptions + return UNKOWN; + } + } + + public synchronized void setStatus(String status) { + try { + node.setProperty(SLC_STATUS, status); + // last modified properties needs to be manually updated + // see https://issues.apache.org/jira/browse/JCR-2233 + JcrUtils.updateLastModified(node); + node.getSession().save(); + } catch (RepositoryException e) { + JcrUtils.discardUnderlyingSessionQuietly(node); + // we should re-throw exception because this information can + // probably used for monitoring in case there are already unexpected + // exceptions + log.error("Cannot set status " + status + ": " + e); + } + } + + /** + * Synchronized in order to make sure that there is no concurrent + * modification of {@link #nextLogLine}. + */ + public synchronized void addSteps(List steps) { + try { + steps: for (ExecutionStep step : steps) { + String type; + if (step.getType().equals(ExecutionStep.TRACE)) + type = SlcTypes.SLC_LOG_TRACE; + else if (step.getType().equals(ExecutionStep.DEBUG)) + type = SlcTypes.SLC_LOG_DEBUG; + else if (step.getType().equals(ExecutionStep.INFO)) + type = SlcTypes.SLC_LOG_INFO; + else if (step.getType().equals(ExecutionStep.WARNING)) + type = SlcTypes.SLC_LOG_WARNING; + else if (step.getType().equals(ExecutionStep.ERROR)) + type = SlcTypes.SLC_LOG_ERROR; + else + // skip + continue steps; + + String relPath = SLC_LOG + '/' + + step.getThread().replace('/', '_') + '/' + + step.getLocation().replace('.', '/'); + String path = node.getPath() + '/' + relPath; + // clean special character + // TODO factorize in JcrUtils + path = path.replace('@', '_'); + + Node location = JcrUtils.mkdirs(node.getSession(), path); + Node logEntry = location.addNode(Long.toString(nextLogLine), + type); + logEntry.setProperty(SLC_MESSAGE, step.getLog()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(step.getTimestamp()); + logEntry.setProperty(SLC_TIMESTAMP, calendar); + + // System.out.println("Logged " + logEntry.getPath()); + + nextLogLine++; + } + + // last modified properties needs to be manually updated + // see https://issues.apache.org/jira/browse/JCR-2233 + JcrUtils.updateLastModified(node); + + node.getSession().save(); + } catch (Exception e) { + JcrUtils.discardUnderlyingSessionQuietly(node); + e.printStackTrace(); + } + } + + // public Node getNode() { + // return node; + // } + + public List getRealizedFlows() { + try { + List realizedFlows = new ArrayList(); + Node rootRealizedFlowNode = node.getNode(SLC_FLOW); + // we just manage one level for the time being + NodeIterator nit = rootRealizedFlowNode.getNodes(SLC_FLOW); + while (nit.hasNext()) { + Node realizedFlowNode = nit.nextNode(); + + if (realizedFlowNode.hasNode(SLC_ADDRESS)) { + String flowPath = realizedFlowNode.getNode(SLC_ADDRESS) + .getProperty(Property.JCR_PATH).getString(); + NameVersion moduleNameVersion = SlcJcrUtils + .moduleNameVersion(flowPath); + ((ProcessThread) Thread.currentThread()) + .getExecutionModulesManager().start( + moduleNameVersion); + } + + RealizedFlow realizedFlow = new JcrRealizedFlow( + realizedFlowNode); + if (realizedFlow != null) + realizedFlows.add(realizedFlow); + } + return realizedFlows; + } catch (RepositoryException e) { + throw new SlcException("Cannot get realized flows", e); + } + } + + public String getNodePath() { + try { + return node.getPath(); + } catch (RepositoryException e) { + throw new SlcException("Cannot get process node path for " + node, + e); + } + } + + public Repository getRepository() { + try { + return node.getSession().getRepository(); + } catch (RepositoryException e) { + throw new SlcException("Cannot get process JCR repository for " + + node, e); + } + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrProcessThread.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrProcessThread.java new file mode 100644 index 000000000..8755829e7 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrProcessThread.java @@ -0,0 +1,95 @@ +/* + + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.jcr.execution; + +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.argeo.ArgeoException; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.core.execution.ProcessThread; +import org.argeo.slc.execution.ExecutionModulesManager; +import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.RealizedFlow; +import org.argeo.slc.jcr.SlcNames; + +/** Where the actual execution takes place */ +public class JcrProcessThread extends ProcessThread implements SlcNames { + + public JcrProcessThread(ThreadGroup processesThreadGroup, + ExecutionModulesManager executionModulesManager, + JcrExecutionProcess process) { + super(processesThreadGroup, executionModulesManager, process); + } + + /** Overridden in order to set progress status on realized flow nodes. */ + @Override + protected void process() throws InterruptedException { + Session session = null; + if (getProcess() instanceof JcrExecutionProcess) + try { + session = ((JcrExecutionProcess) getProcess()).getRepository() + .login(); + + List realizedFlows = getProcess() + .getRealizedFlows(); + for (RealizedFlow realizedFlow : realizedFlows) { + Node realizedFlowNode = session + .getNode(((JcrRealizedFlow) realizedFlow).getPath()); + setFlowStatus(realizedFlowNode, ExecutionProcess.RUNNING); + + try { + // + // EXECUTE THE FLOW + // + execute(realizedFlow, true); + + setFlowStatus(realizedFlowNode, + ExecutionProcess.COMPLETED); + } catch (RepositoryException e) { + throw e; + } catch (InterruptedException e) { + setFlowStatus(realizedFlowNode, ExecutionProcess.KILLED); + throw e; + } catch (RuntimeException e) { + setFlowStatus(realizedFlowNode, ExecutionProcess.ERROR); + throw e; + } + } + } catch (RepositoryException e) { + throw new ArgeoException("Cannot process " + + getJcrExecutionProcess().getNodePath(), e); + } finally { + JcrUtils.logoutQuietly(session); + } + else + super.process(); + } + + protected void setFlowStatus(Node realizedFlowNode, String status) + throws RepositoryException { + realizedFlowNode.setProperty(SLC_STATUS, status); + realizedFlowNode.getSession().save(); + } + + protected JcrExecutionProcess getJcrExecutionProcess() { + return (JcrExecutionProcess) getProcess(); + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrRealizedFlow.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrRealizedFlow.java new file mode 100644 index 000000000..2dd56e331 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrRealizedFlow.java @@ -0,0 +1,143 @@ +package org.argeo.slc.jcr.execution; + +import java.util.HashMap; +import java.util.Map; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Property; +import javax.jcr.RepositoryException; + +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.DefaultExecutionSpec; +import org.argeo.slc.core.execution.PrimitiveSpecAttribute; +import org.argeo.slc.core.execution.PrimitiveUtils; +import org.argeo.slc.core.execution.RefSpecAttribute; +import org.argeo.slc.execution.ExecutionFlowDescriptor; +import org.argeo.slc.execution.ExecutionSpecAttribute; +import org.argeo.slc.execution.RealizedFlow; +import org.argeo.slc.jcr.SlcJcrUtils; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; + +public class JcrRealizedFlow extends RealizedFlow implements SlcNames { + private static final long serialVersionUID = -3709453850260712001L; + private String path; + + public JcrRealizedFlow(Node node) { + try { + this.path = node.getPath(); + loadFromNode(node); + } catch (RepositoryException e) { + throw new SlcException("Cannot initialize from " + node, e); + } + } + + protected void loadFromNode(Node realizedFlowNode) + throws RepositoryException { + if (realizedFlowNode.hasNode(SLC_ADDRESS)) { + String flowPath = realizedFlowNode.getNode(SLC_ADDRESS) + .getProperty(Property.JCR_PATH).getString(); + // TODO: convert to local path if remote + // FIXME start related module + Node flowNode = realizedFlowNode.getSession().getNode(flowPath); + String flowName = flowNode.getProperty(SLC_NAME).getString(); + String description = null; + if (flowNode.hasProperty(Property.JCR_DESCRIPTION)) + description = flowNode.getProperty(Property.JCR_DESCRIPTION) + .getString(); + + Node executionModuleNode = flowNode.getSession().getNode( + SlcJcrUtils.modulePath(flowPath)); + String executionModuleName = executionModuleNode.getProperty( + SLC_NAME).getString(); + String executionModuleVersion = executionModuleNode.getProperty( + SLC_VERSION).getString(); + + RealizedFlow realizedFlow = this; + realizedFlow.setModuleName(executionModuleName); + realizedFlow.setModuleVersion(executionModuleVersion); + + // retrieve execution spec + DefaultExecutionSpec executionSpec = new DefaultExecutionSpec(); + Map attrs = readExecutionSpecAttributes(realizedFlowNode); + executionSpec.setAttributes(attrs); + + // set execution spec name + if (flowNode.hasProperty(SlcNames.SLC_SPEC)) { + Node executionSpecNode = flowNode.getProperty(SLC_SPEC) + .getNode(); + executionSpec.setBeanName(executionSpecNode.getProperty( + SLC_NAME).getString()); + } + + // explicitly retrieve values + Map values = new HashMap(); + for (String attrName : attrs.keySet()) { + ExecutionSpecAttribute attr = attrs.get(attrName); + Object value = attr.getValue(); + values.put(attrName, value); + } + + ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(flowName, + description, values, executionSpec); + realizedFlow.setFlowDescriptor(efd); + } else { + throw new SlcException("Unsupported realized flow " + + realizedFlowNode); + } + } + + protected Map readExecutionSpecAttributes( + Node node) { + try { + Map attrs = new HashMap(); + for (NodeIterator nit = node.getNodes(); nit.hasNext();) { + Node specAttrNode = nit.nextNode(); + if (specAttrNode + .isNodeType(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE)) { + String type = specAttrNode.getProperty(SLC_TYPE) + .getString(); + Object value = null; + if (specAttrNode.hasProperty(SLC_VALUE)) { + String valueStr = specAttrNode.getProperty(SLC_VALUE) + .getString(); + value = PrimitiveUtils.convert(type, valueStr); + } + PrimitiveSpecAttribute specAttr = new PrimitiveSpecAttribute( + type, value); + attrs.put(specAttrNode.getName(), specAttr); + } else if (specAttrNode + .isNodeType(SlcTypes.SLC_REF_SPEC_ATTRIBUTE)) { + if (!specAttrNode.hasProperty(SLC_VALUE)) { + continue; + } + Integer value = (int) specAttrNode.getProperty(SLC_VALUE) + .getLong(); + RefSpecAttribute specAttr = new RefSpecAttribute(); + NodeIterator children = specAttrNode.getNodes(); + int index = 0; + String id = null; + while (children.hasNext()) { + Node child = children.nextNode(); + if (index == value) + id = child.getName(); + index++; + } + specAttr.setValue(id); + attrs.put(specAttrNode.getName(), specAttr); + } + // throw new SlcException("Unsupported spec attribute " + // + specAttrNode); + } + return attrs; + } catch (RepositoryException e) { + throw new SlcException("Cannot read spec attributes from " + node, + e); + } + } + + public String getPath() { + return path; + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/jcr/slc.cnd b/org.argeo.slc.core/src/org/argeo/slc/jcr/slc.cnd new file mode 100644 index 000000000..6e23cf5e9 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/jcr/slc.cnd @@ -0,0 +1,139 @@ + + +// COMMON +[slc:nameVersion] > nt:base +mixin +- slc:name (STRING) m +- slc:version (STRING) m + +[slc:categorizedNameVersion] > slc:nameVersion +mixin +// define as mandatory? +- slc:category (STRING) + +// AGENT +[slc:agentFactory] > nt:unstructured, mix:title ++ * (slc:agent) + +[slc:agent] > nt:unstructured, mix:title ++ * (slc:module) + +[slc:module] > slc:nameVersion, mix:title +mixin + +[slc:activableModule] > slc:module +mixin + +[slc:executionModule] > slc:activableModule +mixin + +[slc:executionSpec] > nt:unstructured, mix:referenceable, mix:title +- slc:name (STRING) m ++ * (slc:executionSpecAttribute) * + +[slc:executionSpecAttribute] > nt:base +mixin abstract +- slc:isImmutable (BOOLEAN) +- slc:isConstant (BOOLEAN) +- slc:isHidden (BOOLEAN) + +[slc:primitiveSpecAttribute] > slc:executionSpecAttribute +mixin +- slc:type (STRING) +- slc:value (UNDEFINED) + +[slc:refSpecAttribute] > slc:executionSpecAttribute +orderable +mixin +// typically a class name +- slc:type (STRING) +- slc:value (UNDEFINED) ++ * (mix:title) + +[slc:executionFlow] > nt:unstructured, mix:title +- slc:name (STRING) ! m +// if the execution spec is a referenceable node +- slc:spec (REFERENCE) +// if the execution spec is internal (without name) ++ * (slc:executionSpecAttribute) * + +// PROCESS +[slc:process] > nt:unstructured, mix:created, mix:lastModified +orderable +- slc:uuid (STRING) ! m +- slc:status (STRING) m ++ slc:flow (slc:realizedFlow) ++ slc:log + +// The first part of the relative path is the thread name, rest is location +[slc:logEntry] > nt:unstructured +abstract +- slc:message (STRING) ! +- slc:timestamp (STRING) + +// Log levels are set via types. +// Querying one level also queries the higher levels thanks to the inheritance +// e.g. 'select * from [slc:logWarn]' also returns errors +[slc:logTrace] > slc:logEntry + +[slc:logDebug] > slc:logTrace + +[slc:logInfo] > slc:logDebug + +[slc:logWarning] > slc:logInfo + +[slc:logError] > slc:logWarning + +[slc:realizedFlow] > nt:base +orderable +mixin +// the name of the flow +// - slc:flow (STRING) +// the name of the execution spec +// - slc:spec (STRING) +- slc:started (DATE) +- slc:completed (DATE) +//- slc:status (STRING) ++ slc:address (nt:address) ++ slc:flow (slc:realizedFlow) * +// the realized execution spec attributes ++ * (slc:executionSpecAttribute) * + +// RESULT +[slc:testResult] > nt:unstructured, mix:created, mix:lastModified +- slc:uuid (STRING) ! m +- slc:testCase (STRING) +- slc:completed (DATE) +// Helper to keep a centralize place to have testResultStatus +// when adding more than one result part to a given testResult ++ slc:aggregatedStatus (slc:check) +// DEPRECATED - FOR COMPATIBILITY - DO NOT USE ++ slc:testStatus (slc:check) + +[slc:diffResult] > slc:testResult ++ slc:summary ++ slc:issues + +[slc:resultFolder] > nt:unstructured ++ slc:folderStatus (slc:check) ++ * (slc:resultFolder) * ++ * (slc:testResult) * + +// base node for user defined and managed result tree +// simplify UI management +[slc:myResultRootFolder] > nt:unstructured ++ * (slc:resultFolder) * ++ * (slc:testResult) * + +[slc:check] > nt:unstructured +// true for PASSED, false for FAILED or ERROR +- slc:success (BOOLEAN) ! m +- slc:message (STRING) +// ERROR if set, the check could not be performed because of an unexpected exception +- slc:errorMessage (STRING) +// to ease transition with legacy approach ++ * (slc:property) * + +[slc:property] > nt:unstructured +- slc:name (STRING) ! m +- slc:value (STRING) m diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/BundleRegister.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/BundleRegister.java new file mode 100644 index 000000000..747785fee --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/BundleRegister.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +/** Experimental A structured set of OSGi bundles. */ +public interface BundleRegister { + /** + * @param pkg + * the Java package + * @param version + * the version, can be only major.minor or null + * @return the bundle providing this package or null if none was found + */ + public String bundleProvidingPackage(String pkg, String version); +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/BundlesManager.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/BundlesManager.java new file mode 100644 index 000000000..8c975eeef --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/BundlesManager.java @@ -0,0 +1,441 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.osgi.framework.Constants; +import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.FrameworkListener; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.packageadmin.PackageAdmin; +import org.osgi.util.tracker.ServiceTracker; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.eclipse.gemini.blueprint.context.BundleContextAware; +import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextEvent; +import org.eclipse.gemini.blueprint.context.event.OsgiBundleApplicationContextListener; +import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextClosedEvent; +import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextFailedEvent; +import org.eclipse.gemini.blueprint.context.event.OsgiBundleContextRefreshedEvent; +import org.eclipse.gemini.blueprint.util.OsgiBundleUtils; +import org.eclipse.gemini.blueprint.util.OsgiFilterUtils; +import org.springframework.util.Assert; + +/** Wraps low-level access to a {@link BundleContext} */ +public class BundlesManager implements BundleContextAware, FrameworkListener, + InitializingBean, DisposableBean, OsgiBundleApplicationContextListener { + private final static Log log = LogFactory.getLog(BundlesManager.class); + + private BundleContext bundleContext; + + private Long defaultTimeout = 60 * 1000l; + private Long pollingPeriod = 200l; + + // Refresh sync objects + private final Object refreshedPackageSem = new Object(); + private Boolean packagesRefreshed = false; + + public BundlesManager() { + } + + public BundlesManager(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + /** + * Stop the module, update it, refresh it and restart it. All synchronously. + */ + public void upgradeSynchronous(OsgiBundle osgiBundle) { + try { + Bundle bundle = findRelatedBundle(osgiBundle); + + long begin = System.currentTimeMillis(); + + long bStop = begin; + stopSynchronous(bundle); + + long bUpdate = System.currentTimeMillis(); + updateSynchronous(bundle); + + // Refresh in case there are fragments + long bRefresh = System.currentTimeMillis(); + refreshSynchronous(bundle); + + long bStart = System.currentTimeMillis(); + startSynchronous(bundle); + + long aStart = System.currentTimeMillis(); + if (log.isTraceEnabled()) { + log.debug("OSGi upgrade performed in " + (aStart - begin) + + "ms for bundle " + osgiBundle); + log.debug(" stop \t: " + (bUpdate - bStop) + "ms"); + log.debug(" update\t: " + (bRefresh - bUpdate) + "ms"); + log.debug(" refresh\t: " + (bStart - bRefresh) + "ms"); + log.debug(" start\t: " + (aStart - bStart) + "ms"); + log.debug(" TOTAL\t: " + (aStart - begin) + "ms"); + } + + long bAppContext = System.currentTimeMillis(); + String filter = "(Bundle-SymbolicName=" + bundle.getSymbolicName() + + ")"; + // Wait for application context to be ready + // TODO: use service tracker + ServiceReference[] srs = getServiceRefSynchronous( + ApplicationContext.class.getName(), filter); + ServiceReference sr = srs[0]; + long aAppContext = System.currentTimeMillis(); + long end = aAppContext; + + if (log.isTraceEnabled()) { + log.debug("Application context refresh performed in " + + (aAppContext - bAppContext) + "ms for bundle " + + osgiBundle); + } + + if (log.isDebugEnabled()) + log.debug("Bundle '" + bundle.getSymbolicName() + + "' upgraded and ready " + " (upgrade performed in " + + (end - begin) + "ms)."); + + if (log.isTraceEnabled()) { + ApplicationContext applicationContext = (ApplicationContext) bundleContext + .getService(sr); + int beanDefCount = applicationContext.getBeanDefinitionCount(); + log.debug(" " + beanDefCount + " beans in app context of " + + bundle.getSymbolicName() + + ", average init time per bean=" + (end - begin) + / beanDefCount + "ms"); + } + + bundleContext.ungetService(sr); + + } catch (Exception e) { + throw new SlcException("Cannot update bundle " + osgiBundle, e); + } + } + + /** Updates bundle synchronously. */ + protected void updateSynchronous(Bundle bundle) throws BundleException { + bundle.update(); + boolean waiting = true; + + long begin = System.currentTimeMillis(); + do { + int state = bundle.getState(); + if (state == Bundle.INSTALLED || state == Bundle.ACTIVE + || state == Bundle.RESOLVED) + waiting = false; + + sleepWhenPolling(); + checkTimeout(begin, "Update of bundle " + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isTraceEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " updated."); + } + + /** Starts bundle synchronously. Does nothing if already started. */ + protected void startSynchronous(Bundle bundle) throws BundleException { + int originalState = bundle.getState(); + if (originalState == Bundle.ACTIVE) + return; + + bundle.start(); + boolean waiting = true; + + long begin = System.currentTimeMillis(); + do { + if (bundle.getState() == Bundle.ACTIVE) + waiting = false; + + sleepWhenPolling(); + checkTimeout(begin, "Start of bundle " + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isTraceEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " started."); + } + + /** Stops bundle synchronously. Does nothing if already started. */ + protected void stopSynchronous(Bundle bundle) throws BundleException { + int originalState = bundle.getState(); + if (originalState != Bundle.ACTIVE) + return; + + bundle.stop(); + boolean waiting = true; + + long begin = System.currentTimeMillis(); + do { + if (bundle.getState() != Bundle.ACTIVE + && bundle.getState() != Bundle.STOPPING) + waiting = false; + + sleepWhenPolling(); + checkTimeout(begin, "Stop of bundle " + bundle.getSymbolicName() + + " timed out. Bundle state = " + bundle.getState()); + } while (waiting); + + if (log.isTraceEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " stopped."); + } + + /** Refresh bundle synchronously. Does nothing if already started. */ + protected void refreshSynchronous(Bundle bundle) throws BundleException { + ServiceReference packageAdminRef = bundleContext + .getServiceReference(PackageAdmin.class.getName()); + PackageAdmin packageAdmin = (PackageAdmin) bundleContext + .getService(packageAdminRef); + Bundle[] bundles = { bundle }; + + long begin = System.currentTimeMillis(); + synchronized (refreshedPackageSem) { + packagesRefreshed = false; + packageAdmin.refreshPackages(bundles); + try { + refreshedPackageSem.wait(defaultTimeout); + } catch (InterruptedException e) { + // silent + } + if (!packagesRefreshed) { + long now = System.currentTimeMillis(); + throw new SlcException("Packages not refreshed after " + + (now - begin) + "ms"); + } else { + packagesRefreshed = false; + } + } + + if (log.isTraceEnabled()) + log.debug("Bundle " + bundle.getSymbolicName() + " refreshed."); + } + + public void frameworkEvent(FrameworkEvent event) { + if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) { + synchronized (refreshedPackageSem) { + packagesRefreshed = true; + refreshedPackageSem.notifyAll(); + } + } + } + + public ServiceReference[] getServiceRefSynchronous(String clss, + String filter) throws InvalidSyntaxException { + if (log.isTraceEnabled()) + log.debug("Filter: '" + filter + "'"); + ServiceReference[] sfs = null; + boolean waiting = true; + long begin = System.currentTimeMillis(); + do { + sfs = bundleContext.getServiceReferences(clss, filter); + + if (sfs != null) + waiting = false; + + sleepWhenPolling(); + checkTimeout(begin, "Search of services " + clss + " with filter " + + filter + " timed out."); + } while (waiting); + + return sfs; + } + + protected void checkTimeout(long begin, String msg) { + long now = System.currentTimeMillis(); + if (now - begin > defaultTimeout) + throw new SlcException(msg + " (timeout after " + (now - begin) + + "ms)"); + + } + + protected void sleepWhenPolling() { + try { + Thread.sleep(pollingPeriod); + } catch (InterruptedException e) { + throw new SlcException("Polling interrupted"); + } + } + + /** Creates and open a new service tracker. */ + public ServiceTracker newTracker(Class clss) { + ServiceTracker st = new ServiceTracker(bundleContext, clss.getName(), + null); + st.open(); + return st; + } + + @SuppressWarnings(value = { "unchecked" }) + public T getSingleService(Class clss, String filter, + Boolean synchronous) { + if (filter != null) + Assert.isTrue(OsgiFilterUtils.isValidFilter(filter), "valid filter"); + ServiceReference[] sfs; + try { + if (synchronous) + sfs = getServiceRefSynchronous(clss.getName(), filter); + else + sfs = bundleContext + .getServiceReferences(clss.getName(), filter); + } catch (InvalidSyntaxException e) { + throw new SlcException("Cannot retrieve service reference for " + + filter, e); + } + + if (sfs == null || sfs.length == 0) + return null; + else if (sfs.length > 1) + throw new SlcException("More than one execution flow found for " + + filter); + return (T) bundleContext.getService(sfs[0]); + } + + public T getSingleServiceStrict(Class clss, String filter, + Boolean synchronous) { + T service = getSingleService(clss, filter, synchronous); + if (service == null) + throw new SlcException("No execution flow found for " + filter); + else + return service; + } + + public OsgiBundle findRelatedBundle(String moduleName, String moduleVersion) { + OsgiBundle osgiBundle = new OsgiBundle(moduleName, moduleVersion); + if (osgiBundle.getVersion() == null) { + Bundle bundle = findRelatedBundle(osgiBundle); + osgiBundle = new OsgiBundle(bundle); + } + return osgiBundle; + } + + /** + * @param osgiBundle + * cannot be null + * @return the related bundle or null if not found + * @throws SlcException + * if osgiBundle argument is null + */ + public Bundle findRelatedBundle(OsgiBundle osgiBundle) { + if (osgiBundle == null) + throw new SlcException("OSGi bundle cannot be null"); + + Bundle bundle = null; + if (osgiBundle.getInternalBundleId() != null) { + bundle = bundleContext.getBundle(osgiBundle.getInternalBundleId()); + Assert.isTrue( + osgiBundle.getName().equals(bundle.getSymbolicName()), + "symbolic name consistent"); + if (osgiBundle.getVersion() != null) + Assert.isTrue( + osgiBundle.getVersion().equals( + bundle.getHeaders().get( + Constants.BUNDLE_VERSION)), + "version consistent"); + } else if (osgiBundle.getVersion() == null + || osgiBundle.getVersion().equals("0.0.0")) { + bundle = OsgiBundleUtils.findBundleBySymbolicName(bundleContext, + osgiBundle.getName()); + } else {// scan all bundles + bundles: for (Bundle b : bundleContext.getBundles()) { + if (b.getSymbolicName() == null) { + log.warn("Bundle " + b + " has no symbolic name defined."); + continue bundles; + } + + if (b.getSymbolicName().equals(osgiBundle.getName())) { + if (osgiBundle.getVersion() == null) { + bundle = b; + break bundles; + } + + if (b.getHeaders().get(Constants.BUNDLE_VERSION) + .equals(osgiBundle.getVersion())) { + bundle = b; + osgiBundle.setInternalBundleId(b.getBundleId()); + break bundles; + } + } + } + } + return bundle; + } + + /** Find a single bundle based on a symbolic name pattern. */ + public OsgiBundle findFromPattern(String pattern) { + OsgiBundle osgiBundle = null; + for (Bundle b : bundleContext.getBundles()) { + if (b.getSymbolicName().contains(pattern)) { + osgiBundle = new OsgiBundle(b); + break; + } + } + return osgiBundle; + } + + public OsgiBundle getBundle(Long bundleId) { + Bundle bundle = bundleContext.getBundle(bundleId); + return new OsgiBundle(bundle); + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + public void afterPropertiesSet() throws Exception { + bundleContext.addFrameworkListener(this); + } + + public void destroy() throws Exception { + bundleContext.removeFrameworkListener(this); + } + + public void setDefaultTimeout(Long defaultTimeout) { + this.defaultTimeout = defaultTimeout; + } + + /** + * Use with caution since it may interfer with some cached information + * within this object + */ + public BundleContext getBundleContext() { + return bundleContext; + } + + public void setPollingPeriod(Long pollingPeriod) { + this.pollingPeriod = pollingPeriod; + } + + public void onOsgiApplicationEvent(OsgiBundleApplicationContextEvent event) { + if (event instanceof OsgiBundleContextRefreshedEvent) { + log.debug("App context refreshed: " + event); + } else if (event instanceof OsgiBundleContextFailedEvent) { + log.debug("App context failed: " + event); + } + if (event instanceof OsgiBundleContextClosedEvent) { + log.debug("App context closed: " + event); + } + + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/FileSystemBundleRegister.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/FileSystemBundleRegister.java new file mode 100644 index 000000000..a068a4f8c --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/FileSystemBundleRegister.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import java.io.File; +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.framework.Constants; + +/** Experimental */ +public class FileSystemBundleRegister implements BundleRegister { + private final static Log log = LogFactory + .getLog(FileSystemBundleRegister.class); + private Properties packagesBundles = null; + + public String bundleProvidingPackage(String pkg, String version) { + if (packagesBundles == null) + return null; + return packagesBundles.getProperty(pkg); + } + + protected void scan(File baseDirectory) { + long begin = System.currentTimeMillis(); + int bundleCount = 0; + int packageCount = 0; + + packagesBundles = new Properties(); + + File[] files = baseDirectory.listFiles(); + for (File file : files) { + if (file.isDirectory()) { + + } else { + try { + JarFile jarFile = new JarFile(file); + Manifest manifest = jarFile.getManifest(); + String symbolicName = manifest.getMainAttributes() + .getValue(Constants.BUNDLE_SYMBOLICNAME); + String exportPackage = manifest.getMainAttributes() + .getValue(Constants.EXPORT_PACKAGE); + + // List exported packages + Set exportedPackages = exportPackageToPackageNames(exportPackage); + + for (String exportedPackage : exportedPackages) { + packagesBundles.put(exportedPackage, symbolicName); + packageCount++; + if (log.isTraceEnabled()) + log.trace("Register " + exportedPackage + "=" + + symbolicName); + } + bundleCount++; + } catch (Exception e) { + log.warn("Cannot scan " + file, e); + if (log.isTraceEnabled()) + e.printStackTrace(); + } + } + } + if (log.isDebugEnabled()) + log.debug("Scanned " + bundleCount + " bundles with " + + packageCount + " packages in " + + (System.currentTimeMillis() - begin) + " ms"); + } + + protected Set exportPackageToPackageNames(String exportPackage) { + Set exportedPackages = new HashSet(); + if (exportPackage == null) + return exportedPackages; + char[] arr = exportPackage.toCharArray(); + + StringBuffer currentPkg = new StringBuffer(""); + boolean skip = false; + boolean inQuote = false; + for (char c : arr) { + if (c == ' ' || c == '\n') { + // ignore + } else if (c == ';') { + if (!skip) + skip = true; + } else if (c == ',') { + if (skip && !inQuote) { + skip = false; + // add new package + exportedPackages.add(currentPkg.toString()); + currentPkg = new StringBuffer(""); + } + } else if (c == '\"') { + inQuote = inQuote ? false : true; + } else { + if (!skip) + currentPkg.append(c); + } + } + + return exportedPackages; + } + + public static void main(String[] args) { + FileSystemBundleRegister fsbr = new FileSystemBundleRegister(); + fsbr.scan(new File( + "/home/mbaudier/dev/src/slc/dist/org.argeo.slc.sdk/target/lib")); + + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/MultipleServiceExporterPostProcessor.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/MultipleServiceExporterPostProcessor.java new file mode 100644 index 000000000..2d8b0311c --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/MultipleServiceExporterPostProcessor.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.core.Ordered; + +/** Publishes beans of the application context as OSGi services. */ +@SuppressWarnings(value = { "unchecked", "rawtypes" }) +public class MultipleServiceExporterPostProcessor implements + ApplicationListener, Ordered { + private final static Log log = LogFactory + .getLog(MultipleServiceExporterPostProcessor.class); + + private List interfaces = new ArrayList(); + + private int order = Ordered.LOWEST_PRECEDENCE; + + private BundleContext bundleContext = null; + + // private Class osgiServiceFactoryClass = OsgiServiceFactoryBean.class; + // private Boolean useServiceProviderContextClassLoader = false; + + public void onApplicationEvent(ApplicationEvent event) { + Map beans = new HashMap(); + if (event instanceof ContextRefreshedEvent) { + if (bundleContext != null) { + for (Class clss : interfaces) { + ApplicationContext ac = ((ContextRefreshedEvent) event) + .getApplicationContext(); + beans.putAll(ac.getBeansOfType(clss, false, false)); + } + + int count = 0; + for (String beanName : beans.keySet()) { + Object bean = beans.get(beanName); + List classes = new ArrayList(); + for (Class clss : interfaces) { + if (clss.isAssignableFrom(bean.getClass())) { + classes.add(clss.getName()); + } + } + Properties props = new Properties(); + Bundle bundle = bundleContext.getBundle(); + props.put(Constants.BUNDLE_SYMBOLICNAME, + bundle.getSymbolicName()); + props.put(Constants.BUNDLE_VERSION, bundle.getVersion()); + // retrocompatibility with pre-1.0: + props.put("org.eclipse.gemini.blueprint.bean.name", beanName); + bundleContext.registerService( + classes.toArray(new String[classes.size()]), bean, + new Hashtable(props)); + count++; + } + if (log.isTraceEnabled()) + log.trace("Published " + count + " " + interfaces + + " as OSGi services from bundle " + + bundleContext.getBundle().getSymbolicName() + " " + + bundleContext.getBundle().getVersion()); + // note: the services will be automatically unregistered when + // the bundle will be stopped + } + } + } + + // public void postProcessBeanFactory( + // ConfigurableListableBeanFactory beanFactory) throws BeansException { + // if (!(beanFactory instanceof BeanDefinitionRegistry)) { + // throw new SlcException("Can only work on " + // + BeanDefinitionRegistry.class); + // } + // + // long begin = System.currentTimeMillis(); + // + // // Merge all beans implementing these interfaces + // Set beanNames = new HashSet(); + // for (Class clss : interfaces) { + // String[] strs = beanFactory.getBeanNamesForType(clss, true, false); + // beanNames.addAll(Arrays.asList(strs)); + // } + // + // // Register service factory beans for them + // for (String beanName : beanNames) { + // MutablePropertyValues mpv = new MutablePropertyValues(); + // mpv.addPropertyValue("interfaces", interfaces.toArray()); + // mpv.addPropertyValue("targetBeanName", beanName); + // if (useServiceProviderContextClassLoader) + // mpv.addPropertyValue("contextClassLoader", + // ExportContextClassLoader.SERVICE_PROVIDER); + // RootBeanDefinition bd = new RootBeanDefinition( + // osgiServiceFactoryClass, mpv); + // + // String exporterBeanName = "osgiService." + beanName; + // if (log.isTraceEnabled()) + // log.debug("Registering OSGi service exporter " + // + exporterBeanName); + // ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition( + // exporterBeanName, bd); + // } + // + // long end = System.currentTimeMillis(); + // if (log.isTraceEnabled()) + // log.debug("Multiple services exported in " + (end - begin) + // + " ms in bundle."); + // + // } + + public void setInterfaces(List interfaces) { + this.interfaces = interfaces; + } + + // public void setOsgiServiceFactoryClass(Class osgiServiceFactoryClass) { + // this.osgiServiceFactoryClass = osgiServiceFactoryClass; + // } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + // public void setUseServiceProviderContextClassLoader( + // Boolean useServiceProviderContextClassLoader) { + // this.useServiceProviderContextClassLoader = + // useServiceProviderContextClassLoader; + // } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiBundle.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiBundle.java new file mode 100644 index 000000000..cb11615b6 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiBundle.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import org.argeo.slc.DefaultNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.core.build.ResourceDistribution; +import org.argeo.slc.deploy.DeploymentData; +import org.argeo.slc.deploy.Module; +import org.argeo.slc.deploy.ModuleDescriptor; +import org.argeo.slc.deploy.TargetData; +import org.argeo.slc.execution.RealizedFlow; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; +import org.springframework.core.io.Resource; + +/** A deployed OSGi bundle. */ +public class OsgiBundle extends DefaultNameVersion implements Module { + private ResourceDistribution distribution; + + private Long internalBundleId; + + private String title; + private String description; + + public OsgiBundle() { + + } + + public OsgiBundle(String name, String version) { + super(name, version); + } + + public OsgiBundle(NameVersion nameVersion) { + super(nameVersion); + } + + public OsgiBundle(Bundle bundle) { + super(bundle.getSymbolicName(), getVersionSafe(bundle)); + internalBundleId = bundle.getBundleId(); + } + + /** + * Initialize from a {@link RealizedFlow}. + * + * @deprecated introduce an unnecessary dependency. TODO: create a separate + * helper. + */ + public OsgiBundle(RealizedFlow realizedFlow) { + super(realizedFlow.getModuleName(), realizedFlow.getModuleVersion()); + } + + /** Utility to avoid NPE. */ + private static String getVersionSafe(Bundle bundle) { + Object versionObj = bundle.getHeaders().get(Constants.BUNDLE_VERSION); + if (versionObj != null) + return versionObj.toString(); + else + return null; + } + + /** Unique deployed system id. TODO: use internal bundle id when available? */ + public String getDeployedSystemId() { + return getName() + ":" + getVersion(); + } + + /** + * OSGi bundle are self-contained and do not require additional deployment + * data. + * + * @return always null + */ + public DeploymentData getDeploymentData() { + return null; + } + + /** The related distribution. */ + public Distribution getDistribution() { + return distribution; + } + + /** + * The related distribution, a jar file with OSGi metadata referenced by a + * {@link Resource}. + */ + public ResourceDistribution getResourceDistribution() { + return distribution; + } + + /** TODO: reference the {@link OsgiRuntime} as target data? */ + public TargetData getTargetData() { + throw new UnsupportedOperationException(); + } + + public void setResourceDistribution(ResourceDistribution distribution) { + this.distribution = distribution; + } + + /** + * Bundle ID used by the OSGi runtime. To be used for optimization when + * looking in the bundle context. Can therefore be null. + */ + public Long getInternalBundleId() { + return internalBundleId; + } + + /** Only package access for the time being. e.g. from {@link BundlesManager} */ + void setInternalBundleId(Long internalBundleId) { + this.internalBundleId = internalBundleId; + } + + /** Value of the Bundle-Name directive. */ + public String getTitle() { + return title; + } + + public void setTitle(String label) { + this.title = label; + } + + /** Value of the Bundle-Description directive. */ + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ModuleDescriptor getModuleDescriptor() { + ModuleDescriptor moduleDescriptor = new ModuleDescriptor(); + moduleDescriptor.setName(getName()); + moduleDescriptor.setVersion(getVersion()); + moduleDescriptor.setDescription(description); + moduleDescriptor.setTitle(title); + return moduleDescriptor; + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModule.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModule.java new file mode 100644 index 000000000..df7ae9bc1 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModule.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.core.execution.AbstractSpringExecutionModule; +import org.argeo.slc.execution.ExecutionContext; + +@Deprecated +public class OsgiExecutionModule extends AbstractSpringExecutionModule { + private final static Log log = LogFactory.getLog(OsgiExecutionModule.class); + + public OsgiExecutionModule() { + log.error("######## ERROR - DEPRECATED APPROACH USED ########"); + log.error(OsgiExecutionModule.class.getName() + " is deprecated. "); + log + .error("It will be removed in the next release. Remove its bean definition."); + log + .error("And replace: "); + log + .error("by: "); + log.error("in osgi.xml.\n\n"); + } + + public void setExecutionContext(ExecutionContext executionContext) { + // do nothing, just for compatibility + } + + /* + * private BundleContext bundleContext; + * + * @Override public void execute(ExecutionFlowDescriptor + * executionFlowDescriptor) { if (descriptorConverter != null) + * executionContext.addVariables(descriptorConverter + * .convertValues(executionFlowDescriptor)); + * + * ExecutionFlow flow = findExecutionFlow(getName(), getVersion(), + * executionFlowDescriptor.getName()); flow.run(); } + * + * @Override protected Map listFlows() { String + * filter = "(org.argeo.slc.execution.module.name=" + getName() + ")"; + * ServiceReference[] sfs; try { sfs = + * bundleContext.getServiceReferences(ExecutionFlow.class .getName(), + * filter); } catch (InvalidSyntaxException e) { throw new SlcException( + * "Cannot retrieve service reference for flow " + filter, e); } + * + * Map flows = new HashMap(); + * for (ServiceReference sf : sfs) { ExecutionFlow flow = (ExecutionFlow) + * bundleContext.getService(sf); flows.put(flow.getName(), flow); } return + * flows; } + * + * public String getName() { return + * bundleContext.getBundle().getSymbolicName(); } + * + * public String getVersion() { return + * bundleContext.getBundle().getHeaders().get("Bundle-Version") .toString(); + * } + * + * public void setBundleContext(BundleContext bundleContext) { + * this.bundleContext = bundleContext; } + * + * protected ExecutionFlow findExecutionFlow(String moduleName, String + * moduleVersion, String flowName) { String filter = + * "(&(org.argeo.slc.execution.module.name=" + moduleName + + * ")(org.argeo.slc.execution.flow.name=" + flowName + "))"; + * log.debug("OSGi filter: " + filter); + * + * Assert.isTrue(OsgiFilterUtils.isValidFilter(filter), "valid filter"); + * ServiceReference[] sfs; try { sfs = + * bundleContext.getServiceReferences(ExecutionFlow.class .getName(), + * filter); } catch (InvalidSyntaxException e) { throw new + * SlcException("Cannot retrieve service reference for " + filter, e); } + * + * if (sfs == null || sfs.length == 0) throw new + * SlcException("No execution flow found for " + filter); else if + * (sfs.length > 1) throw new + * SlcException("More than one execution flow found for " + filter); return + * (ExecutionFlow) bundleContext.getService(sfs[0]); } + */ + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java new file mode 100644 index 000000000..68fcead71 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java @@ -0,0 +1,696 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.DefaultNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.AbstractExecutionModulesManager; +import org.argeo.slc.core.execution.DefaultExecutionFlowDescriptorConverter; +import org.argeo.slc.deploy.Module; +import org.argeo.slc.deploy.ModuleDescriptor; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionFlowDescriptor; +import org.argeo.slc.execution.ExecutionFlowDescriptorConverter; +import org.argeo.slc.execution.ExecutionModuleDescriptor; +import org.argeo.slc.execution.ExecutionModulesListener; +import org.argeo.slc.execution.RealizedFlow; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleEvent; +import org.osgi.framework.BundleException; +import org.osgi.framework.BundleListener; +import org.osgi.framework.Constants; +import org.osgi.framework.launch.Framework; +import org.springframework.context.ApplicationContext; +import org.eclipse.gemini.blueprint.service.importer.OsgiServiceLifecycleListener; + +/** Execution modules manager implementation based on an OSGi runtime. */ +public class OsgiExecutionModulesManager extends + AbstractExecutionModulesManager implements + OsgiServiceLifecycleListener, BundleListener { + + private final static Log log = LogFactory + .getLog(OsgiExecutionModulesManager.class); + + private BundlesManager bundlesManager; + private Map executionContexts = new HashMap(); + private Map executionFlowDescriptorConverters = new HashMap(); + private Map> executionFlows = new HashMap>(); + private ExecutionFlowDescriptorConverter defaultDescriptorConverter = new DefaultExecutionFlowDescriptorConverter(); + + private List executionModulesListeners = new ArrayList(); + + private Boolean registerFlowsToJmx = false; + + public void init() throws Exception { + bundlesManager.getBundleContext().addBundleListener(this); + + final String module = System.getProperty(UNIQUE_LAUNCH_MODULE_PROPERTY); + final String flow = System.getProperty(UNIQUE_LAUNCH_FLOW_PROPERTY); + if (module != null) { + // launch a flow and stops + new Thread("Unique Flow") { + @Override + public void run() { + executeFlowAndExit(module, null, flow); + } + }.start(); + } + } + + public void destroy() { + bundlesManager.getBundleContext().removeBundleListener(this); + } + + /** Executes a single flow and stops the JVM */ + protected void executeFlowAndExit(final String module, + final String version, final String flow) { + if (log.isDebugEnabled()) + log.debug("Launch unique flow " + flow + " from module " + module); + try { + OsgiBundle osgiBundle = bundlesManager.findFromPattern(module); + if (osgiBundle == null) + throw new SlcException("No OSGi bundle found for " + module); + // Bundle moduleBundle = + // bundlesManager.findRelatedBundle(osgiBundle); + start(osgiBundle); + + RealizedFlow lastLaunch = findRealizedFlow(module, flow); + if (lastLaunch == null) + throw new SlcException("Cannot find launch for " + module + " " + + flow); + execute(lastLaunch); + } catch (Exception e) { + log.error( + "Error in unique flow " + flow + " from module " + module, + e); + } finally { + if (log.isDebugEnabled()) + log.debug("Shutdown OSGi runtime..."); + Framework framework = (Framework) bundlesManager.getBundleContext() + .getBundle(0); + try { + // shutdown framework + framework.stop(); + // wait 1 min for shutdown + framework.waitForStop(60 * 1000); + // close VM + System.exit(0); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + } + + // public void startExectionModule(String moduleName, String moduleVersion) + // { + // try { + // ServiceReference[] sr = bundlesManager.getServiceRefSynchronous( + // ApplicationContext.class.getName(), + // "org.springframework.context.service.name=" + moduleName); + // // bundlesManager.startSynchronous(moduleBundle); + // if (sr == null || sr.length == 0) + // throw new SlcException( + // "Cannot find execution module application context " + // + moduleName); + // } catch (InvalidSyntaxException e) { + // throw new SlcException("Cannot start exeuction module " + // + moduleName, e); + // } + // } + + public synchronized ExecutionModuleDescriptor getExecutionModuleDescriptor( + String moduleName, String version) { + ExecutionModuleDescriptor md = new ExecutionModuleDescriptor(); + OsgiBundle osgiBundle = null; + DefaultNameVersion nameVersion = new DefaultNameVersion(moduleName, + version); + bundles: for (Iterator iterator = executionContexts + .keySet().iterator(); iterator.hasNext();) { + OsgiBundle ob = iterator.next(); + if (nameVersion.getVersion() != null) { + if (ob.equals(nameVersion)) { + osgiBundle = ob; + break bundles; + } + } else { + if (ob.getName().equals(nameVersion.getName())) { + osgiBundle = ob; + break bundles; + } + } + } + if (osgiBundle == null) + throw new SlcException("No execution module registered for " + + nameVersion); + md.setName(osgiBundle.getName()); + md.setVersion(osgiBundle.getVersion()); + md.setTitle(osgiBundle.getTitle()); + md.setDescription(osgiBundle.getDescription()); + + ExecutionFlowDescriptorConverter executionFlowDescriptorConverter = getExecutionFlowDescriptorConverter( + moduleName, version); + if (executionFlowDescriptorConverter == null) + throw new SlcException("No flow converter found."); + executionFlowDescriptorConverter.addFlowsToDescriptor(md, + listFlows(moduleName, version)); + return md; + } + + public synchronized List listExecutionModules() { + List descriptors = new ArrayList(); + + for (Iterator iterator = executionContexts.keySet() + .iterator(); iterator.hasNext();) { + OsgiBundle osgiBundle = iterator.next(); + ExecutionModuleDescriptor md = new ExecutionModuleDescriptor(); + setMetadataFromBundle(md, + bundlesManager.findRelatedBundle(osgiBundle)); + descriptors.add(md); + } + return descriptors; + } + + protected synchronized Map listFlows( + String moduleName, String moduleVersion) { + + Map flows = new HashMap(); + OsgiBundle key = bundlesManager.findRelatedBundle(moduleName, + moduleVersion); + if (!executionFlows.containsKey(key)) + return flows; + Set flowsT = executionFlows.get(key); + for (ExecutionFlow flow : flowsT) + flows.put(flow.getName(), flow); + return flows; + } + + protected ExecutionFlow findExecutionFlow(String moduleName, + String moduleVersion, String flowName) { + String filter = moduleVersion == null || moduleVersion.equals("0.0.0") ? "(&(Bundle-SymbolicName=" + + moduleName + + ")(org.eclipse.gemini.blueprint.bean.name=" + + flowName + "))" + : "(&(Bundle-SymbolicName=" + moduleName + ")(Bundle-Version=" + + moduleVersion + + ")(org.eclipse.gemini.blueprint.bean.name=" + flowName + + "))"; + return bundlesManager.getSingleServiceStrict(ExecutionFlow.class, + filter, true); + } + + protected ExecutionContext findExecutionContext(String moduleName, + String moduleVersion) { + String filter = moduleFilter(moduleName, moduleVersion); + return bundlesManager.getSingleServiceStrict(ExecutionContext.class, + filter, true); + } + + protected ExecutionFlowDescriptorConverter findExecutionFlowDescriptorConverter( + String moduleName, String moduleVersion) { + String filter = moduleFilter(moduleName, moduleVersion); + return bundlesManager.getSingleService( + ExecutionFlowDescriptorConverter.class, filter, false); + } + + /** Only based on symbolic name if version is null or "0.0.0" */ + protected String moduleFilter(String moduleName, String moduleVersion) { + return moduleVersion == null || moduleVersion.equals("0.0.0") ? "(Bundle-SymbolicName=" + + moduleName + ")" + : "(&(Bundle-SymbolicName=" + moduleName + ")(Bundle-Version=" + + moduleVersion + "))"; + + } + + /** + * Builds a minimal realized flow, based on the provided information + * (typically from the command line). + * + * @param module + * a bundle id, or a pattern contained in a bundle symbolic name + * @param module + * the execution flow name + * @return a minimal realized flow, to be used in an execution + */ + public RealizedFlow findRealizedFlow(String module, String executionName) { + // First check whether we have a bundleId + Long bundleId = null; + try { + bundleId = Long.parseLong(module); + } catch (NumberFormatException e) { + // silent + } + + // Look for bundle names containing pattern + OsgiBundle bundle = null; + if (bundleId != null) { + bundle = bundlesManager.getBundle(bundleId); + } else { + bundle = bundlesManager.findFromPattern(module); + } + + if (bundle != null) { + RealizedFlow launch = new RealizedFlow(); + launch.setModuleName(bundle.getName()); + launch.setModuleVersion(bundle.getVersion()); + ExecutionFlowDescriptor descriptor = new ExecutionFlowDescriptor(); + descriptor.setName(executionName); + launch.setFlowDescriptor(descriptor); + return launch; + } else { + log.warn("Could not find any execution module matching these requirements."); + return null; + } + } + + public void upgrade(NameVersion nameVersion) { + OsgiBundle osgiBundle = new OsgiBundle(nameVersion); + bundlesManager.upgradeSynchronous(osgiBundle); + } + + protected synchronized ExecutionFlowDescriptorConverter getExecutionFlowDescriptorConverter( + String moduleName, String moduleVersion) { + return findExecutionFlowDescriptorConverter(moduleName, moduleVersion); + // OsgiBundle osgiBundle = new OsgiBundle(moduleName, moduleVersion); + // return getExecutionFlowDescriptorConverter(osgiBundle); + } + + protected synchronized ExecutionFlowDescriptorConverter getExecutionFlowDescriptorConverter( + OsgiBundle osgiBundle) { + if (executionFlowDescriptorConverters.containsKey(osgiBundle)) + return executionFlowDescriptorConverters.get(osgiBundle); + else + return defaultDescriptorConverter; + } + + public ModuleDescriptor getModuleDescriptor(String moduleName, + String version) { + return getExecutionModuleDescriptor(moduleName, version); + } + + public List listModules() { + Bundle[] bundles = bundlesManager.getBundleContext().getBundles(); + List lst = new ArrayList(); + for (Bundle bundle : bundles) { + ModuleDescriptor moduleDescriptor = new ModuleDescriptor(); + setMetadataFromBundle(moduleDescriptor, bundle); + lst.add(moduleDescriptor); + } + return lst; + } + + public void start(NameVersion nameVersion) { + try { + Bundle bundle = bundlesManager.findRelatedBundle(new OsgiBundle( + nameVersion)); + if (bundle == null) + throw new SlcException("Could not find bundle for " + + nameVersion); + + bundlesManager.startSynchronous(bundle); + if (isSpringInstrumented(bundle)) { + // Wait for Spring application context to be ready + String filter = "(Bundle-SymbolicName=" + + bundle.getSymbolicName() + ")"; + try { + bundlesManager.getServiceRefSynchronous( + ApplicationContext.class.getName(), filter); + } catch (Exception e) { + // stop if application context not found + bundle.stop(); + throw e; + } + } + } catch (Exception e) { + throw new SlcException("Cannot start " + nameVersion, e); + } + } + + /** Do it calmly in order to avoid NPE */ + private Boolean isSpringInstrumented(Bundle bundle) { + Dictionary headers = bundle.getHeaders(); + if (headers != null && headers.get("Spring-Context") != null) + return true; + Enumeration springEntryPaths = bundle + .getEntryPaths("/META-INF/spring"); + if (springEntryPaths != null && springEntryPaths.hasMoreElements()) + return true; + return false; + } + + public void stop(NameVersion nameVersion) { + try { + Bundle bundle = bundlesManager.findRelatedBundle(new OsgiBundle( + nameVersion)); + bundlesManager.stopSynchronous(bundle); + } catch (BundleException e) { + throw new SlcException("Cannot stop " + nameVersion, e); + } + } + + protected void setMetadataFromBundle(ModuleDescriptor md, Bundle bundle) { + Bundle bdl = bundle; + if (bdl == null) { + if (md.getName() == null || md.getVersion() == null) + throw new SlcException("Name and version not available."); + + Bundle[] bundles = bundlesManager.getBundleContext().getBundles(); + for (Bundle b : bundles) { + if (b.getSymbolicName().equals(md.getName()) + && md.getVersion().equals( + getHeaderSafe(b, Constants.BUNDLE_VERSION))) { + bdl = b; + break; + } + } + + } + + if (bdl == null) + throw new SlcException("Cannot find bundle."); + + md.setName(bdl.getSymbolicName()); + md.setVersion(getHeaderSafe(bdl, Constants.BUNDLE_VERSION)); + md.setTitle(getHeaderSafe(bdl, Constants.BUNDLE_NAME)); + md.setDescription(getHeaderSafe(bdl, Constants.BUNDLE_DESCRIPTION)); + + // copy manifets header to meta data + Dictionary headers = bundle.getHeaders(); + Enumeration keys = headers.keys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + Object value = headers.get(key); + if (value != null) + md.getMetadata().put(key.toString(), value.toString()); + } + + // check if started + if (bundle.getState() == Bundle.ACTIVE + || bundle.getState() == Bundle.STARTING) + md.setStarted(true); + else + md.setStarted(false); + } + + private String getHeaderSafe(Bundle bundle, Object key) { + Object obj = bundle.getHeaders().get(key); + if (obj == null) + return null; + else + return obj.toString(); + } + + /* + * REGISTRATION + */ + + /** Registers an execution context. */ + public synchronized void register(ExecutionContext executionContext, + Map properties) { + OsgiBundle osgiBundle = asOsgiBundle(properties); + Bundle bundle = bundlesManager.findRelatedBundle(osgiBundle); + osgiBundle.setTitle(getHeaderSafe(bundle, Constants.BUNDLE_NAME)); + osgiBundle.setDescription(getHeaderSafe(bundle, + Constants.BUNDLE_DESCRIPTION)); + executionContexts.put(osgiBundle, executionContext); + if (log.isTraceEnabled()) + log.trace("Registered execution context from " + osgiBundle); + // Notify + ModuleDescriptor md = osgiBundle.getModuleDescriptor(); + md.setStarted(true); + for (ExecutionModulesListener listener : executionModulesListeners) + listener.executionModuleAdded(md); + } + + /** Unregisters an execution context. */ + public synchronized void unregister(ExecutionContext executionContext, + Map properties) { + OsgiBundle osgiBundle = asOsgiBundle(properties); + if (executionContexts.containsKey(osgiBundle)) { + executionContexts.remove(osgiBundle); + if (log.isTraceEnabled()) + log.trace("Removed execution context from " + osgiBundle); + // Notify + ModuleDescriptor md = osgiBundle.getModuleDescriptor(); + md.setStarted(false); + for (ExecutionModulesListener listener : executionModulesListeners) + listener.executionModuleRemoved(md); + } + } + + /** Registers an execution flow. */ + public synchronized void register(ExecutionFlow executionFlow, + Map properties) { + OsgiBundle osgiBundle = asOsgiBundle(properties); + if (!executionFlows.containsKey(osgiBundle)) { + executionFlows.put(osgiBundle, new HashSet()); + } + executionFlows.get(osgiBundle).add(executionFlow); + if (log.isTraceEnabled()) + log.trace("Registered " + executionFlow + " from " + osgiBundle); + + // notifications + if (registerFlowsToJmx) + registerMBean(osgiBundle, executionFlow); + ExecutionFlowDescriptorConverter efdc = getExecutionFlowDescriptorConverter(osgiBundle); + for (ExecutionModulesListener listener : executionModulesListeners) + listener.executionFlowAdded(osgiBundle.getModuleDescriptor(), + efdc.getExecutionFlowDescriptor(executionFlow)); + } + + /** Unregisters an execution flow. */ + public synchronized void unregister(ExecutionFlow executionFlow, + Map properties) { + OsgiBundle osgiBundle = asOsgiBundle(properties); + if (executionFlows.containsKey(osgiBundle)) { + Set flows = executionFlows.get(osgiBundle); + flows.remove(executionFlow); + if (log.isTraceEnabled()) + log.trace("Removed " + executionFlow + " from " + osgiBundle); + if (flows.size() == 0) { + executionFlows.remove(osgiBundle); + if (log.isTraceEnabled()) + log.trace("Removed flows set from " + osgiBundle); + } + + // notifications + if (registerFlowsToJmx) + unregisterMBean(osgiBundle, executionFlow); + ExecutionFlowDescriptorConverter efdc = getExecutionFlowDescriptorConverter(osgiBundle); + for (ExecutionModulesListener listener : executionModulesListeners) + listener.executionFlowRemoved(osgiBundle.getModuleDescriptor(), + efdc.getExecutionFlowDescriptor(executionFlow)); + } + } + + /** Registers an execution module listener. */ + public synchronized void register( + ExecutionModulesListener executionModulesListener, + Map properties) { + // sync with current state + for (OsgiBundle osgiBundle : executionContexts.keySet()) { + executionModulesListener.executionModuleAdded(osgiBundle + .getModuleDescriptor()); + } + for (OsgiBundle osgiBundle : executionFlows.keySet()) { + ExecutionFlowDescriptorConverter efdc = getExecutionFlowDescriptorConverter(osgiBundle); + for (ExecutionFlow executionFlow : executionFlows.get(osgiBundle)) + executionModulesListener.executionFlowAdded( + osgiBundle.getModuleDescriptor(), + efdc.getExecutionFlowDescriptor(executionFlow)); + } + executionModulesListeners.add(executionModulesListener); + } + + /** Unregisters an execution module listener. */ + public synchronized void unregister( + ExecutionModulesListener executionModulesListener, + Map properties) { + executionModulesListeners.remove(executionModulesListener); + } + + /* + * INTERFACE IMPLEMENTATIONS + */ + + public void bundleChanged(BundleEvent evt) { + Bundle bundle = evt.getBundle(); + if (bundle.getHeaders().get( + ExecutionModuleDescriptor.SLC_EXECUTION_MODULE) != null) { + OsgiBundle osgiBundle = new OsgiBundle(bundle); + if (evt.getType() == BundleEvent.INSTALLED) + for (ExecutionModulesListener listener : executionModulesListeners) + listener.executionModuleAdded(osgiBundle + .getModuleDescriptor()); + else if (evt.getType() == BundleEvent.UNINSTALLED) + for (ExecutionModulesListener listener : executionModulesListeners) + listener.executionModuleRemoved(osgiBundle + .getModuleDescriptor()); + } + + } + + @SuppressWarnings({ "rawtypes" }) + public synchronized void bind(Object service, Map properties) + throws Exception { + if (service instanceof ExecutionFlowDescriptorConverter) { + ExecutionFlowDescriptorConverter executionFlowDescriptorConverter = (ExecutionFlowDescriptorConverter) service; + OsgiBundle osgiBundle = asOsgiBundle(properties); + executionFlowDescriptorConverters.put(osgiBundle, + executionFlowDescriptorConverter); + if (log.isTraceEnabled()) + log.debug("Registered execution flow descriptor converter from " + + osgiBundle); + } else { + // ignore + } + } + + @SuppressWarnings("rawtypes") + public synchronized void unbind(Object service, Map properties) + throws Exception { + if (service instanceof ExecutionFlowDescriptorConverter) { + OsgiBundle osgiBundle = asOsgiBundle(properties); + if (executionFlowDescriptorConverters.containsKey(osgiBundle)) { + executionFlowDescriptorConverters.remove(osgiBundle); + if (log.isTraceEnabled()) + log.debug("Removed execution flow descriptor converter from " + + osgiBundle); + } + } else { + // ignore + } + } + + /* + * JMX + */ + protected MBeanServer getMBeanServer() { + return ManagementFactory.getPlatformMBeanServer(); + } + + public void registerMBean(Module module, ExecutionFlow executionFlow) { + try { + StandardMBean mbean = new StandardMBean(executionFlow, + ExecutionFlow.class); + getMBeanServer().registerMBean(mbean, + flowMBeanName(module, executionFlow)); + } catch (Exception e) { + String msg = "Cannot register execution flow " + executionFlow + + " as mbean"; + throw new SlcException(msg, e); + } + } + + public void unregisterMBean(Module module, ExecutionFlow executionFlow) { + try { + getMBeanServer().unregisterMBean( + flowMBeanName(module, executionFlow)); + } catch (Exception e) { + String msg = "Cannot unregister execution flow " + executionFlow + + " as mbean"; + throw new SlcException(msg, e); + } + } + + @SuppressWarnings("deprecation") + protected ObjectName flowMBeanName(Module module, + ExecutionFlow executionFlow) { + String executionModulesPrefix = "SLCExecutionModules"; + String path = executionFlow.getPath(); + String name = executionFlow.getName(); + if (path == null && name.indexOf('/') >= 0) { + path = name.substring(0, name.lastIndexOf('/')); + name = name.substring(name.lastIndexOf('/')); + } + + StringBuffer buf = new StringBuffer(executionModulesPrefix + ":" + + "module=" + module.getName() + " [" + module.getVersion() + + "],"); + + if (path != null && !path.equals("")) { + int depth = 0; + for (String token : path.split("/")) { + if (!token.equals("")) { + buf.append("path").append(depth).append('='); + // in order to have directories first + buf.append('/'); + buf.append(token).append(','); + depth++; + } + } + } + buf.append("name=").append(name); + try { + return new ObjectName(buf.toString()); + } catch (Exception e) { + throw new SlcException("Cannot generate object name based on " + + buf, e); + } + } + + /* + * UTILITIES + */ + @SuppressWarnings("rawtypes") + private OsgiBundle asOsgiBundle(Map properties) { + String bundleSymbolicName = checkAndGet(Constants.BUNDLE_SYMBOLICNAME, + properties); + String bundleVersion = checkAndGet(Constants.BUNDLE_VERSION, properties); + return new OsgiBundle(bundleSymbolicName, bundleVersion); + } + + @SuppressWarnings("rawtypes") + private String checkAndGet(Object key, Map properties) { + if (!properties.containsKey(key) || properties.get(key) == null) + throw new SlcException(key + " not set in " + properties); + else + return properties.get(key).toString(); + } + + public void setBundlesManager(BundlesManager bundlesManager) { + this.bundlesManager = bundlesManager; + } + + public void setDefaultDescriptorConverter( + ExecutionFlowDescriptorConverter defaultDescriptorConverter) { + this.defaultDescriptorConverter = defaultDescriptorConverter; + } + + public void setRegisterFlowsToJmx(Boolean registerFlowsToJmx) { + this.registerFlowsToJmx = registerFlowsToJmx; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionResources.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionResources.java new file mode 100644 index 000000000..57f33cfc6 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionResources.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.FileExecutionResources; +import org.osgi.framework.BundleContext; +import org.springframework.core.io.Resource; +import org.eclipse.gemini.blueprint.context.BundleContextAware; +import org.eclipse.gemini.blueprint.io.OsgiBundleResource; + +/** Write access to resources in an OSGi context */ +public class OsgiExecutionResources extends FileExecutionResources implements + BundleContextAware { + private final static Log log = LogFactory + .getLog(OsgiExecutionResources.class); + + private BundleContext bundleContext; + + @Override + protected File fileFromResource(Resource resource) { + File file = super.fileFromResource(resource); + if (file != null) + return file; + + if (!(resource instanceof OsgiBundleResource)) + return null; + + OsgiBundleResource osgiBundleResource = (OsgiBundleResource) resource; + try { + return osgiBundleResource.getFile(); + } catch (IOException e) { + if (log.isTraceEnabled()) + log.trace("Resource " + resource + + " is not available on the file system: " + e); + } + + // TODO: ability to access resources in other bundles + String location = bundleContext.getBundle().getLocation(); + String base = null; + if (location.startsWith("reference:file:")) + base = location.substring("reference:file:".length()); + else if (location.startsWith("initial@reference:file:")) { + // TODO: Equinox specific? + String relPath = location.substring("initial@reference:file:" + .length()); + // if (relPath.startsWith("../"))// relative to the framework jar + // relPath = relPath.substring("../".length()); + // String framework = + // System.getProperty("osgi.framework").substring( + // "file:".length()); + // log.debug(framework); + String installArea = System.getProperty("osgi.install.area") + .substring("file:".length()); + // log.debug(installArea); + base = installArea + '/' + relPath; + // int sepIndex = framework.lastIndexOf(File.separatorChar); + // framework = framework.substring(0, sepIndex); + // base = framework + '/' + relPath; + } else { + return null; + } + + String path = base + '/' + osgiBundleResource.getPathWithinContext(); + try { + file = new File(path).getCanonicalFile(); + } catch (IOException e) { + throw new SlcException("Cannot determine canonical path for " + + path, e); + } + + if (!file.exists()) + throw new SlcException(file + + " was retrieved in bundle located at '" + location + + "' for resource " + resource + " but it does not exist"); + + if (log.isTraceEnabled()) + log.debug("OSGi local resource: " + file + " from " + resource); + return file; + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiRuntime.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiRuntime.java new file mode 100644 index 000000000..2414649cd --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiRuntime.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.StreamReadable; +import org.argeo.slc.UnsupportedException; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.core.build.VersionedResourceDistribution; +import org.argeo.slc.deploy.DeploymentData; +import org.argeo.slc.deploy.DynamicRuntime; +import org.argeo.slc.deploy.TargetData; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.eclipse.gemini.blueprint.context.BundleContextAware; + +public class OsgiRuntime implements BundleContextAware, ResourceLoaderAware, + DynamicRuntime { + private String uuid = UUID.randomUUID().toString(); + private BundleContext bundleContext; + private ResourceLoader resourceLoader; + + public List listModules() { + List modules = new ArrayList(); + Bundle[] bundles = bundleContext.getBundles(); + for (Bundle bundle : bundles) { + OsgiBundle osgiBundle = new OsgiBundle(bundle); + modules.add(osgiBundle); + String location = bundle.getLocation(); + if (location != null) { + Resource resource = resourceLoader.getResource(location); + osgiBundle + .setResourceDistribution(new VersionedResourceDistribution( + osgiBundle.getName(), osgiBundle.getVersion(), + resource)); + } + } + return modules; + } + + public OsgiBundle installModule(Distribution distribution) { + if (!(distribution instanceof StreamReadable)) + throw new UnsupportedException("distribution", distribution); + + StreamReadable sr = (StreamReadable) distribution; + Bundle bundle; + try { + bundle = bundleContext.installBundle(sr.toString(), sr + .getInputStream()); + } catch (BundleException e) { + throw new SlcException( + "Cannot install OSGi bundle " + distribution, e); + } + return new OsgiBundle(bundle); + } + + public void updateModule(NameVersion nameVersion) { + Bundle bundle = findBundle(nameVersion); + try { + bundle.update(); + } catch (BundleException e) { + throw new SlcException("Cannot update " + bundle, e); + } + } + + public void uninstallModule(NameVersion nameVersion) { + Bundle bundle = findBundle(nameVersion); + try { + bundle.uninstall(); + } catch (BundleException e) { + throw new SlcException("Cannot uninstall " + bundle, e); + } + } + + public void startModule(NameVersion nameVersion) { + Bundle bundle = findBundle(nameVersion); + try { + bundle.start(); + // TODO: use bundle manager + } catch (BundleException e) { + throw new SlcException("Cannot uninstall " + bundle, e); + } + } + + protected Bundle findBundle(NameVersion nameVersion) { + Bundle[] bundles = bundleContext.getBundles(); + for (Bundle bundle : bundles) { + OsgiBundle osgiBundle = new OsgiBundle(bundle); + if (osgiBundle.equals(nameVersion)) { + return bundle; + } + } + throw new SlcException("Could not find bundle " + nameVersion); + } + + public void shutdown() { + // FIXME use framework + throw new UnsupportedException(); + } + + public String getDeployedSystemId() { + return uuid; + } + + public DeploymentData getDeploymentData() { + throw new UnsupportedException(); + } + + public Distribution getDistribution() { + throw new UnsupportedException(); + } + + public TargetData getTargetData() { + throw new UnsupportedException(); + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/AbstractOsgiModularDistribution.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/AbstractOsgiModularDistribution.java new file mode 100644 index 000000000..a38adadcc --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/AbstractOsgiModularDistribution.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi.build; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.DefaultNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.UnsupportedException; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.build.ModularDistribution; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.springframework.beans.factory.InitializingBean; +import org.eclipse.gemini.blueprint.context.BundleContextAware; + +public abstract class AbstractOsgiModularDistribution implements + ModularDistribution, BundleContextAware, InitializingBean { + private final static Log log = LogFactory + .getLog(AbstractOsgiModularDistribution.class); + + private BundleContext bundleContext; + private EclipseUpdateSite eclipseUpdateSite; + + /** Initialized by the object itself. */ + private SortedMap distributions = new TreeMap(); + + protected abstract void fillDistributions( + SortedMap distributions) + throws Exception; + + public Distribution getModuleDistribution(String moduleName, + String moduleVersion) { + return distributions.get(new DefaultNameVersion(moduleName, + moduleVersion)); + } + + public String getDistributionId() { + return bundleContext.getBundle().getSymbolicName() + + "-" + + bundleContext.getBundle().getHeaders() + .get(Constants.BUNDLE_VERSION); + } + + public Set listModulesNameVersions() { + return distributions.keySet(); + } + + public Iterator nameVersions() { + return distributions.keySet().iterator(); + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + public void afterPropertiesSet() throws Exception { + fillDistributions(distributions); + if (log.isDebugEnabled()) + log.debug("Distribution " + getName() + ":" + getVersion() + + " loaded (" + distributions.size() + " modules)"); + } + + protected String findVersion(String name) { + Set versions = new HashSet(); + for (NameVersion key : distributions.keySet()) { + if (key.getName().equals(name)) + versions.add(key.getVersion()); + } + + if (versions.size() == 0) + throw new SlcException("Cannot find version for name " + name); + else if (versions.size() > 1) + throw new SlcException("Found more than one version for name " + + name + ": " + versions); + else + return versions.iterator().next(); + + } + + public Object getModulesDescriptor(String descriptorType) { + if (descriptorType.equals("eclipse")) + return writeEclipseUpdateSite(); + else + throw new UnsupportedException("descriptorType", descriptorType); + } + + protected Set writePlainUrlList() { + return distributions.keySet(); + } + + protected String writeEclipseUpdateSite() { + if (eclipseUpdateSite == null) + throw new SlcException("No eclipse update site declared."); + + StringBuffer buf = new StringBuffer(""); + buf.append(""); + + List usedCategories = new ArrayList(); + for (EclipseUpdateSiteFeature feature : eclipseUpdateSite.getFeatures()) { + + String featureId = feature.getName(); + String featureVersion = findVersion(featureId); + buf.append("\n"); + + for (EclipseUpdateSiteCategory category : feature.getCategories()) { + usedCategories.add(category); + buf.append(" \n"); + } + buf.append("\n\n"); + } + + for (EclipseUpdateSiteCategory category : usedCategories) { + buf.append("\n"); + buf.append(" ").append(category.getDescription()) + .append("\n"); + buf.append("\n\n"); + } + + buf.append(""); + return buf.toString(); + } + + public String getName() { + return bundleContext.getBundle().getSymbolicName(); + } + + public String getVersion() { + return bundleContext.getBundle().getHeaders() + .get(Constants.BUNDLE_VERSION).toString(); + } + + @Override + public String toString() { + return new DefaultNameVersion(this).toString(); + } + + public void setEclipseUpdateSite(EclipseUpdateSite eclipseUpdateSite) { + this.eclipseUpdateSite = eclipseUpdateSite; + } + + public BundleContext getBundleContext() { + return bundleContext; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/BundleModularDistribution.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/BundleModularDistribution.java new file mode 100644 index 000000000..51595750e --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/BundleModularDistribution.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi.build; + +import java.net.URL; +import java.util.Enumeration; +import java.util.SortedMap; +import java.util.StringTokenizer; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; + +import org.apache.commons.io.IOUtils; +import org.argeo.slc.DefaultNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.core.build.VersionedResourceDistribution; +import org.osgi.framework.Constants; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.ResourceLoader; + +public class BundleModularDistribution extends AbstractOsgiModularDistribution + implements ResourceLoaderAware { + private ResourceLoader resourceLoader; + + private String libDirectory = "/lib"; + + @SuppressWarnings(value = { "unchecked" }) + protected void fillDistributions( + SortedMap distributions) + throws Exception { + Enumeration urls = (Enumeration) getBundleContext() + .getBundle().findEntries(libDirectory, "*.jar", false); + while (urls.hasMoreElements()) { + URL url = urls.nextElement(); + JarInputStream in = null; + try { + in = new JarInputStream(url.openStream()); + Manifest mf = in.getManifest(); + String name = mf.getMainAttributes().getValue( + Constants.BUNDLE_SYMBOLICNAME); + // Skip additional specs such as + // ; singleton:=true + if (name.indexOf(';') > -1) { + name = new StringTokenizer(name, " ;").nextToken(); + } + + String version = mf.getMainAttributes().getValue( + Constants.BUNDLE_VERSION); + DefaultNameVersion nameVersion = new DefaultNameVersion(name, + version); + distributions.put(nameVersion, + new VersionedResourceDistribution(name, version, + resourceLoader.getResource(url.toString()))); + } finally { + IOUtils.closeQuietly(in); + } + } + } + + public void setLibDirectory(String libDirectory) { + this.libDirectory = libDirectory; + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + /* + * @SuppressWarnings(value = { "unchecked" }) protected URL + * findModule(String moduleName, String version) { Enumeration urls = + * (Enumeration) bundleContext.getBundle() .findEntries(libDirectory, + * moduleName + "*", false); + * + * if (!urls.hasMoreElements()) throw new SlcException("Cannot find module " + * + moduleName); + * + * URL url = urls.nextElement(); + * + * // TODO: check version as well if (urls.hasMoreElements()) throw new + * SlcException("More than one module with name " + moduleName); return url; + * } + */ + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSite.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSite.java new file mode 100644 index 000000000..e38d9c024 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSite.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi.build; + +import java.util.ArrayList; +import java.util.List; + +public class EclipseUpdateSite { + private List features = new ArrayList(); + + public List getFeatures() { + return features; + } + + public void setFeatures(List features) { + this.features = features; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteCategory.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteCategory.java new file mode 100644 index 000000000..c71656236 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteCategory.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi.build; + +public class EclipseUpdateSiteCategory { + private String name; + private String label; + private String description; + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteFeature.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteFeature.java new file mode 100644 index 000000000..f28c0cb12 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteFeature.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi.build; + +import java.util.ArrayList; +import java.util.List; + +public class EclipseUpdateSiteFeature { + private String name; + private List categories = new ArrayList(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getCategories() { + return categories; + } + + public void setCategories(List categories) { + this.categories = categories; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/OsgiRuntimeModularDistribution.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/OsgiRuntimeModularDistribution.java new file mode 100644 index 000000000..434ef0e09 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/build/OsgiRuntimeModularDistribution.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi.build; + +import java.net.URL; +import java.util.SortedMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.NameVersion; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.core.build.VersionedResourceDistribution; +import org.argeo.slc.osgi.OsgiBundle; +import org.osgi.framework.Bundle; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.eclipse.gemini.blueprint.util.OsgiBundleUtils; + +public class OsgiRuntimeModularDistribution extends + AbstractOsgiModularDistribution implements ResourceLoaderAware { + private final static Log log = LogFactory + .getLog(OsgiRuntimeModularDistribution.class); + + private ResourceLoader resourceLoader; + + protected void fillDistributions( + SortedMap distributions) + throws Exception { + + String frameworkUrl = System.getProperty("osgi.framework"); + String frameworkBaseUrl = null; + if (frameworkUrl != null) + frameworkBaseUrl = frameworkUrl.substring(0, frameworkUrl + .lastIndexOf('/')); + bundles: for (Bundle bundle : getBundleContext().getBundles()) { + OsgiBundle osgiBundle = new OsgiBundle(bundle); + + String originalLocation = bundle.getLocation(); + + if (OsgiBundleUtils.isSystemBundle(bundle)) { + continue bundles; + } + + String location = originalLocation; + if (originalLocation.startsWith("reference:file:")) + location = originalLocation.substring("reference:".length()); + + if (frameworkBaseUrl != null + && originalLocation.startsWith("initial@reference:file:")) { + location = frameworkBaseUrl + + '/' + + originalLocation.substring("initial@reference:file:" + .length()); + } + + try { + URL url = new URL(location); + Resource res = resourceLoader.getResource(url.toString()); + distributions.put(osgiBundle, + new VersionedResourceDistribution(osgiBundle, res)); + + if (log.isTraceEnabled()) + log.debug("Added url " + url + " from original location " + + originalLocation); + } catch (Exception e) { + log.warn("Cannot interpret location " + location + + " of bundle " + bundle + ": " + e); + } + } + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/deploy/OsgiResourceSet.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/deploy/OsgiResourceSet.java new file mode 100644 index 000000000..d95137e23 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/deploy/OsgiResourceSet.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.osgi.deploy; + +import org.argeo.slc.core.deploy.DefaultResourceSet; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.springframework.core.io.ResourceLoader; +import org.eclipse.gemini.blueprint.context.BundleContextAware; +import org.eclipse.gemini.blueprint.io.OsgiBundleResourceLoader; +import org.eclipse.gemini.blueprint.io.OsgiBundleResourcePatternResolver; +import org.eclipse.gemini.blueprint.util.OsgiBundleUtils; + +/** + * Retrieves ressources from an OSGi bundle either the active one or another one + * referenced by its symbolic name. + */ +public class OsgiResourceSet extends DefaultResourceSet implements + BundleContextAware { + private BundleContext bundleContext; + private Bundle bundle = null; + private String bundleSymbolicName = null; + + private OsgiBundleResourceLoader osgiBundleResourceLoader = null; + + @Override + public void afterPropertiesSet() throws Exception { + osgiBundleResourceLoader = new OsgiBundleResourceLoader(getBundle()); + if (getResourcePatternResolver() == null) + setResourcePatternResolver(new OsgiBundleResourcePatternResolver( + osgiBundleResourceLoader)); + super.afterPropertiesSet(); + } + + public Bundle getBundle() { + if (bundle != null) + return bundle; + else if (bundleSymbolicName != null)// do not cache + return OsgiBundleUtils.findBundleBySymbolicName(bundleContext, + bundleSymbolicName); + else + // containing bundle + return bundleContext.getBundle(); + } + + public void setBundleContext(BundleContext bundleContext) { + this.bundleContext = bundleContext; + } + + @Override + public ResourceLoader getResourceLoaderToUse() { + return osgiBundleResourceLoader; + } + + public void setBundle(Bundle bundle) { + this.bundle = bundle; + } + + public void setBundleSymbolicName(String bundleSymbolicName) { + this.bundleSymbolicName = bundleSymbolicName; + } + +} diff --git a/org.argeo.slc.core/src/org/argeo/slc/osgi/execution.xml b/org.argeo.slc.core/src/org/argeo/slc/osgi/execution.xml new file mode 100644 index 000000000..cc0aac069 --- /dev/null +++ b/org.argeo.slc.core/src/org/argeo/slc/osgi/execution.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file -- 2.39.2