From: Mathieu Baudier Date: Sat, 15 Feb 2020 08:45:53 +0000 (+0100) Subject: Rename SLC Core into SLC Spring. X-Git-Tag: argeo-slc-2.1.17~68 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;h=e14154d2baba78852915304d51cbb56bed1d3d3e;hp=aba0f1135009d9014c42368ecea338088e6d2be1;p=gpl%2Fargeo-slc.git Rename SLC Core into SLC Spring. --- diff --git a/dep/org.argeo.slc.dep.e4.rap/pom.xml b/dep/org.argeo.slc.dep.e4.rap/pom.xml index f1a968975..30bd59c9e 100644 --- a/dep/org.argeo.slc.dep.e4.rap/pom.xml +++ b/dep/org.argeo.slc.dep.e4.rap/pom.xml @@ -14,13 +14,13 @@ org.argeo.commons - org.argeo.dep.cms.e4.rap + org.argeo.dep.cms.sdk ${version.argeo-commons} pom org.argeo.slc - org.argeo.slc.dep.spring + org.argeo.slc.dep.minimal 2.1.17-SNAPSHOT pom @@ -85,29 +85,6 @@ - - - - - - - - - - - - - - - - - - - - - - - org.codehaus.mojo rpm-maven-plugin @@ -136,18 +113,11 @@ - - - - - - - argeo-cms-e4-rap argeo-cms-sdk-tp - slc-spring + slc-agent diff --git a/dep/org.argeo.slc.dep.minimal/pom.xml b/dep/org.argeo.slc.dep.minimal/pom.xml index c1ab9d88e..e32a59a82 100644 --- a/dep/org.argeo.slc.dep.minimal/pom.xml +++ b/dep/org.argeo.slc.dep.minimal/pom.xml @@ -25,11 +25,6 @@ org.argeo.slc.api 2.1.17-SNAPSHOT - - org.argeo.slc - org.argeo.slc.core - 2.1.17-SNAPSHOT - org.argeo.slc org.argeo.slc.support diff --git a/dep/org.argeo.slc.dep.spring/pom.xml b/dep/org.argeo.slc.dep.spring/pom.xml index bec19f6d6..faada3bb6 100644 --- a/dep/org.argeo.slc.dep.spring/pom.xml +++ b/dep/org.argeo.slc.dep.spring/pom.xml @@ -20,6 +20,11 @@ + + org.argeo.slc + org.argeo.slc.core + 2.1.17-SNAPSHOT + org.argeo.slc org.argeo.slc.agent diff --git a/org.argeo.slc.core/.classpath b/org.argeo.slc.core/.classpath deleted file mode 100644 index 70b08e830..000000000 --- a/org.argeo.slc.core/.classpath +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/org.argeo.slc.core/.gitignore b/org.argeo.slc.core/.gitignore deleted file mode 100644 index 09e3bc9b2..000000000 --- a/org.argeo.slc.core/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/bin/ -/target/ diff --git a/org.argeo.slc.core/.project b/org.argeo.slc.core/.project deleted file mode 100644 index a304482ca..000000000 --- a/org.argeo.slc.core/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - org.argeo.slc.core - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.pde.ManifestBuilder - - - - - org.eclipse.pde.SchemaBuilder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.pde.PluginNature - - diff --git a/org.argeo.slc.core/META-INF/.gitignore b/org.argeo.slc.core/META-INF/.gitignore deleted file mode 100644 index 4854a41b9..000000000 --- a/org.argeo.slc.core/META-INF/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/MANIFEST.MF diff --git a/org.argeo.slc.core/META-INF/spring.handlers b/org.argeo.slc.core/META-INF/spring.handlers deleted file mode 100644 index 417a952e8..000000000 --- a/org.argeo.slc.core/META-INF/spring.handlers +++ /dev/null @@ -1 +0,0 @@ -http\://www.argeo.org/schema/slc-flow=org.argeo.slc.core.execution.xml.FlowNamespaceHandler \ No newline at end of file diff --git a/org.argeo.slc.core/META-INF/spring.schemas b/org.argeo.slc.core/META-INF/spring.schemas deleted file mode 100644 index 229d4c5f6..000000000 --- a/org.argeo.slc.core/META-INF/spring.schemas +++ /dev/null @@ -1,3 +0,0 @@ -http\://www.argeo.org/schema/slc-flow.xsd=org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd -http\://www.argeo.org/schema/slc-flow-1.2.xsd=org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd -http\://www.argeo.org/schema/slc-flow-0.12.xsd=org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd diff --git a/org.argeo.slc.core/bnd.bnd b/org.argeo.slc.core/bnd.bnd deleted file mode 100644 index fb76254e2..000000000 --- a/org.argeo.slc.core/bnd.bnd +++ /dev/null @@ -1,6 +0,0 @@ -Import-Package: javax.jcr.nodetype,\ -javax.jcr.security,\ -org.apache.tools.ant.*;resolution:="optional",\ -junit.framework;resolution:="optional",\ -org.osgi.*;version=0.0.0,\ -* diff --git a/org.argeo.slc.core/build.properties b/org.argeo.slc.core/build.properties deleted file mode 100644 index 7abe0796a..000000000 --- a/org.argeo.slc.core/build.properties +++ /dev/null @@ -1,3 +0,0 @@ -additional.bundles = org.springframework.context -bin.includes = META-INF/,. -source.. = src/ diff --git a/org.argeo.slc.core/ext/test/log4j.properties b/org.argeo.slc.core/ext/test/log4j.properties deleted file mode 100644 index 0133bab88..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/deploy/DefaultResourceSetTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/DefaultResourceSetTest.java deleted file mode 100644 index 15fb42903..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/DefaultResourceSetTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.core.deploy; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.core.test.context.AbstractInternalSpringTestCase; -import org.springframework.core.io.Resource; - -public class DefaultResourceSetTest extends AbstractInternalSpringTestCase { - private final static Log log = LogFactory - .getLog(DefaultResourceSetTest.class); - - public void testListResources() { - DefaultResourceSet rrs = getBean("relativeResourceSet"); - Map res = rrs.listResources(); - for (String relativePath : res.keySet()) - log.debug(relativePath + "=" + res.get(relativePath)); - assertEquals(2, res.size()); - } - - @Override - protected String getApplicationContextLocation() { - return inPackage("relativeResourceSet.xml"); - } - -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/data/file1.txt b/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/data/file1.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/data/subdir/file2.txt b/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/data/subdir/file2.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/relativeResourceSet.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/relativeResourceSet.xml deleted file mode 100644 index 074c205a5..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/deploy/relativeResourceSet.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.java deleted file mode 100644 index 004605cab..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.core.execution; - -import junit.framework.TestCase; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.core.test.SimpleTestResult; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.test.TestResultPart; -import org.argeo.slc.test.TestStatus; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -public abstract class AbstractExecutionFlowTestCase extends TestCase { - - protected final Log log = LogFactory.getLog(getClass()); - - protected void logException(Throwable ex) { - log.info("Got Exception of class " + ex.getClass().toString() - + " with message '" + ex.getMessage() + "'."); - } - - protected void validateTestResult(SimpleTestResult testResult) { - validateTestResult(testResult, TestStatus.PASSED); - } - - protected void validateTestResult(SimpleTestResult testResult, - int expectedStatus) { - for (TestResultPart part : testResult.getParts()) { - if (part.getStatus() != expectedStatus) { - fail("Error found in TestResult: " + part.getMessage()); - } - } - } - - protected ConfigurableApplicationContext createApplicationContext( - String applicationContextSuffix) { - ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext( - inPackage(applicationContextSuffix)); - // applicationContext.start(); - return applicationContext; - } - - protected void configureAndExecuteSlcFlow(String applicationContextSuffix, - String beanName) { - ConfigurableApplicationContext applicationContext = createApplicationContext(applicationContextSuffix); - ExecutionContext executionContext = (ExecutionContext) applicationContext - .getBean("executionContext"); - ExecutionFlow executionFlow = (ExecutionFlow) applicationContext - .getBean(beanName); - if (executionFlow instanceof DefaultExecutionFlow) - ((DefaultExecutionFlow) executionFlow) - .setExecutionContext(executionContext); - try { - executionContext.beforeFlow(executionFlow); - executionFlow.run(); - } finally { - executionContext.afterFlow(executionFlow); - } - applicationContext.close(); - } - - protected String inPackage(String suffix) { - String prefix = getClass().getPackage().getName().replace('.', '/'); - return prefix + '/' + suffix; - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/BasicExecutionFlowTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/BasicExecutionFlowTest.java deleted file mode 100644 index 91be3bdbe..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/BasicExecutionFlowTest.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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.core.execution; - -import java.util.HashMap; -import java.util.Map; - -import org.argeo.slc.core.test.SimpleTestResult; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.test.TestStatus; -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.context.ConfigurableApplicationContext; - -public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase { - // TO TEST - // - post-processing for @{} replacement in beans with complex properties - // - bean of scope other than execution are not resolved at execution - - // public void testMyTest() throws Exception { - // ConfigurableApplicationContext applicationContext = - // createApplicationContext("test.xml"); - // log.info("Start Execution"); - // ((ExecutionFlow) applicationContext.getBean("flow1")).execute(); - // applicationContext.close(); - // } - - public void testSpecOverriding() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("specOverriding.xml"); - ((ExecutionFlow) applicationContext.getBean("flow2")).run(); - SimpleTestResult res = (SimpleTestResult) applicationContext - .getBean("myTestResult"); - validateTestResult(res); - } - - public void testMultipleFlows() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("multipleFlow.xml"); - ((ExecutionFlow) applicationContext.getBean("flow1")).run(); - SimpleTestResult res = (SimpleTestResult) applicationContext - .getBean("myTestResult"); - validateTestResult(res); - res.getParts().clear(); - ((ExecutionFlow) applicationContext.getBean("flow2")).run(); - validateTestResult(res, TestStatus.FAILED); - applicationContext.close(); - } - - /** - * Test placeholder resolution in a context without scope execution or proxy - * and with cascading flows (the flow A contains the flow B) - * - * @throws Exception - */ - public void testPlaceHolders() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("placeHolders.cascading.xml"); - ((ExecutionFlow) applicationContext.getBean("flowA")).run(); - validateTestResult((SimpleTestResult) applicationContext - .getBean("myTestResult")); - applicationContext.close(); - } - - /** - * Test placeholder resolution in a context without scope execution or proxy - * and with cascading flows (the flow A contains the flow B) setting - * execution values (should have no effect) - * - * @throws Exception - */ - public void testPlaceHoldersWithExecutionValues() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("placeHolders.cascading.xml"); - - ExecutionContext executionContext = (ExecutionContext) applicationContext - .getBean("executionContext"); - Map executionParameters = new HashMap(); - executionParameters.put("p1", "e1"); - executionParameters.put("p2", "e2"); - executionParameters.put("p3", "e3"); - executionParameters.put("p4", "e4"); - executionParameters.put("p5", "e5"); - executionParameters.put("p6", "e6"); - executionParameters.put("p7", "e7"); - executionParameters.put("p8", "e8"); - addVariables(executionContext, executionParameters); - - ((ExecutionFlow) applicationContext.getBean("flowA")).run(); - validateTestResult((SimpleTestResult) applicationContext - .getBean("myTestResult")); - applicationContext.close(); - } - - public void testPlaceHoldersExec() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("placeHolders.cascading.exec.xml"); - - ExecutionContext executionContext = (ExecutionContext) applicationContext - .getBean("executionContext"); - Map executionParameters = new HashMap(); - executionParameters.put("p1", "e1"); - executionParameters.put("p2", "e2"); - executionParameters.put("p3", "e3"); - executionParameters.put("p4", "e4"); - executionParameters.put("p5", "e5"); - executionParameters.put("p6", "e6"); - addVariables(executionContext, executionParameters); - - ((ExecutionFlow) applicationContext.getBean("flowA")).run(); - validateTestResult((SimpleTestResult) applicationContext - .getBean("myTestResult")); - applicationContext.close(); - } - - public void testCanonicFlowParameters() throws Exception { - configureAndExecuteSlcFlow("canonic-001.xml", "canonic.001"); - } - - public void testCanonicDefaultValues() throws Exception { - configureAndExecuteSlcFlow("canonic-002.xml", "canonic.002"); - } - - public void testCanonicMissingValues() throws Exception { - try { - configureAndExecuteSlcFlow("canonic-003.error.xml", "canonic.003"); - fail("Parameter not set - should be rejected."); - } catch (BeanCreationException e) { - // exception expected - logException(e); - } - } - - public void testCanonicUnknownParameter() throws Exception { - try { - configureAndExecuteSlcFlow("canonic-004.error.xml", "canonic.004"); - fail("Unknown parameter set - should be rejected."); - } catch (BeanCreationException e) { - // exception expected - logException(e); - } - } - - public void testListSetMap() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("listSetMap.xml"); - ExecutionFlow executionFlow = (ExecutionFlow) applicationContext - .getBean("myFlow"); - executionFlow.run(); - - validateTestResult((SimpleTestResult) applicationContext - .getBean("myTestResult")); - - // BasicTestData res = (BasicTestData) - // applicationContext.getBean("cascadingComplex.testData"); - // log.info("res=" + res.getReached().toString()); - - applicationContext.close(); - } - - public void testListSetMapMultipleFlows() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("listSetMapMultipleFlow.xml"); - ((ExecutionFlow) applicationContext.getBean("flow1")).run(); - SimpleTestResult res = (SimpleTestResult) applicationContext - .getBean("myTestResult"); - validateTestResult(res); - res.getParts().clear(); - ((ExecutionFlow) applicationContext.getBean("flow2")).run(); - validateTestResult(res, TestStatus.FAILED); - applicationContext.close(); - } - - protected void addVariables(ExecutionContext executionContext, - Map vars) { - for (String key : vars.keySet()) - executionContext.setVariable(key, vars.get(key)); - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/DefaultAgentCliTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/DefaultAgentCliTest.java deleted file mode 100644 index a7d9b8b78..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/DefaultAgentCliTest.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.argeo.slc.core.execution; - -import java.net.URI; -import java.util.List; - -import junit.framework.TestCase; - -public class DefaultAgentCliTest extends TestCase { - public void testArgsToUris() { - String[] args = { "org.argeo.slc.demo.minimal", "HelloWorld/WithVar", - "--testKey", "555" }; - List uris = DefaultAgentCli.asURIs(args); - assertEquals(1, uris.size()); - assertEquals( - "flow:/org.argeo.slc.demo.minimal/HelloWorld/WithVar?testKey=555", - uris.get(0).toString()); - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java deleted file mode 100644 index 55afdc0c8..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.core.execution; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.InitializingBean; - -public class ExceptionIfInitCalledTwice implements Runnable, InitializingBean { - private final static Log log = LogFactory - .getLog(ExceptionIfInitCalledTwice.class); - - private Boolean calledOnce = false; - - public void run() { - log.info(getClass().getSimpleName() + " ran properly"); - } - - public void afterPropertiesSet() throws Exception { - log.info(getClass().getSimpleName() + " init method called"); - - if (calledOnce) - throw new SlcException(getClass().getSimpleName() - + "init method called twice."); - else - calledOnce = true; - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.java deleted file mode 100644 index 8b3d2ec25..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.core.execution; - -import java.io.File; - -public class FileExecutionResourcesSpringTest extends - AbstractExecutionFlowTestCase { - private String basePath = FileExecutionResources.DEFAULT_EXECUTION_RESOURCES_TMP_PATH; - - public void testSimple() throws Exception { - File file = getFile("subdir/writeTo"); - try { - assertFalse(file.exists()); - configureAndExecuteSlcFlow("executionResources.xml", - "executionResources.simple"); - assertTrue(file.exists()); - } finally { - file.deleteOnExit(); - } - } - - public void testPlaceholderPass() throws Exception { - File file = getFile("subdir/60"); - try { - assertFalse(file.exists()); - configureAndExecuteSlcFlow("executionResources.xml", - "executionResources.placeholderPass"); - assertTrue(file.exists()); - } finally { - file.deleteOnExit(); - } - } - - /** - * Test that it generate the wrong file because of issue when using - * execution placeholder in contructor-arg - */ - public void testPlaceholderFail() throws Exception { - File file = getFile("subdir/@{var}"); - try { - assertFalse(file.exists()); - configureAndExecuteSlcFlow("executionResources.xml", - "executionResources.placeholderFail"); - assertTrue(file.exists()); - } finally { - file.deleteOnExit(); - } - } - - protected File getFile(String relativePath) { - return new File(basePath + File.separator - + relativePath.replace('/', File.separatorChar)); - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesTest.java deleted file mode 100644 index e2dae6564..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.core.execution; - -import java.io.File; - -import junit.framework.TestCase; - -import org.apache.commons.io.FileUtils; -import org.argeo.slc.execution.ExecutionContext; -import org.springframework.core.io.Resource; - -public class FileExecutionResourcesTest extends TestCase { - public void testGetWritableFile() throws Exception { - FileExecutionResources executionResources = new FileExecutionResources(); - ExecutionContext executionContext = new MapExecutionContext(); - executionResources.setExecutionContext(executionContext); - - String expected = "TEST"; - String reached = ""; - try { - // Resource - Resource resource = executionResources - .getWritableResource("subdir1/textRes.txt"); - assertTrue(resource.getFile().getParentFile().exists()); - assertFalse(resource.getFile().exists()); - FileUtils.writeStringToFile(resource.getFile(), expected); - reached = FileUtils.readFileToString(resource.getFile()); - assertEquals(expected, reached); - - // File - File file = executionResources.getFile("subdir2/textFile.txt"); - assertFalse(file.getParentFile().exists()); - assertFalse(file.exists()); - FileUtils.writeStringToFile(file, expected); - reached = FileUtils.readFileToString(file); - assertEquals(expected, reached); - } finally { - if (executionResources.getBaseDir() != null - && executionResources.getBaseDir().exists()) - FileUtils.deleteDirectory(executionResources.getBaseDir()); - } - - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/ParameterRefTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/ParameterRefTest.java deleted file mode 100644 index 35df7eb53..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/ParameterRefTest.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.core.execution; - -import org.argeo.slc.core.test.SimpleTestResult; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.test.TestStatus; -import org.springframework.context.ConfigurableApplicationContext; - -public class ParameterRefTest extends AbstractExecutionFlowTestCase { - public void test001() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("parameterRef.xml"); - ((ExecutionFlow) applicationContext.getBean("parameterRef.001")).run(); - - SimpleTestResult res = (SimpleTestResult) applicationContext - .getBean("parameterRef.testResult"); - assertEquals(res.getParts().get(0).getStatus(), TestStatus.PASSED); - assertEquals(res.getParts().get(1).getStatus(), TestStatus.FAILED); - - applicationContext.close(); - } - -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/applicationContext.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/applicationContext.xml deleted file mode 100644 index d83c2c125..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/canonic-001.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-001.xml deleted file mode 100644 index a1c59c9b1..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-001.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-002.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-002.xml deleted file mode 100644 index 57f0c8a89..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-002.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-003.error.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-003.error.xml deleted file mode 100644 index 6de881047..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-003.error.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-004.error.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-004.error.xml deleted file mode 100644 index 2638ed6ee..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic-004.error.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/canonic.xml deleted file mode 100644 index 8d6af0ef1..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/executionResources.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/executionResources.xml deleted file mode 100644 index 654f8b420..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/imports.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/imports.xml deleted file mode 100644 index 7ddb4ea80..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/listSetMap.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/listSetMap.xml deleted file mode 100644 index 8cf72e354..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml deleted file mode 100644 index b8626f851..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/minimal.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/minimal.xml deleted file mode 100644 index 5b166970b..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/multipleFlow.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/multipleFlow.xml deleted file mode 100644 index 58a43e418..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/parameterRef.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/parameterRef.xml deleted file mode 100644 index 98cc14d3d..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml deleted file mode 100644 index a36b4a167..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.xml deleted file mode 100644 index 893768be3..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/specOverriding.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/specOverriding.xml deleted file mode 100644 index de1dc8504..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/tasks/SystemCallTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/tasks/SystemCallTest.java deleted file mode 100644 index 8301b8517..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/tasks/SystemCallTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.core.execution.tasks; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.core.execution.AbstractExecutionFlowTestCase; - -public class SystemCallTest extends AbstractExecutionFlowTestCase { - private final static Log log = LogFactory.getLog(SystemCallTest.class); - - private final String defFile = "systemCall.xml"; - - public void testSystemCallSimple() throws Exception { - if (isOsSupported()) - configureAndExecuteSlcFlow(defFile, "systemCallSimple"); - } - - public void testSystemCallList() throws Exception { - if (isOsSupported()) - configureAndExecuteSlcFlow(defFile, "systemCallList"); - } - - public void testSystemCallOsSpecific() throws Exception { - if (isOsSupported()) - configureAndExecuteSlcFlow(defFile, "systemCallOsSpecific"); - } - - public void testSystemCallWithVar() throws Exception { - if (isOsSupported()) - configureAndExecuteSlcFlow(defFile, "systemCallWithVar"); - } - - protected boolean isOsSupported() { - String osName = System.getProperty("os.name"); - final Boolean ret; - if (osName.contains("Windows")) - ret = false; - else - ret = true; - - if (ret == false) - log.warn("Skip test because OS '" + osName + "' is not supported."); - return ret; - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/tasks/systemCall.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/tasks/systemCall.xml deleted file mode 100644 index 8d3565040..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/test.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/test.xml deleted file mode 100644 index d8bec3df0..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/xml/FlowNamespaceTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/FlowNamespaceTest.java deleted file mode 100644 index f673020e6..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/FlowNamespaceTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.core.execution.xml; - -import org.argeo.slc.core.execution.AbstractExecutionFlowTestCase; -import org.argeo.slc.core.test.SimpleTestResult; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.springframework.context.ConfigurableApplicationContext; - -public class FlowNamespaceTest extends AbstractExecutionFlowTestCase { - public void testCanonical() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("canonic-ns.xml"); - ((ExecutionFlow) applicationContext.getBean("canonic-ns.001")).run(); - ((ExecutionFlow) applicationContext.getBean("canonic-ns.002")).run(); - } - - public void testAdvanced() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("advanced.xml"); - ((ExecutionFlow) applicationContext.getBean("flow1")).run(); - ((ExecutionFlow) applicationContext.getBean("flow2")).run(); - ((ExecutionFlow) applicationContext.getBean("flow3")).run(); - - validateTestResult((SimpleTestResult) applicationContext - .getBean("testResult")); - } - - public void testAdvancedExecution() throws Exception { - ConfigurableApplicationContext applicationContext = createApplicationContext("advanced.xml"); - - ExecutionContext executionContext = (ExecutionContext) applicationContext - .getBean("executionContext"); - executionContext.setVariable("param2", 4); - - ((ExecutionFlow) applicationContext.getBean("flow4")).run(); - - validateTestResult((SimpleTestResult) applicationContext - .getBean("testResult")); - } - - // These tests causes pb when using Spring 3 - - // public void testContainers() throws Exception { - // ConfigurableApplicationContext applicationContext = - // createApplicationContext("containers.xml"); - // ((ExecutionFlow) applicationContext.getBean("test.list.flow1")).run(); - // ((ExecutionFlow) applicationContext.getBean("test.list.flow2")).run(); - // - // validateTestResult((SimpleTestResult) applicationContext - // .getBean("testResult")); - // } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/advanced.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/advanced.xml deleted file mode 100644 index 49b6f7e1d..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/advanced.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - 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/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-001.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-001.xml deleted file mode 100644 index aeef3a3af..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-002.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-002.xml deleted file mode 100644 index ac5f085eb..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-002.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/canonic-ns.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/canonic-ns.xml deleted file mode 100644 index facb27761..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/xml/containers.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/containers.xml deleted file mode 100644 index 61bfa0703..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/execution/xml/tests.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/execution/xml/tests.xml deleted file mode 100644 index ee58a1869..000000000 --- a/org.argeo.slc.core/ext/test/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/ext/test/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.java deleted file mode 100644 index 61eb3b2b3..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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.core.test.context; - -import java.util.Map; - -import junit.framework.TestCase; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.BeanFactoryUtils; -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - -/** Helper for tests using a Spring application context. */ -public abstract class AbstractInternalSpringTestCase extends TestCase { - protected final Log log = LogFactory.getLog(getClass()); - private ConfigurableApplicationContext context; - - /** - * Gets (and create if necessary) the application context to use. Default - * implementation uses a class path xml application context and calls - * {@link #getApplicationContextLocation()}. - */ - protected ConfigurableApplicationContext getContext() { - if (context == null) { - context = new ClassPathXmlApplicationContext( - getApplicationContextLocation()); - } - return context; - } - - /** Returns a bean from the underlying context */ - @SuppressWarnings(value = { "unchecked" }) - protected T getBean(String beanId) { - return (T) getContext().getBean(beanId); - } - - protected T getBean(Class clss) { - T bean = loadSingleFromContext(getContext(), clss); - if (bean == null) { - throw new SlcException("Cannot retrieve a unique bean of type " - + clss); - } else { - return bean; - } - } - - /** - * Th location of the application to load. The default implementation - * returns applicationContext.xml found in the same package as the - * test. - */ - protected String getApplicationContextLocation() { - return inPackage("applicationContext.xml"); - } - - /** - * Prefixes the package of the class after converting the '.' to '/' in - * order to have a resource path. - */ - protected String inPackage(String suffix) { - String prefix = getClass().getPackage().getName().replace('.', '/'); - return prefix + '/' + suffix; - } - - @SuppressWarnings(value = { "unchecked" }) - protected T loadSingleFromContext(ListableBeanFactory context, - Class clss) { - Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors( - context, clss, false, false); - if (beans.size() == 1) { - return beans.values().iterator().next(); - } else if (beans.size() > 1) { - if (log.isDebugEnabled()) { - log - .debug(("Found more that on bean for type " + clss - + ": " + beans.keySet())); - } - return null; - } else { - return null; - } - } - -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/ContextTest.java b/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/ContextTest.java deleted file mode 100644 index 694851c82..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/ContextTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.core.test.context; - -import java.util.List; - -import org.argeo.slc.core.test.SimpleTestResult; -import org.argeo.slc.test.TestResultPart; -import org.argeo.slc.test.TestStatus; -import org.argeo.slc.test.context.ContextAware; - -public class ContextTest extends AbstractInternalSpringTestCase { - - public void testComplexContext() { - SimpleTestResult testResult = new SimpleTestResult(); - ContextUtils.compareReachedExpected( - (ContextAware) getBean("context.c1"), testResult); - ContextUtils.compareReachedExpected( - (ContextAware) getBean("context.c2"), testResult); - ContextUtils.compareReachedExpected( - (ContextAware) getBean("context.c3"), testResult); - - List parts = testResult.getParts(); - assertEquals(6, parts.size()); - assertEquals(TestStatus.PASSED, parts.get(0).getStatus()); - assertEquals(TestStatus.PASSED, parts.get(1).getStatus()); - assertEquals(TestStatus.PASSED, parts.get(2).getStatus()); - assertEquals(TestStatus.FAILED, parts.get(3).getStatus()); - assertEquals(TestStatus.PASSED, parts.get(4).getStatus()); - assertEquals(TestStatus.PASSED, parts.get(5).getStatus()); - } -} diff --git a/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/applicationContext.xml b/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/applicationContext.xml deleted file mode 100644 index 4949c4eb1..000000000 --- a/org.argeo.slc.core/ext/test/org/argeo/slc/core/test/context/applicationContext.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/pom.xml b/org.argeo.slc.core/pom.xml deleted file mode 100644 index 982f0e654..000000000 --- a/org.argeo.slc.core/pom.xml +++ /dev/null @@ -1,92 +0,0 @@ - - 4.0.0 - - org.argeo.slc - argeo-slc - 2.1.17-SNAPSHOT - .. - - org.argeo.slc.core - SLC Runtime - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - - - - - org.argeo.commons - org.argeo.enterprise - ${version.argeo-commons} - - - org.argeo.commons - org.argeo.node.api - ${version.argeo-commons} - - - org.argeo.commons - org.argeo.cms - ${version.argeo-commons} - - - org.argeo.commons - org.argeo.jcr - ${version.argeo-commons} - - - org.argeo.commons - org.argeo.util - ${version.argeo-commons} - - - - - org.argeo.slc - org.argeo.slc.api - 2.1.17-SNAPSHOT - - - - - org.argeo.tp.spring - org.springframework.beans - - - org.argeo.tp.spring - org.springframework.core - - - org.argeo.tp.spring - org.springframework.context - - - org.argeo.tp.spring - org.springframework.aop - - - org.argeo.tp.gemini - org.eclipse.gemini.blueprint.core - - - org.argeo.tp.gemini - org.eclipse.gemini.blueprint.io - - - - - org.argeo.tp.apache.ant - org.apache.ant - - - - \ No newline at end of file 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 deleted file mode 100644 index 9dea43e49..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/ant/AntFlowGenerator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1e2dcb940..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/ant/AntRun.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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/core/attachment/Attachment.java b/org.argeo.slc.core/src/org/argeo/slc/core/attachment/Attachment.java deleted file mode 100644 index ecde0b936..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/Attachment.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.core.attachment; - -public interface Attachment { - public String getUuid(); - - public void setUuid(String uuid); - - public String getName(); - - public String getContentType(); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentUploader.java b/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentUploader.java deleted file mode 100644 index eb484c92c..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentUploader.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.core.attachment; - -import org.springframework.core.io.Resource; - -public interface AttachmentUploader { - public void upload(Attachment attachment, Resource resource); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentsEnabled.java b/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentsEnabled.java deleted file mode 100644 index 780a6a483..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentsEnabled.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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.core.attachment; - -public interface AttachmentsEnabled { - public void addAttachment(Attachment attachment); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentsStorage.java b/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentsStorage.java deleted file mode 100644 index 2214afabf..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/AttachmentsStorage.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.core.attachment; - -import java.io.InputStream; -import java.io.OutputStream; - -public interface AttachmentsStorage { - public void retrieveAttachment(Attachment attachment, - OutputStream outputStream); - - /** Does NOT close the provided input stream. */ - public void storeAttachment(Attachment attachment, InputStream inputStream); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/FileAttachmentsStorage.java b/org.argeo.slc.core/src/org/argeo/slc/core/attachment/FileAttachmentsStorage.java deleted file mode 100644 index 3b7e62dac..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/FileAttachmentsStorage.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * 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.core.attachment; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.Resource; - -public class FileAttachmentsStorage implements AttachmentsStorage, - AttachmentUploader, InitializingBean { - private final static Log log = LogFactory - .getLog(FileAttachmentsStorage.class); - - private File attachmentsDirectory; - - private String attachmentsTocFileName = "attachmentsToc.csv"; - - private DateFormat dateFormatDay = new SimpleDateFormat("yyyy-MM-dd"); - private DateFormat dateFormatTime = new SimpleDateFormat("HH:mm:ss"); - - public void afterPropertiesSet() { - if (attachmentsDirectory == null) { - - String osgiInstanceArea = System.getProperty("osgi.instance.area"); - if (osgiInstanceArea != null) { - if (osgiInstanceArea.startsWith("file:")) - osgiInstanceArea = osgiInstanceArea.substring("file:" - .length()); - attachmentsDirectory = new File(osgiInstanceArea - + File.separator + "slcAttachments"); - } - - if (attachmentsDirectory == null) { - String tempDir = System.getProperty("java.io.tmpdir"); - attachmentsDirectory = new File(tempDir + File.separator - + "slcAttachments"); - } - } - if (!attachmentsDirectory.exists()) - attachmentsDirectory.mkdirs(); - if (log.isDebugEnabled()) - log.debug("File attachment storage initialized in directory " - + attachmentsDirectory); - } - - public void retrieveAttachment(Attachment attachment, - OutputStream outputStream) { - File file = getFile(attachment); - InputStream in = null; - try { - byte[] buffer = new byte[1024 * 1024]; - in = new FileInputStream(file); - int read = -1; - while ((read = in.read(buffer)) >= 0) { - outputStream.write(buffer, 0, read); - } - if (log.isTraceEnabled()) - log.trace("Read " + attachment + " from " + file); - } catch (IOException e) { - throw new SlcException("Cannot write attachment " + attachment - + " to " + file, e); - } finally { - IOUtils.closeQuietly(in); - } - } - - public void storeAttachment(Attachment attachment, InputStream inputStream) { - File file = getFile(attachment); - FileOutputStream out = null; - try { - byte[] buffer = new byte[1024 * 1024]; - out = new FileOutputStream(file); - int read = -1; - while ((read = inputStream.read(buffer)) >= 0) { - out.write(buffer, 0, read); - } - if (log.isTraceEnabled()) - log.trace("Wrote " + attachment + " to " + file); - updateAttachmentToc(attachment, file); - } catch (IOException e) { - throw new SlcException("Cannot write attachment " + attachment - + " to " + file, e); - } finally { - IOUtils.closeQuietly(out); - } - - } - - public void upload(Attachment attachment, Resource resource) { - try { - storeAttachment(attachment, resource.getInputStream()); - } catch (IOException e) { - throw new SlcException("Cannot upload attachment " + attachment, e); - } - } - - /** For monitoring purposes only */ - protected void updateAttachmentToc(Attachment attachment, File file) { - Date date = new Date(file.lastModified()); - FileWriter writer = null; - try { - writer = new FileWriter(attachmentsDirectory + File.separator - + attachmentsTocFileName, true); - writer.append(dateFormatDay.format(date)); - writer.append(','); - writer.append(dateFormatTime.format(date)); - writer.append(','); - writer.append(attachment.getUuid()); - writer.append(','); - writer.append(attachment.getName()); - writer.append(','); - writer.append(attachment.getContentType()); - writer.append(','); - writer.append(Long.toString(file.length())); - writer.append(','); - writer.append(file.getCanonicalPath()); - writer.append('\n'); - } catch (IOException e) { - log.warn("Could not update attachments TOC for " + attachment - + " and file " + file, e); - } finally { - IOUtils.closeQuietly(writer); - } - - } - - protected File getFile(Attachment attachment) { - File file = new File(attachmentsDirectory + File.separator - + attachment.getUuid()); - return file; - } - - public void setAttachmentsDirectory(File attachmentsDirectory) { - this.attachmentsDirectory = attachmentsDirectory; - } - - public void setAttachmentsTocFileName(String attachmentsTocFileName) { - this.attachmentsTocFileName = attachmentsTocFileName; - } - - public void setDateFormatDay(DateFormat dateFormatDay) { - this.dateFormatDay = dateFormatDay; - } - - public void setDateFormatTime(DateFormat dateFormatTime) { - this.dateFormatTime = dateFormatTime; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/SimpleAttachment.java b/org.argeo.slc.core/src/org/argeo/slc/core/attachment/SimpleAttachment.java deleted file mode 100644 index 6248dd71e..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/attachment/SimpleAttachment.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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.core.attachment; - -import java.io.Serializable; -import java.util.UUID; - -public class SimpleAttachment implements Attachment, Serializable { - private static final long serialVersionUID = 6615155908800610606L; - private String uuid = UUID.randomUUID().toString(); - private String name; - private String contentType = ""; - - public SimpleAttachment() { - } - - public SimpleAttachment(String uuid, String name, String contentType) { - super(); - this.uuid = uuid; - this.name = name; - this.contentType = contentType; - } - - public String getUuid() { - return uuid; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - public String toString() { - return "Attachment #" + uuid + "(" + name + ", " + contentType + ")"; - } - - public boolean equals(Object obj) { - if (obj instanceof Attachment) { - Attachment attachment = (Attachment) obj; - if (uuid != null && attachment.getUuid() != null) - return uuid.equals(attachment.getUuid()); - - if (name != null && attachment.getName() != null) - return name.equals(attachment.getName()); - - return hashCode() == attachment.hashCode(); - } - return false; - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/build/ResourceDistribution.java b/org.argeo.slc.core/src/org/argeo/slc/core/build/ResourceDistribution.java deleted file mode 100644 index 4ebbe92a4..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/build/ResourceDistribution.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.core.build; - -import java.io.IOException; -import java.io.InputStream; - -import org.argeo.slc.SlcException; -import org.argeo.slc.StreamReadable; -import org.argeo.slc.build.Distribution; -import org.springframework.core.io.Resource; - -/** A software distribution archive accessible via a {@link Resource}. */ -public class ResourceDistribution implements Distribution, StreamReadable { - private Resource resource; - - public ResourceDistribution() { - } - - public ResourceDistribution(Resource location) { - this.resource = location; - } - - public String getDistributionId() { - return resource.toString(); - } - - public Resource getResource() { - return resource; - } - - public void setResource(Resource resource) { - this.resource = resource; - } - - public InputStream getInputStream() { - try { - return resource.getInputStream(); - } catch (IOException e) { - throw new SlcException("Cannot get input stream", e); - } - } - - @Override - public String toString() { - return resource.toString(); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/build/VersionDistributionId.java b/org.argeo.slc.core/src/org/argeo/slc/core/build/VersionDistributionId.java deleted file mode 100644 index c11dc00ea..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/build/VersionDistributionId.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.core.build; - -import java.util.StringTokenizer; - -/** - *

- * An implementation of the distribution id using the standard - * Major.Minor.Release notation. And additional arbitrary string can also be - * added. - *

- * - *

- * Examples:
- * 0.2.6
- * 2.4.12.RC1 - *

- */ -public class VersionDistributionId { - - private Integer major; - private Integer minor; - private Integer release; - private String additional; - - /** Parse the provided string in order to set the various components. */ - public void setVersionString(String str) { - StringTokenizer st = new StringTokenizer(str, "."); - if (st.hasMoreTokens()) - major = Integer.parseInt(st.nextToken()); - if (st.hasMoreTokens()) - minor = Integer.parseInt(st.nextToken()); - if (st.hasMoreTokens()) - release = Integer.parseInt(st.nextToken()); - if (st.hasMoreTokens()) - additional = st.nextToken(); - } - - public Integer getMajor() { - return major; - } - - public void setMajor(Integer major) { - this.major = major; - } - - public Integer getMinor() { - return minor; - } - - public void setMinor(Integer minor) { - this.minor = minor; - } - - public Integer getRelease() { - return release; - } - - public void setRelease(Integer release) { - this.release = release; - } - - public String getAdditional() { - return additional; - } - - public void setAdditional(String additional) { - this.additional = additional; - } - - @Override - public boolean equals(Object obj) { - // TODO Auto-generated method stub - return super.equals(obj); - } - - @Override - public String toString() { - return major + "." + minor + "." + release - + (additional != null ? "." + additional : ""); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/build/VersionedResourceDistribution.java b/org.argeo.slc.core/src/org/argeo/slc/core/build/VersionedResourceDistribution.java deleted file mode 100644 index 52307ec67..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/build/VersionedResourceDistribution.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.core.build; - -import org.argeo.slc.NameVersion; -import org.springframework.core.io.Resource; - -/** - * The distribution of a software package (jar, zip, RPM, etc.) which is - * versioned. The archive itself is accessible via a {@link Resource}. - */ -public class VersionedResourceDistribution extends ResourceDistribution - implements NameVersion { - private String name; - private String version; - - public VersionedResourceDistribution() { - super(); - } - - public VersionedResourceDistribution(NameVersion nameVersion, - Resource resource) { - this(nameVersion.getName(), nameVersion.getVersion(), resource); - } - - public VersionedResourceDistribution(String name, String version, - Resource resource) { - super(resource); - this.name = name; - this.version = version; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/build/package.html b/org.argeo.slc.core/src/org/argeo/slc/core/build/package.html deleted file mode 100644 index 5da205278..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/build/package.html +++ /dev/null @@ -1,6 +0,0 @@ - - - -SLC Build: building of software systems. - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/DefaultResourceSet.java b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/DefaultResourceSet.java deleted file mode 100644 index abdcfeec3..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/DefaultResourceSet.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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.core.deploy; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.TreeMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.io.support.PathMatchingResourcePatternResolver; -import org.springframework.core.io.support.ResourcePatternResolver; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.PathMatcher; - -public class DefaultResourceSet implements ResourceLoaderAware, - InitializingBean, ResourceSet { - private final static Log log = LogFactory.getLog(DefaultResourceSet.class); - public final static String DEFAULT_EXCLUDES = "**/.svn/**"; - - private String base; - private String include; - private List includes = new ArrayList(); - private String exclude; - private List excludes = new ArrayList(); - private Boolean useDefaultExcludes = true; - private ResourcePatternResolver resourcePatternResolver; - private PathMatcher excludePathMatcher = new AntPathMatcher(); - - private ResourceLoader resourceLoader; - - /** List the resources, identified by their relative path. */ - public Map listResources() { - try { - Map res = new TreeMap(); - if (base == null) - return res; - String baseResUrl = getResourceLoaderToUse().getResource(base) - .getURL().toString(); - for (String includePattern : includes) - processInclude(res, includePattern, baseResUrl); - return res; - } catch (IOException e) { - throw new SlcException("Cannot list resource from " + base, e); - } - } - - protected void processInclude(Map res, String include, - String baseResUrl) throws IOException { - String pattern = base + "/" + include; - if (log.isTraceEnabled()) - log.trace("Look for resources with pattern '" + pattern - + "' in base url " + baseResUrl); - Resource[] resources = resourcePatternResolver.getResources(pattern); - resources: for (Resource resource : resources) { - String url = resource.getURL().toString(); - String relPath = url.substring(baseResUrl.length()); - - // skip dir - if (relPath.charAt(relPath.length() - 1) == '/') { - if (log.isTraceEnabled()) - log.trace("Skip directory " + relPath + "=" + resource); - continue resources; - } - - // make sure there is not starting '/' - if (relPath.charAt(0) == '/') - relPath = relPath.substring(1); - - // skip excludes - for (String exclude : excludes) - if (excludePathMatcher.match(exclude, relPath)) { - if (log.isTraceEnabled()) - log.trace("Exclude " + relPath + "=" + resource); - continue resources; - } - - // check if already exists - if (res.containsKey(relPath)) - log.warn(relPath + " already matched by " + res.get(relPath) - + ", " + resource + " will override it."); - - // store the marched resource - res.put(relPath, resource); - if (log.isTraceEnabled()) - log.trace(relPath + "=" + resource); - } - - } - - public void afterPropertiesSet() throws Exception { - if (resourcePatternResolver == null) - resourcePatternResolver = new PathMatchingResourcePatternResolver( - getResourceLoaderToUse()); - if (include != null) - addCommaSeparatedToList(include, includes); - if (exclude != null) - addCommaSeparatedToList(exclude, excludes); - - if (includes.size() == 0) - includes.add("**"); - - if (useDefaultExcludes) - addCommaSeparatedToList(DEFAULT_EXCLUDES, excludes); - } - - private void addCommaSeparatedToList(String str, List lst) { - StringTokenizer st = new StringTokenizer(str, ","); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - if (!lst.contains(token)) - lst.add(token); - } - } - - public void setResourceLoader(ResourceLoader resourceLoader) { - this.resourceLoader = resourceLoader; - } - - /** - * Can be overridden in order to provide the proper resource loader used to - * resolve resources. - */ - public ResourceLoader getResourceLoaderToUse() { - return resourceLoader; - } - - public void setBase(String base) { - this.base = base; - } - - public void setInclude(String include) { - this.include = include; - } - - public void setIncludes(List includes) { - this.includes = includes; - } - - public void setExclude(String exclude) { - this.exclude = exclude; - } - - public void setExcludes(List excludes) { - this.excludes = excludes; - } - - public void setUseDefaultExcludes(Boolean useDefaultExcludes) { - this.useDefaultExcludes = useDefaultExcludes; - } - - public void setExcludePathMatcher(PathMatcher excludePathMatcher) { - this.excludePathMatcher = excludePathMatcher; - } - - public void setResourcePatternResolver( - ResourcePatternResolver resourcePatternResolver) { - this.resourcePatternResolver = resourcePatternResolver; - } - - public ResourcePatternResolver getResourcePatternResolver() { - return resourcePatternResolver; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/DigestCheck.java b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/DigestCheck.java deleted file mode 100644 index be8355fe3..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/DigestCheck.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.core.deploy; - -import java.io.File; -import java.io.IOException; - -import org.argeo.slc.SlcException; -import org.springframework.core.io.Resource; -import org.springframework.util.DigestUtils; - -/** Add Spring capabilities to {@link DigestUtils} */ -public class DigestCheck extends DigestUtils { - public static String digest(String algorithm, Resource resource) { - try { - File file = resource.getFile(); - return org.argeo.util.DigestUtils.digest(algorithm, file); - } catch (IOException e) { - try { - return org.argeo.util.DigestUtils.digest(algorithm, - resource.getInputStream()); - } catch (IOException e1) { - throw new SlcException("Cannot digest " + resource - + " with algorithm " + algorithm, e); - } - } - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/LocalFilesDeployment.java b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/LocalFilesDeployment.java deleted file mode 100644 index 79ad83597..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/LocalFilesDeployment.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.core.deploy; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Map; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.argeo.slc.SlcException; -import org.springframework.core.io.Resource; - -public class LocalFilesDeployment implements Runnable { - private String targetBase = ""; - private ResourceSet resourceSet; - - public LocalFilesDeployment() { - } - - public LocalFilesDeployment(ResourceSet resourceSet) { - this.resourceSet = resourceSet; - } - - public void run() { - Map resources = resourceSet.listResources(); - for (String relPath : resources.keySet()) { - File targetFile = new File(targetBase + File.separator + relPath); - File parentDir = targetFile.getParentFile(); - if (!parentDir.exists()) - parentDir.mkdirs(); - - Resource resource = resources.get(relPath); - - InputStream in = null; - OutputStream out = null; - try { - in = resource.getInputStream(); - out = FileUtils.openOutputStream(targetFile); - IOUtils.copy(in, out); - } catch (IOException e) { - throw new SlcException("Cannot extract " + resource + " to " - + targetFile, e); - } finally { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(out); - } - } - } - - public void setTargetBase(String targetBase) { - this.targetBase = targetBase; - } - - public void setResourceSet(ResourceSet resourceSet) { - this.resourceSet = resourceSet; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/MultiResourceSet.java b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/MultiResourceSet.java deleted file mode 100644 index 8da17ba42..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/MultiResourceSet.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.core.deploy; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.springframework.core.io.Resource; - -public class MultiResourceSet implements ResourceSet { - private List resourceSets = new ArrayList(); - - public Map listResources() { - Map res = new HashMap(); - for (ResourceSet resourceSet : resourceSets) { - res.putAll(resourceSet.listResources()); - } - return res; - } - - /** Last listed override previous for the same relative paths. */ - public void setResourceSets(List resourceSets) { - this.resourceSets = resourceSets; - } - - public List getResourceSets() { - return resourceSets; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/ResourceSet.java b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/ResourceSet.java deleted file mode 100644 index 01c01abae..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/ResourceSet.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.core.deploy; - -import java.util.Map; - -import org.springframework.core.io.Resource; - -public interface ResourceSet { - /** - * List the resources, identified by their relative path. Relative paths - * must NOT start with a '/'. - */ - public Map listResources(); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/SimpleExecutables.java b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/SimpleExecutables.java deleted file mode 100644 index 5a5b8259f..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/SimpleExecutables.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.core.deploy; - -import java.io.File; -import java.util.Map; -import java.util.TreeMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.build.Distribution; -import org.argeo.slc.deploy.DeploymentData; -import org.argeo.slc.deploy.InstalledExecutables; -import org.argeo.slc.deploy.TargetData; - -public class SimpleExecutables implements InstalledExecutables { - private final static Log log = LogFactory.getLog(SimpleExecutables.class); - - private String baseDir; - private Map paths = new TreeMap(); - - private Distribution distribution; - - public String getExecutablePath(String key) { - String path = paths.get(key); - if (path == null) { - if (log.isDebugEnabled()) - log.debug("No executable path found for key " + key - + ", using the key as executable name."); - path = key; - } - - if (baseDir != null) - path = baseDir + File.separator + path; - return path; - } - - public String getDeployedSystemId() { - // TODO Auto-generated method stub - return null; - } - - public DeploymentData getDeploymentData() { - // TODO Auto-generated method stub - return null; - } - - public Distribution getDistribution() { - return distribution; - } - - public TargetData getTargetData() { - // TODO Auto-generated method stub - return null; - } - - public String getBaseDir() { - return baseDir; - } - - public void setBaseDir(String baseDir) { - this.baseDir = baseDir; - } - - public Map getPaths() { - return paths; - } - - public void setPaths(Map paths) { - this.paths = paths; - } - - public void setDistribution(Distribution distribution) { - this.distribution = distribution; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/VersionedDirSync.java b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/VersionedDirSync.java deleted file mode 100644 index 13d254366..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/VersionedDirSync.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.core.deploy; - -import java.io.File; -import java.io.IOException; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.deploy.VersioningDriver; - -/** - * Synchronizes an URL to a local directory, taking into account versioning - * information if possible. - */ -public class VersionedDirSync implements Runnable { - private final static Log log = LogFactory.getLog(VersionedDirSync.class); - - private VersioningDriver versioningDriver; - private File dir; - private String url; - private Boolean clean = false; - - private Boolean changed = null; - - public void run() { - changed = null; - if (clean) { - try { - log.info("Clean " + dir); - FileUtils.deleteDirectory(dir); - } catch (IOException e) { - throw new SlcException("Cannot delete checkout directory " - + dir, e); - } - dir.mkdirs(); - } - log.info("Checkout " + url + " to " + dir); - changed = versioningDriver.checkout(url, dir, true); - if (log.isDebugEnabled()) - log.debug("Synchronized " + url + " to " + dir); - } - - public void setVersioningDriver(VersioningDriver versioningDriver) { - this.versioningDriver = versioningDriver; - } - - public void setDir(File dir) { - this.dir = dir; - } - - public void setUrl(String url) { - this.url = url; - } - - /** Delete before checkout */ - public void setClean(Boolean clean) { - this.clean = clean; - } - - /** Whether last call has changed the directory */ - public Boolean getChanged() { - if (changed == null) - throw new SlcException("Sync has not run"); - return changed; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/package.html b/org.argeo.slc.core/src/org/argeo/slc/core/deploy/package.html deleted file mode 100644 index f3a4c5bd6..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/deploy/package.html +++ /dev/null @@ -1,6 +0,0 @@ - - - -SLC Deploy: deployment of software systems. - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionFlowGenerator.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionFlowGenerator.java deleted file mode 100644 index dc55b40f9..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionFlowGenerator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.core.execution; - -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.springframework.beans.BeansException; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.core.Ordered; -import org.springframework.core.PriorityOrdered; - -public abstract class AbstractExecutionFlowGenerator implements - BeanFactoryPostProcessor, PriorityOrdered { - private final Log log = LogFactory.getLog(getClass()); - - protected abstract Map createExecutionFlowDefinitions( - ConfigurableListableBeanFactory beanFactory); - - public void postProcessBeanFactory( - ConfigurableListableBeanFactory beanFactory) throws BeansException { - if (!(beanFactory instanceof BeanDefinitionRegistry)) { - throw new SlcException("Can only work on " - + BeanDefinitionRegistry.class); - } - - Map definitions = createExecutionFlowDefinitions(beanFactory); - - for (String beanName : definitions.keySet()) { - if (log.isTraceEnabled()) - log.debug("Registering execution flow " + beanName); - ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition( - beanName, definitions.get(beanName)); - } - } - - protected GenericBeanDefinition createDefaultFlowDefinition( - List executables) { - GenericBeanDefinition bd = new GenericBeanDefinition(); - bd.setBeanClass(DefaultExecutionFlow.class); - - MutablePropertyValues mpv = new MutablePropertyValues(); - mpv.addPropertyValue("executables", executables); - - bd.setPropertyValues(mpv); - return bd; - } - - public int getOrder() { - return Ordered.HIGHEST_PRECEDENCE; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java deleted file mode 100644 index 1d401c6b0..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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.core.execution; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionFlowDescriptorConverter; -import org.argeo.slc.execution.ExecutionModulesManager; -import org.argeo.slc.execution.RealizedFlow; - -/** Provides the base feature of an execution module manager. */ -public abstract class AbstractExecutionModulesManager implements - ExecutionModulesManager { - private final static Log log = LogFactory - .getLog(AbstractExecutionModulesManager.class); - - // private List filteredNotifiers = Collections - // .synchronizedList(new ArrayList()); - - protected abstract ExecutionFlow findExecutionFlow(String moduleName, - String moduleVersion, String flowName); - - protected abstract ExecutionContext findExecutionContext(String moduleName, - String moduleVersion); - - protected abstract ExecutionFlowDescriptorConverter getExecutionFlowDescriptorConverter( - String moduleName, String moduleVersion); - - public void execute(RealizedFlow realizedFlow) { - if (log.isTraceEnabled()) - log.trace("Executing " + realizedFlow); - - String moduleName = realizedFlow.getModuleName(); - String moduleVersion = realizedFlow.getModuleVersion(); - - Map variablesToAdd = getExecutionFlowDescriptorConverter( - moduleName, moduleVersion).convertValues( - realizedFlow.getFlowDescriptor()); - ExecutionContext executionContext = findExecutionContext(moduleName, - moduleVersion); - for (String key : variablesToAdd.keySet()) - executionContext.setVariable(key, variablesToAdd.get(key)); - - ExecutionFlow flow = findExecutionFlow(moduleName, moduleVersion, - realizedFlow.getFlowDescriptor().getName()); - - // - // Actually runs the flow, IN THIS THREAD - // - executionContext.beforeFlow(flow); - try { - flow.run(); - } finally { - executionContext.afterFlow(flow); - } - // - // - // - } - - // public void dispatchUpdateStatus(ExecutionProcess process, - // String oldStatus, String newStatus) { - // // filtered notifiers - // for (Iterator it = filteredNotifiers.iterator(); it - // .hasNext();) { - // FilteredNotifier filteredNotifier = it.next(); - // if (filteredNotifier.receiveFrom(process)) - // filteredNotifier.getNotifier().updateStatus(process, oldStatus, - // newStatus); - // } - // - // } - - // public void dispatchAddSteps(ExecutionProcess process, - // List steps) { - // process.addSteps(steps); - // for (Iterator it = filteredNotifiers.iterator(); it - // .hasNext();) { - // FilteredNotifier filteredNotifier = it.next(); - // if (filteredNotifier.receiveFrom(process)) - // filteredNotifier.getNotifier().addSteps(process, steps); - // } - // } - - // public void registerProcessNotifier(ExecutionProcessNotifier notifier, - // Map properties) { - // filteredNotifiers.add(new FilteredNotifier(notifier, properties)); - // } - // - // public void unregisterProcessNotifier(ExecutionProcessNotifier notifier, - // Map properties) { - // filteredNotifiers.remove(notifier); - // } - - // protected class FilteredNotifier { - // private final ExecutionProcessNotifier notifier; - // private final String processId; - // - // public FilteredNotifier(ExecutionProcessNotifier notifier, - // Map properties) { - // super(); - // this.notifier = notifier; - // if (properties == null) - // properties = new HashMap(); - // if (properties.containsKey(SLC_PROCESS_ID)) - // processId = properties.get(SLC_PROCESS_ID); - // else - // processId = null; - // } - // - // /** - // * Whether event from this process should be received by this listener. - // */ - // public Boolean receiveFrom(ExecutionProcess process) { - // if (processId != null) - // if (process.getUuid().equals(processId)) - // return true; - // else - // return false; - // return true; - // } - // - // @Override - // public int hashCode() { - // return notifier.hashCode(); - // } - // - // @Override - // public boolean equals(Object obj) { - // if (obj instanceof FilteredNotifier) { - // FilteredNotifier fn = (FilteredNotifier) obj; - // return notifier.equals(fn.notifier); - // } else if (obj instanceof ExecutionProcessNotifier) { - // ExecutionProcessNotifier epn = (ExecutionProcessNotifier) obj; - // return notifier.equals(epn); - // } else - // return false; - // } - // - // public ExecutionProcessNotifier getNotifier() { - // return notifier; - // } - // - // } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionValue.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionValue.java deleted file mode 100644 index 131ffec75..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractExecutionValue.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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.core.execution; - -import java.io.Serializable; - -/** Value to be used by an execution */ -public abstract class AbstractExecutionValue implements Serializable { - private static final long serialVersionUID = 1558444746120706961L; -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractSpecAttribute.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractSpecAttribute.java deleted file mode 100644 index 109c0335e..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractSpecAttribute.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.core.execution; - -import java.io.Serializable; - -import org.argeo.slc.execution.ExecutionSpecAttribute; - -/** Canonical implementation of the execution spec attribute booleans. */ -public abstract class AbstractSpecAttribute implements ExecutionSpecAttribute, - Serializable { - private static final long serialVersionUID = 6494963738891709440L; - private Boolean isImmutable = false; - private Boolean isConstant = false; - private Boolean isHidden = false; - - private String description; - - /** Has to be set at instantiation */ - public Boolean getIsImmutable() { - return isImmutable; - } - - public void setIsImmutable(Boolean isImmutable) { - this.isImmutable = isImmutable; - } - - /** Cannot be overridden at runtime */ - public Boolean getIsConstant() { - return isConstant; - } - - public void setIsConstant(Boolean isConstant) { - this.isConstant = isConstant; - } - - /** Should not be shown to the end user */ - public Boolean getIsHidden() { - return isHidden; - } - - public void setIsHidden(Boolean isHidden) { - this.isHidden = isHidden; - } - - /* - * DEPRECATED - */ - /** @deprecated use {@link #getIsImmutable()} instead */ - public Boolean getIsParameter() { - return isImmutable; - } - - /** @deprecated use {@link #getIsConstant()} instead */ - public Boolean getIsFrozen() { - return isConstant; - } - - /** @deprecated use {@link #setIsImmutable(Boolean)} instead */ - public void setIsParameter(Boolean isParameter) { - this.isImmutable = isParameter; - } - - /** @deprecated use {@link #setIsConstant(Boolean)} instead */ - public void setIsFrozen(Boolean isFrozen) { - this.isConstant = isFrozen; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getDescription() { - return description; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractSpringExecutionModule.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractSpringExecutionModule.java deleted file mode 100644 index b2252f6a2..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/AbstractSpringExecutionModule.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.core.execution; - -import org.argeo.slc.execution.ExecutionModule; - -@Deprecated -public abstract class AbstractSpringExecutionModule implements ExecutionModule - { -/* - protected ApplicationContext applicationContext; - - protected ExecutionContext executionContext; - - protected ExecutionFlowDescriptorConverter descriptorConverter = new DefaultDescriptorConverter(); - - public ExecutionModuleDescriptor getDescriptor() { - ExecutionModuleDescriptor md = new ExecutionModuleDescriptor(); - md.setName(getName()); - md.setVersion(getVersion()); - - Map executionFlows = listFlows(); - for (String name : executionFlows.keySet()) { - ExecutionFlow executionFlow = executionFlows.get(name); - - Assert.notNull(executionFlow.getName()); - Assert.state(name.equals(executionFlow.getName())); - - ExecutionSpec executionSpec = executionFlow.getExecutionSpec(); - Assert.notNull(executionSpec); - Assert.notNull(executionSpec.getName()); - - Map values = new TreeMap(); - for (String key : executionSpec.getAttributes().keySet()) { - ExecutionSpecAttribute attribute = executionSpec - .getAttributes().get(key); - - if (executionFlow.isSetAsParameter(key)) { - Object value = executionFlow.getParameter(key); - if (attribute instanceof PrimitiveSpecAttribute) { - PrimitiveValue primitiveValue = new PrimitiveValue(); - primitiveValue - .setType(((PrimitiveSpecAttribute) attribute) - .getType()); - primitiveValue.setValue(value); - values.put(key, primitiveValue); - } else if (attribute instanceof RefSpecAttribute) { - RefValue refValue = new RefValue(); - if (value instanceof ScopedObject) { - refValue.setLabel("RUNTIME " - + value.getClass().getName()); - } else { - refValue.setLabel("STATIC " - + value.getClass().getName()); - } - values.put(key, refValue); - } else if (attribute instanceof ResourceSpecAttribute) { - PrimitiveValue primitiveValue = new PrimitiveValue(); - primitiveValue - .setType(((ResourceSpecAttribute) attribute) - .getType()); - primitiveValue.setValue(value); - values.put(key, primitiveValue); - } else { - throw new SlcException("Unkown spec attribute type " - + attribute.getClass()); - } - } - - } - - ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name, - values, executionSpec); - if (executionFlow.getPath() != null) - efd.setPath(executionFlow.getPath()); - - // Add execution spec if necessary - if (!md.getExecutionSpecs().contains(executionSpec)) - md.getExecutionSpecs().add(executionSpec); - - // Add execution flow - md.getExecutionFlows().add(efd); - } - - return md; - } - - protected Map listFlows() { - GenericBeanFactoryAccessor accessor = new GenericBeanFactoryAccessor( - applicationContext); - Map executionFlows = accessor - .getBeansOfType(ExecutionFlow.class); - return executionFlows; - } - - public void execute(ExecutionFlowDescriptor executionFlowDescriptor) { - if (descriptorConverter != null) - executionContext.addVariables(descriptorConverter - .convertValues(executionFlowDescriptor)); - ExecutionFlow flow = (ExecutionFlow) applicationContext.getBean( - executionFlowDescriptor.getName(), ExecutionFlow.class); - flow.run(); - } - - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - this.applicationContext = applicationContext; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } - - public void setDescriptorConverter( - ExecutionFlowDescriptorConverter descriptorConverter) { - this.descriptorConverter = descriptorConverter; - }*/ - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultAgent.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultAgent.java deleted file mode 100644 index c692820e7..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultAgent.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 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.core.execution; - -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URLDecoder; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.argeo.slc.DefaultNameVersion; -import org.argeo.slc.NameVersion; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionModuleDescriptor; -import org.argeo.slc.execution.ExecutionModulesManager; -import org.argeo.slc.execution.ExecutionProcess; -import org.argeo.slc.execution.SlcAgent; - -/** Implements the base methods of an SLC agent. */ -public class DefaultAgent implements SlcAgent { - // private final static Log log = LogFactory.getLog(DefaultAgent.class); - /** UTF-8 charset for encoding. */ - private final static String UTF8 = "UTF-8"; - - private String agentUuid = null; - private ExecutionModulesManager modulesManager; - - private ThreadGroup processesThreadGroup; - private Map runningProcesses = Collections - .synchronizedMap(new HashMap()); - - private String defaultModulePrefix = null; - - /* - * LIFECYCLE - */ - /** Initialization */ - public void init() { - agentUuid = initAgentUuid(); - processesThreadGroup = new ThreadGroup("SLC Processes of Agent #" - + agentUuid); - } - - /** Clean up (needs to be called by overriding method) */ - public void destroy() { - } - - /** - * Called during initialization in order to determines the agent UUID. To be - * overridden. By default creates a new one per instance. - */ - protected String initAgentUuid() { - return UUID.randomUUID().toString(); - } - - /* - * SLC AGENT - */ - public void process(ExecutionProcess process) { - ProcessThread processThread = createProcessThread(processesThreadGroup, - modulesManager, process); - processThread.start(); - runningProcesses.put(process.getUuid(), processThread); - - // clean up old processes - Iterator it = runningProcesses.values().iterator(); - while (it.hasNext()) { - ProcessThread pThread = it.next(); - if (!pThread.isAlive()) - it.remove(); - } - } - - public String process(List uris) { - DefaultProcess process = new DefaultProcess(); - for (URI uri : uris) { - String[] path = uri.getPath().split("/"); - if (path.length < 3) - throw new SlcException("Badly formatted URI: " + uri); - NameVersion nameVersion = new DefaultNameVersion(path[1]); - StringBuilder flow = new StringBuilder(); - for (int i = 2; i < path.length; i++) - flow.append('/').append(path[i]); - - Map values = getQueryMap(uri.getQuery()); - // Get execution module descriptor - ExecutionModuleDescriptor emd = getExecutionModuleDescriptor( - nameVersion.getName(), nameVersion.getVersion()); - process.getRealizedFlows().add( - emd.asRealizedFlow(flow.toString(), values)); - } - process(process); - return process.getUuid(); - } - - public void kill(String processUuid) { - if (runningProcesses.containsKey(processUuid)) { - runningProcesses.get(processUuid).interrupt(); - } else { - // assume is finished - } - } - - public void waitFor(String processUuid, Long millis) { - if (runningProcesses.containsKey(processUuid)) { - try { - if (millis != null) - runningProcesses.get(processUuid).join(millis); - else - runningProcesses.get(processUuid).join(); - } catch (InterruptedException e) { - // silent - } - } else { - // assume is finished - } - } - - /** Creates the thread which will coordinate the execution for this agent. */ - protected ProcessThread createProcessThread( - ThreadGroup processesThreadGroup, - ExecutionModulesManager modulesManager, ExecutionProcess process) { - ProcessThread processThread = new ProcessThread(processesThreadGroup, - modulesManager, process); - return processThread; - } - - public ExecutionModuleDescriptor getExecutionModuleDescriptor( - String moduleName, String moduleVersion) { - // Get execution module descriptor - ExecutionModuleDescriptor emd; - try { - modulesManager - .start(new DefaultNameVersion(moduleName, moduleVersion)); - emd = modulesManager.getExecutionModuleDescriptor(moduleName, - moduleVersion); - } catch (SlcException e) { - if (defaultModulePrefix != null) { - moduleName = defaultModulePrefix + "." + moduleName; - modulesManager.start(new DefaultNameVersion(moduleName, - moduleVersion)); - emd = modulesManager.getExecutionModuleDescriptor(moduleName, - moduleVersion); - } else - throw e; - } - return emd; - } - - public List listExecutionModuleDescriptors() { - return modulesManager.listExecutionModules(); - } - - public boolean ping() { - return true; - } - - /* - * UTILITIES - */ - /** - * @param query - * can be null - */ - static Map getQueryMap(String query) { - Map map = new LinkedHashMap(); - if (query == null) - return map; - String[] params = query.split("&"); - for (String param : params) { - String[] arr = param.split("="); - String name = arr[0]; - Object value = arr.length > 1 ? param.split("=")[1] : Boolean.TRUE; - try { - map.put(URLDecoder.decode(name, UTF8), - URLDecoder.decode(value.toString(), UTF8)); - } catch (UnsupportedEncodingException e) { - throw new SlcException("Cannot decode '" + param + "'", e); - } - } - return map; - } - - /* - * BEAN - */ - public void setModulesManager(ExecutionModulesManager modulesManager) { - this.modulesManager = modulesManager; - } - - public void setDefaultModulePrefix(String defaultModulePrefix) { - this.defaultModulePrefix = defaultModulePrefix; - } - - public String getAgentUuid() { - return agentUuid; - } - - @Override - public String toString() { - return "Agent #" + getAgentUuid(); - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultAgentCli.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultAgentCli.java deleted file mode 100644 index e02d50f2f..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultAgentCli.java +++ /dev/null @@ -1,238 +0,0 @@ -package org.argeo.slc.core.execution; - -import java.net.URI; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -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.execution.ExecutionFlowDescriptor; -import org.argeo.slc.execution.ExecutionModuleDescriptor; -import org.argeo.slc.execution.ExecutionSpec; -import org.argeo.slc.execution.ExecutionSpecAttribute; -import org.argeo.slc.execution.SlcAgent; -import org.argeo.slc.execution.SlcAgentCli; - -/** - * Authenticates thread and executes synchronously a command line execution. - * Reference implementation of args to URIs algorithm. - */ -public class DefaultAgentCli implements SlcAgentCli { - private final static Log log = LogFactory.getLog(DefaultAgentCli.class); - - private final static String UTF8 = "UTF-8"; - private SlcAgent agent; -// private AuthenticationManager authenticationManager; - - private Long timeout = 24 * 60 * 60 * 1000l; - - public String process(String[] args) { -// if (SecurityContextHolder.getContext().getAuthentication() == null) { -// OsAuthenticationToken oat = new OsAuthenticationToken(); -// Authentication authentication = authenticationManager -// .authenticate(oat); -// SecurityContextHolder.getContext() -// .setAuthentication(authentication); -// } - - if (args.length > 0 && args[0].equals("help")) { - StringBuilder buf = new StringBuilder(); - help(args, buf); - log.info("\n" + buf); - return buf.toString(); - } else { - List uris = asURIs(args); - String processUuid = agent.process(uris); - agent.waitFor(processUuid, timeout); - return processUuid; - } - } - - protected void help(String[] rawArgs, StringBuilder buf) { - String[] args = Arrays.copyOfRange(rawArgs, 1, rawArgs.length); - if (args.length == 0) {// modules - for (ExecutionModuleDescriptor emd : agent - .listExecutionModuleDescriptors()) { - appendModule(emd, buf); - } - } else if (args.length == 1 && !args[0].contains("/")) {// single module - NameVersion nameVersion = new DefaultNameVersion(args[0]); - ExecutionModuleDescriptor emd = agent.getExecutionModuleDescriptor( - nameVersion.getName(), nameVersion.getVersion()); - appendModule(emd, buf); - - // flows - for (ExecutionFlowDescriptor efd : emd.getExecutionFlows()) { - buf.append(" ").append(efd.getName()); - if (efd.getDescription() != null - && !efd.getDescription().trim().equals("")) - buf.append(" : ").append(" ").append(efd.getDescription()); - buf.append('\n'); - } - return; - } else { - List uris = asURIs(args); - for (URI uri : uris) { - appendUriHelp(uri, buf); - } - } - } - - protected void appendUriHelp(URI uri, StringBuilder buf) { - String[] path = uri.getPath().split("/"); - NameVersion nameVersion = new DefaultNameVersion(path[1]); - ExecutionModuleDescriptor emd = agent.getExecutionModuleDescriptor( - nameVersion.getName(), nameVersion.getVersion()); - - StringBuilder flow = new StringBuilder(); - for (int i = 2; i < path.length; i++) - flow.append('/').append(path[i]); - String flowPath = flow.toString(); - ExecutionFlowDescriptor efd = findExecutionFlowDescriptor(emd, flowPath); - if (efd == null) - throw new SlcException("Flow " + uri + " not found"); - - appendModule(emd, buf); - - buf.append(" ").append(efd.getName()); - if (efd.getDescription() != null - && !efd.getDescription().trim().equals("")) - buf.append(" : ").append(" ").append(efd.getDescription()); - buf.append('\n'); - Map values = DefaultAgent.getQueryMap(uri.getQuery()); - ExecutionSpec spec = efd.getExecutionSpec(); - for (String attrKey : spec.getAttributes().keySet()) { - ExecutionSpecAttribute esa = spec.getAttributes().get(attrKey); - buf.append(" --").append(attrKey); - if (values.containsKey(attrKey)) - buf.append(" ").append(values.get(attrKey)); - if (esa.getValue() != null) - buf.append(" (").append(esa.getValue()).append(')'); - buf.append('\n'); - } - } - - private void appendModule(ExecutionModuleDescriptor emd, StringBuilder buf) { - buf.append("# ").append(emd.getName()); - if (emd.getDescription() != null - && !emd.getDescription().trim().equals("")) - buf.append(" : ").append(emd.getDescription()); - if (emd.getVersion() != null) - buf.append(" (v").append(emd.getVersion()).append(")"); - buf.append('\n'); - } - - public static List asURIs(String[] args) { - try { - List uris = new ArrayList(); - List leftOvers = new ArrayList(); - - Boolean hasArgs = false; - String currKey = null; - StringBuilder currUri = null; - Iterator argIt = Arrays.asList(args).iterator(); - while (argIt.hasNext()) { - String arg = argIt.next(); - if (!arg.startsWith("-")) { - if (currKey != null) {// value - currUri.append(URLEncoder.encode(arg, UTF8)); - currKey = null; - } else { // module - if (currUri != null) { - uris.add(new URI(currUri.toString())); - } - currUri = new StringBuilder("flow:"); - - String currModule = arg; - currUri.append('/').append(currModule); - if (!arg.contains("/")) { - // flow path not in arg go to next arg - if (!argIt.hasNext()) - throw new SlcException("No flow found"); - String currFlow = argIt.next(); - if (!currFlow.startsWith("/")) - currFlow = "/" + currFlow; - currUri.append(currFlow); - } - } - } else { - if (currUri == null) {// first args - leftOvers.add(arg); - } else { - String key; - if (arg.startsWith("--")) - key = arg.substring(2); - else if (arg.startsWith("-")) - key = arg.substring(1); - else { - throw new SlcException("Cannot intepret key: " - + arg); - } - - if (!hasArgs) { - currUri.append('?'); - hasArgs = true; - } else { - currUri.append('&'); - } - - // deal with boolean keys - if (currKey != null) {// value - currUri.append(URLEncoder.encode("true", UTF8)); - currKey = null; - } - - currKey = key; - currUri.append(URLEncoder.encode(key, UTF8)) - .append('='); - } - } - } - if (currUri != null) - uris.add(new URI(currUri.toString())); - return uris; - } catch (Exception e) { - throw new SlcException("Cannot convert " + Arrays.toString(args) - + " to flow URI", e); - } - } - - private ExecutionFlowDescriptor findExecutionFlowDescriptor( - ExecutionModuleDescriptor emd, String flowPath) { - ExecutionFlowDescriptor flowDescriptor = null; - for (ExecutionFlowDescriptor efd : emd.getExecutionFlows()) { - String name = efd.getName(); - // normalize name as flow path - if (!name.startsWith("/")) - name = "/" + name; - if (name.endsWith("/")) - name = name.substring(0, name.length() - 1); - if (name.equals(flowPath)) { - flowDescriptor = efd; - break; - } - } - return flowDescriptor; - } - - public void setAgent(SlcAgent agent) { - this.agent = agent; - } - -// public void setAuthenticationManager( -// AuthenticationManager authenticationManager) { -// this.authenticationManager = authenticationManager; -// } - - public void setTimeout(Long timeout) { - this.timeout = timeout; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionFlow.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionFlow.java deleted file mode 100644 index bebde7512..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionFlow.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * 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.core.execution; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionSpec; -import org.argeo.slc.execution.ExecutionSpecAttribute; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.validation.MapBindingResult; - -/** Default implementation of an execution flow. */ -public class DefaultExecutionFlow implements ExecutionFlow, InitializingBean, - BeanNameAware { - private final static Log log = LogFactory - .getLog(DefaultExecutionFlow.class); - - private final ExecutionSpec executionSpec; - private String name = null; - private Map parameters = new HashMap(); - private List executables = new ArrayList(); - - private String path; - - private Boolean failOnError = true; - - // Only needed if stacked execution flows are used - private ExecutionContext executionContext = null; - - public DefaultExecutionFlow() { - this.executionSpec = new DefaultExecutionSpec(); - } - - public DefaultExecutionFlow(ExecutionSpec executionSpec) { - this.executionSpec = executionSpec; - } - - public DefaultExecutionFlow(ExecutionSpec executionSpec, - Map parameters) { - // be sure to have an execution spec - this.executionSpec = (executionSpec == null) ? new DefaultExecutionSpec() - : executionSpec; - - // only parameters contained in the executionSpec can be set - for (String parameter : parameters.keySet()) { - if (!executionSpec.getAttributes().containsKey(parameter)) { - throw new SlcException("Parameter " + parameter - + " is not defined in the ExecutionSpec"); - } - } - - // set the parameters - this.parameters.putAll(parameters); - - // check that all the required parameters are defined - MapBindingResult errors = new MapBindingResult(parameters, "execution#" - + getName()); - for (String key : executionSpec.getAttributes().keySet()) { - ExecutionSpecAttribute attr = executionSpec.getAttributes() - .get(key); - - if (attr.getIsImmutable() && !isSetAsParameter(key)) { - errors.rejectValue(key, "Immutable but not set"); - break; - } - - if (attr.getIsConstant() && !isSetAsParameter(key)) { - errors.rejectValue(key, "Constant but not set as parameter"); - break; - } - - if (attr.getIsHidden() && !isSetAsParameter(key)) { - errors.rejectValue(key, "Hidden but not set as parameter"); - break; - } - } - - if (errors.hasErrors()) - throw new SlcException("Could not prepare execution flow: " - + errors.toString()); - - } - - public void run() { - try { - for (Runnable executable : executables) { - if (Thread.interrupted()) { - log.error("Flow '" + getName() + "' killed before '" - + executable + "'"); - Thread.currentThread().interrupt(); - return; - // throw new ThreadDeath(); - } - this.doExecuteRunnable(executable); - } - } catch (RuntimeException e) { - if (Thread.interrupted()) { - log.error("Flow '" + getName() - + "' killed while receiving an unrelated exception", e); - Thread.currentThread().interrupt(); - return; - // throw new ThreadDeath(); - } - if (failOnError) - throw e; - else { - log.error("Execution flow failed," - + " but process did not fail" - + " because failOnError property" - + " is set to false: " + e); - if (log.isTraceEnabled()) - e.printStackTrace(); - } - } - } - - /** - * List sub-runnables that would be executed if run() method would be - * called. - */ - public Iterator runnables() { - return executables.iterator(); - } - - /** - * If there is one and only one runnable wrapped return it, throw an - * exeception otherwise. - */ - public Runnable getRunnable() { - if (executables.size() == 1) - return executables.get(0); - else - throw new SlcException("There are " + executables.size() - + " runnables in flow " + getName()); - } - - public void doExecuteRunnable(Runnable runnable) { - try { - if (executionContext != null) - if (runnable instanceof ExecutionFlow) - executionContext.beforeFlow((ExecutionFlow) runnable); - runnable.run(); - } finally { - if (executionContext != null) - if (runnable instanceof ExecutionFlow) - executionContext.afterFlow((ExecutionFlow) runnable); - } - } - - public void afterPropertiesSet() throws Exception { - if (path == null) { - if (name.charAt(0) == '/') { - path = name.substring(0, name.lastIndexOf('/')); - } - } - - if (path != null) { - for (Runnable executable : executables) { - if (executable instanceof DefaultExecutionFlow) { - // so we don't need to have DefaultExecutionFlow - // implementing StructureAware - // FIXME: probably has side effects - DefaultExecutionFlow flow = (DefaultExecutionFlow) executable; - String newPath = path + '/' + flow.getName(); - flow.setPath(newPath); - log.warn(newPath + " was forcibly set on " + flow); - } - } - } - } - - public void setBeanName(String name) { - this.name = name; - } - - public void setExecutables(List executables) { - this.executables = executables; - } - - public void setParameters(Map attributes) { - this.parameters = attributes; - } - - public String getName() { - return name; - } - - public ExecutionSpec getExecutionSpec() { - return executionSpec; - } - - public Object getParameter(String parameterName) { - // Verify that there is a spec attribute - ExecutionSpecAttribute specAttr = null; - if (executionSpec.getAttributes().containsKey(parameterName)) { - specAttr = executionSpec.getAttributes().get(parameterName); - } else { - throw new SlcException("Key " + parameterName - + " is not defined in the specifications of " + toString()); - } - - if (parameters.containsKey(parameterName)) { - Object paramValue = parameters.get(parameterName); - return paramValue; - } else { - if (specAttr.getValue() != null) { - return specAttr.getValue(); - } - } - throw new SlcException("Key " + parameterName - + " is not set as parameter in " + toString()); - } - - public Boolean isSetAsParameter(String key) { - return parameters.containsKey(key) - || (executionSpec.getAttributes().containsKey(key) && executionSpec - .getAttributes().get(key).getValue() != null); - } - - @Override - public String toString() { - return new StringBuffer("Execution flow ").append(name).toString(); - } - - @Override - public boolean equals(Object obj) { - return ((ExecutionFlow) obj).getName().equals(name); - } - - @Override - public int hashCode() { - return name.hashCode(); - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public Boolean getFailOnError() { - return failOnError; - } - - public void setFailOnError(Boolean failOnError) { - this.failOnError = failOnError; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java deleted file mode 100644 index beac9175a..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java +++ /dev/null @@ -1,359 +0,0 @@ -/* - * 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.core.execution; - -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -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.ExecutionSpec; -import org.argeo.slc.execution.ExecutionSpecAttribute; -import org.springframework.aop.scope.ScopedObject; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.util.StringUtils; - -/** - * Performs conversion in both direction between data exchanged with the agent - * and the data in the application context. - */ -public class DefaultExecutionFlowDescriptorConverter implements - ExecutionFlowDescriptorConverter, ApplicationContextAware { - public final static String REF_VALUE_TYPE_BEAN_NAME = "beanName"; - - /** Workaround for https://www.spartadn.com/bugzilla/show_bug.cgi?id=206 */ - private final static String REF_VALUE_INTERNAL = "[internal]"; - - private final static Log log = LogFactory - .getLog(DefaultExecutionFlowDescriptorConverter.class); - - private ApplicationContext applicationContext; - - @SuppressWarnings("unused") - public Map convertValues( - ExecutionFlowDescriptor executionFlowDescriptor) { - Map values = executionFlowDescriptor.getValues(); - Map convertedValues = new HashMap(); - ExecutionSpec executionSpec = executionFlowDescriptor - .getExecutionSpec(); - - if (executionSpec == null && log.isTraceEnabled()) - log.warn("Execution spec is null for " + executionFlowDescriptor); - - if (values != null && executionSpec != null) { - values: for (String key : values.keySet()) { - ExecutionSpecAttribute attribute = executionSpec - .getAttributes().get(key); - - if (attribute == null) - throw new FlowConfigurationException( - "No spec attribute defined for '" + key + "'"); - - if (attribute.getIsConstant()) - continue values; - - Object value = values.get(key); - if (value instanceof PrimitiveValue) { - PrimitiveValue primitiveValue = (PrimitiveValue) value; - // TODO: check class <=> type - convertedValues.put(key, primitiveValue.getValue()); - } else if (value instanceof RefValue) { - RefValue refValue = (RefValue) value; - String type = refValue.getType(); - if (REF_VALUE_TYPE_BEAN_NAME.equals(type)) { - // FIXME: UI should send all information about spec - // - targetClass - // - name - // String executionSpecName = executionSpec.getName(); - // ExecutionSpec localSpec = (ExecutionSpec) - // applicationContext - // .getBean(executionSpecName); - // RefSpecAttribute localAttr = (RefSpecAttribute) - // localSpec - // .getAttributes().get(key); - // Class targetClass = localAttr.getTargetClass(); - // - // String primitiveType = PrimitiveUtils - // .classAsType(targetClass); - String primitiveType = null; - if (primitiveType != null) { - // not active - String ref = refValue.getRef(); - Object obj = PrimitiveUtils.convert(primitiveType, - ref); - convertedValues.put(key, obj); - } else { - String ref = refValue.getRef(); - if (ref != null && !ref.equals(REF_VALUE_INTERNAL)) { - Object obj = null; - if (applicationContext.containsBean(ref)) { - obj = applicationContext.getBean(ref); - } else { - // FIXME: hack in order to pass primitive - obj = ref; - } - convertedValues.put(key, obj); - } else { - log.warn("Cannot interpret " + refValue); - } - } - } else if (PrimitiveUtils.typeAsClass(type) != null) { - String ref = refValue.getRef(); - Object obj = PrimitiveUtils.convert(type, ref); - convertedValues.put(key, obj); - } else { - throw new FlowConfigurationException( - "Ref value type not supported: " - + refValue.getType()); - } - } else { - // default is to take the value as is - convertedValues.put(key, value); - } - } - } - return convertedValues; - } - - public void addFlowsToDescriptor(ExecutionModuleDescriptor md, - Map executionFlows) { - SortedSet set = new TreeSet( - new ExecutionFlowDescriptorComparator()); - for (String name : executionFlows.keySet()) { - ExecutionFlow executionFlow = executionFlows.get(name); - - ExecutionFlowDescriptor efd = getExecutionFlowDescriptor(executionFlow); - ExecutionSpec executionSpec = efd.getExecutionSpec(); - - // Add execution spec if necessary - if (!md.getExecutionSpecs().contains(executionSpec)) - md.getExecutionSpecs().add(executionSpec); - - // Add execution flow - set.add(efd); - // md.getExecutionFlows().add(efd); - } - md.getExecutionFlows().addAll(set); - } - - public ExecutionFlowDescriptor getExecutionFlowDescriptor( - ExecutionFlow executionFlow) { - if (executionFlow.getName() == null) - throw new FlowConfigurationException("Flow name is null: " - + executionFlow); - String name = executionFlow.getName(); - - ExecutionSpec executionSpec = executionFlow.getExecutionSpec(); - if (executionSpec == null) - throw new FlowConfigurationException("Execution spec is null: " - + executionFlow); - if (executionSpec.getName() == null) - throw new FlowConfigurationException( - "Execution spec name is null: " + executionSpec); - - Map values = new TreeMap(); - for (String key : executionSpec.getAttributes().keySet()) { - ExecutionSpecAttribute attribute = executionSpec.getAttributes() - .get(key); - - if (attribute instanceof PrimitiveSpecAttribute) { - if (executionFlow.isSetAsParameter(key)) { - Object value = executionFlow.getParameter(key); - PrimitiveValue primitiveValue = new PrimitiveValue(); - primitiveValue.setType(((PrimitiveSpecAttribute) attribute) - .getType()); - primitiveValue.setValue(value); - values.put(key, primitiveValue); - } else { - // no need to add a primitive value if it is not set, - // all necessary information is in the spec - } - } else if (attribute instanceof RefSpecAttribute) { - if (attribute.getIsConstant()) { - values.put(key, new RefValue(REF_VALUE_INTERNAL)); - } else - values.put( - key, - buildRefValue((RefSpecAttribute) attribute, - executionFlow, key)); - } else { - throw new FlowConfigurationException( - "Unkown spec attribute type " + attribute.getClass()); - } - - } - - ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name, null, - values, executionSpec); - // Takes description from spring - BeanFactory bf = getBeanFactory(); - if (bf != null) { - BeanDefinition bd = getBeanFactory().getBeanDefinition(name); - efd.setDescription(bd.getDescription()); - } - return efd; - } - - protected RefValue buildRefValue(RefSpecAttribute rsa, - ExecutionFlow executionFlow, String key) { - RefValue refValue = new RefValue(); - // FIXME: UI should be able to deal with other types - refValue.setType(REF_VALUE_TYPE_BEAN_NAME); - Class targetClass = rsa.getTargetClass(); - String primitiveType = PrimitiveUtils.classAsType(targetClass); - if (primitiveType != null) { - if (executionFlow.isSetAsParameter(key)) { - Object value = executionFlow.getParameter(key); - refValue.setRef(value.toString()); - } - refValue.setType(primitiveType); - return refValue; - } else { - - if (executionFlow.isSetAsParameter(key)) { - String ref = null; - Object value = executionFlow.getParameter(key); - if (applicationContext == null) { - log.warn("No application context declared, cannot scan ref value."); - ref = value.toString(); - } else { - - // look for a ref to the value - Map beans = getBeanFactory() - .getBeansOfType(targetClass, false, false); - // TODO: also check scoped beans - beans: for (String beanName : beans.keySet()) { - Object obj = beans.get(beanName); - if (value instanceof ScopedObject) { - // don't call methods of the target of the scope - if (obj instanceof ScopedObject) - if (value == obj) { - ref = beanName; - break beans; - } - } else { - if (obj.equals(value)) { - ref = beanName; - break beans; - } - } - } - } - if (ref == null) { - if (log.isTraceEnabled()) - log.trace("Cannot define reference for ref spec attribute " - + key - + " in " - + executionFlow - + " (" - + rsa - + ")." - + " If it is an inner bean consider put it frozen."); - ref = REF_VALUE_INTERNAL; - } else { - if (log.isTraceEnabled()) - log.trace(ref - + " is the reference for ref spec attribute " - + key + " in " + executionFlow + " (" + rsa - + ")"); - } - refValue.setRef(ref); - } - return refValue; - } - } - - /** @return can be null */ - private ConfigurableListableBeanFactory getBeanFactory() { - if (applicationContext == null) - return null; - return ((ConfigurableApplicationContext) applicationContext) - .getBeanFactory(); - } - - /** Must be use within the execution application context */ - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - this.applicationContext = applicationContext; - } - - private static class ExecutionFlowDescriptorComparator implements - Comparator { - @SuppressWarnings("deprecation") - public int compare(ExecutionFlowDescriptor o1, - ExecutionFlowDescriptor o2) { - // TODO: write unit tests for this - - String name1 = o1.getName(); - String name2 = o2.getName(); - - String path1 = o1.getPath(); - String path2 = o2.getPath(); - - // Check whether name include path - int lastIndex1 = name1.lastIndexOf('/'); - // log.debug(name1+", "+lastIndex1); - if (!StringUtils.hasText(path1) && lastIndex1 >= 0) { - path1 = name1.substring(0, lastIndex1); - name1 = name1.substring(lastIndex1 + 1); - } - - int lastIndex2 = name2.lastIndexOf('/'); - if (!StringUtils.hasText(path2) && lastIndex2 >= 0) { - path2 = name2.substring(0, lastIndex2); - name2 = name2.substring(lastIndex2 + 1); - } - - // Perform the actual comparison - if (StringUtils.hasText(path1) && StringUtils.hasText(path2)) { - if (path1.equals(path2)) - return name1.compareTo(name2); - else if (path1.startsWith(path2)) - return -1; - else if (path2.startsWith(path1)) - return 1; - else - return path1.compareTo(path2); - } else if (!StringUtils.hasText(path1) - && StringUtils.hasText(path2)) { - return 1; - } else if (StringUtils.hasText(path1) - && !StringUtils.hasText(path2)) { - return -1; - } else if (!StringUtils.hasText(path1) - && !StringUtils.hasText(path2)) { - return name1.compareTo(name2); - } else { - return 0; - } - } - - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionSpec.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionSpec.java deleted file mode 100644 index 2bce12577..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionSpec.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.core.execution; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.execution.ExecutionSpec; -import org.argeo.slc.execution.ExecutionSpecAttribute; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.ConfigurableApplicationContext; - -/** Spring based implementation of execution specifications. */ -public class DefaultExecutionSpec implements ExecutionSpec, BeanNameAware, - ApplicationContextAware, InitializingBean, Serializable { - private static final long serialVersionUID = 5159882223926926539L; - private final static Log log = LogFactory - .getLog(DefaultExecutionSpec.class); - private transient ApplicationContext applicationContext; - - private String description; - private Map attributes = new HashMap(); - - private String name = INTERNAL_NAME; - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public void setBeanName(String name) { - this.name = name; - } - - /** - * The Spring bean name (only relevant for specs declared has high-level - * beans) - */ - public String getName() { - return name; - } - - public boolean equals(Object obj) { - return ((ExecutionSpec) obj).getName().equals(name); - } - - /** - * The Spring bean description (only relevant for specs declared has - * high-level beans) - */ - public String getDescription() { - return description; - } - - private ConfigurableListableBeanFactory getBeanFactory() { - return ((ConfigurableApplicationContext) applicationContext) - .getBeanFactory(); - } - - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - public void afterPropertiesSet() throws Exception { - if (description == null) { - try { - description = getBeanFactory().getBeanDefinition(name) - .getDescription(); - } catch (NoSuchBeanDefinitionException e) { - // silent - } - } - - for (String key : attributes.keySet()) { - ExecutionSpecAttribute attr = attributes.get(key); - if (attr instanceof RefSpecAttribute) { - RefSpecAttribute rsa = (RefSpecAttribute) attr; - if (rsa.getChoices() == null) { - List choices = buildRefValueChoices(rsa); - rsa.setChoices(choices); - } - if (log.isTraceEnabled()) - log.debug("Spec attr " + key + " has " - + rsa.getChoices().size() + " choices"); - } - } - } - - /** - * Generates a list of ref value choices based on the bean available in the - * application ocntext. - */ - protected List buildRefValueChoices(RefSpecAttribute rsa) { - List choices = new ArrayList(); - if (applicationContext == null) { - log.warn("No application context declared," - + " cannot scan ref value choices."); - return choices; - } - - beanNames: for (String beanName : getBeanFactory().getBeanNamesForType( - rsa.getTargetClass(), true, false)) { - - // Since Spring 3, systemProperties is implicitly defined but has no - // bean definition - if (beanName.equals("systemProperties")) - continue beanNames; - - BeanDefinition bd = getBeanFactory().getBeanDefinition(beanName); - RefValueChoice choice = new RefValueChoice(); - choice.setName(beanName); - choice.setDescription(bd.getDescription()); - if (log.isTraceEnabled()) - log.debug("Found choice " + beanName + " for " + rsa); - - choices.add(choice); - - } - return choices; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionStack.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionStack.java deleted file mode 100644 index d1d06c698..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultExecutionStack.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.core.execution; - -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; -import java.util.UUID; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionSpecAttribute; -import org.argeo.slc.execution.ExecutionStack; - -/** Canonical implementation of an execution stack. */ -public class DefaultExecutionStack implements ExecutionStack { - - private final static Log log = LogFactory - .getLog(DefaultExecutionStack.class); - - private final Stack stack = new Stack(); - - public synchronized void enterFlow(ExecutionFlow executionFlow) { - ExecutionFlowRuntime runtime = new ExecutionFlowRuntime(executionFlow); - stack.push(runtime); - - Map specAttrs = executionFlow - .getExecutionSpec().getAttributes(); - for (String key : specAttrs.keySet()) { - if (executionFlow.isSetAsParameter(key)) { - runtime.getLocalVariables().put(key, - executionFlow.getParameter(key)); - } - } - } - - public synchronized String getCurrentStackLevelUuid() { - return stack.peek().getUuid(); - } - - public synchronized Integer getStackSize() { - return stack.size(); - } - - /** - * Looks for a set variable in the stack, starting at the upper flows - * - * @return the variable or null if not found - */ - public synchronized Object findLocalVariable(String key) { - Object obj = null; - for (int i = 0; i < stack.size(); i++) { - if (stack.get(i).getLocalVariables().containsKey(key)) { - obj = stack.get(i).getLocalVariables().get(key); - break; - } - } - return obj; - } - - public synchronized void leaveFlow(ExecutionFlow executionFlow) { - ExecutionFlowRuntime leftEf = stack.pop(); - - if (!leftEf.getExecutionFlow().getName() - .equals(executionFlow.getName())) - throw new SlcException("Asked to leave " + executionFlow - + " but last is " + leftEf); - - leftEf.getScopedObjects().clear(); - leftEf.getLocalVariables().clear(); - } - - public synchronized void addScopedObject(String name, Object obj) { - ExecutionFlowRuntime runtime = stack.peek(); - // TODO: check that the object is not set yet ? - if (log.isDebugEnabled()) { - Object existing = findScopedObject(name); - if (existing != null) - log.warn("Scoped object " + name + " of type " + obj.getClass() - + " already registered in " + runtime); - } - runtime.getScopedObjects().put(name, obj); - } - - /** @return null if not found */ - public synchronized Object findScopedObject(String name) { - Object obj = null; - for (int i = stack.size() - 1; i >= 0; i--) { - if (stack.get(i).getScopedObjects().containsKey(name)) { - obj = stack.get(i).getScopedObjects().get(name); - break; - } - } - return obj; - } - - protected static class ExecutionFlowRuntime { - private final ExecutionFlow executionFlow; - private final Map scopedObjects = new HashMap(); - private final Map localVariables = new HashMap(); - private final String uuid = UUID.randomUUID().toString(); - - public ExecutionFlowRuntime(ExecutionFlow executionFlow) { - this.executionFlow = executionFlow; - } - - public ExecutionFlow getExecutionFlow() { - return executionFlow; - } - - public Map getScopedObjects() { - return scopedObjects; - } - - public String getUuid() { - return uuid; - } - - public Map getLocalVariables() { - return localVariables; - } - - @Override - public String toString() { - return "Stack Level #" + uuid; - } - - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultProcess.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultProcess.java deleted file mode 100644 index 30211800f..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/DefaultProcess.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.argeo.slc.core.execution; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -import org.argeo.slc.execution.ExecutionProcess; -import org.argeo.slc.execution.ExecutionStep; -import org.argeo.slc.execution.RealizedFlow; - -/** Canonical implementation of an {@link ExecutionProcess} as a bean. */ -public class DefaultProcess implements ExecutionProcess { - private String uuid = UUID.randomUUID().toString(); - private String status = ExecutionProcess.NEW; - - private List steps = new ArrayList(); - private List realizedFlows = new ArrayList(); - - public String getUuid() { - return uuid; - } - - public String getStatus() { - return status; - } - - public void setStatus(String status) { - this.status = status; - } - - public void addSteps(List steps) { - steps.addAll(steps); - } - - public List getRealizedFlows() { - return realizedFlows; - } - - public List getSteps() { - return steps; - } - - public void setSteps(List steps) { - this.steps = steps; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public void setRealizedFlows(List realizedFlows) { - this.realizedFlows = realizedFlows; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionAspect.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionAspect.java deleted file mode 100644 index b50b78f51..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionAspect.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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.core.execution; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionStack; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; - -@Aspect -/** Aspect intercepting calls on execution flows and contexts. */ -public class ExecutionAspect { - private final static Log log = LogFactory.getLog(ExecutionAspect.class); - - private ExecutionStack executionStack; - private ExecutionContext executionContext; - - @Around("flowExecution()") - public void aroundFlow(ProceedingJoinPoint pjp) throws Throwable { - // IMPORTANT: Make sure that the execution context is called before the - // execution stack - executionContext.getUuid(); - - ExecutionFlow executionFlow = (ExecutionFlow) pjp.getTarget(); - executionStack.enterFlow(executionFlow); - executionContext.setVariable(ExecutionContext.VAR_FLOW_ID, - executionStack.getCurrentStackLevelUuid()); - executionContext.setVariable(ExecutionContext.VAR_FLOW_NAME, - executionFlow.getName()); - - logStackEvent("=> ", executionFlow); - try { - // Actually execute the flow - pjp.proceed(); - } finally { - logStackEvent("<= ", executionFlow); - executionStack.leaveFlow(executionFlow); - } - } - - @Around("getVariable()") - public Object aroundGetVariable(ProceedingJoinPoint pjp) throws Throwable { - Object obj = pjp.proceed(); - // if the variable was not found, look in the stack starting at the - // upper flows - if (obj == null) { - String key = pjp.getArgs()[0].toString(); - obj = executionStack.findLocalVariable(key); - } - return obj; - } - - @Pointcut("execution(void org.argeo.slc.execution.ExecutionFlow.run())") - public void flowExecution() { - } - - @Pointcut("execution(* org.argeo.slc.execution.ExecutionContext.getVariable(..))") - public void getVariable() { - } - - public void setExecutionStack(ExecutionStack executionStack) { - this.executionStack = executionStack; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } - - protected void logStackEvent(String symbol, ExecutionFlow executionFlow) { - Integer stackSize = executionStack.getStackSize(); - if (log.isTraceEnabled()) - log.debug(depthSpaces(stackSize) + symbol + executionFlow + " #" - + executionStack.getCurrentStackLevelUuid() + ", depth=" - + stackSize); - if (log.isDebugEnabled()) - log.debug(depthSpaces(stackSize) + symbol + executionFlow); - } - - protected void logRunnableExecution(ExecutionFlow executionFlow, - Runnable runnable) { - Integer stackSize = executionStack.getStackSize(); - if (log.isDebugEnabled()) - log.debug(depthSpaces(stackSize + 1) - + runnable.getClass().getSimpleName() + " in " - + executionFlow); - } - - private String depthSpaces(int depth) { - StringBuffer buf = new StringBuffer(depth * 2); - for (int i = 0; i < depth; i++) - buf.append(" "); - return buf.toString(); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java deleted file mode 100644 index 84c932ee2..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * 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.core.execution; - -import java.beans.PropertyDescriptor; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.springframework.beans.BeansException; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.PropertyValue; -import org.springframework.beans.PropertyValues; -import org.springframework.beans.factory.BeanDefinitionStoreException; -import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; -import org.springframework.beans.factory.config.TypedStringValue; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.support.ManagedSet; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * Spring post processor which ensures that execution parameters are properly - * set. It is used at two levels: first during instantiation for instantiation - * parameters which allow to implement templates, then at runtime in order to - * interpret @{} placeholders when object of scope execution are instantiated. - */ -public class ExecutionParameterPostProcessor extends - InstantiationAwareBeanPostProcessorAdapter { - - private final static Log log = LogFactory - .getLog(ExecutionParameterPostProcessor.class); - - private ExecutionContext executionContext; - private InstantiationManager instantiationManager; - - private String placeholderPrefix = "@{"; - private String placeholderSuffix = "}"; - private String nullValue; - - @Override - public PropertyValues postProcessPropertyValues(PropertyValues pvs, - PropertyDescriptor[] pds, Object bean, String beanName) - throws BeansException { - - // TODO: resolve at execution only if scope is execution - // TODO: deal with placeholders in RuntimeBeanReference and - // RuntimeBeanNameReference - - MutablePropertyValues newPvs = new MutablePropertyValues(); - - boolean changesOccured = false; - - for (PropertyValue pv : pvs.getPropertyValues()) { - Object convertedValue = resolveValue(beanName, bean, pv.getValue()); - newPvs.addPropertyValue(new PropertyValue(pv, convertedValue)); - if (convertedValue != pv.getValue()) { - changesOccured = true; - } - } - - return changesOccured ? newPvs : pvs; - } - - @Override - public boolean postProcessAfterInstantiation(Object bean, String beanName) - throws BeansException { - if (bean instanceof ExecutionFlow) - instantiationManager.flowInitializationStarted( - (ExecutionFlow) bean, beanName); - return true; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - if (bean instanceof ExecutionFlow) - instantiationManager.flowInitializationFinished( - (ExecutionFlow) bean, beanName); - return bean; - } - - protected String resolvePlaceholder(Object bean, String placeholder) { - if (instantiationManager.isInFlowInitialization()) - return instantiationManager.getInitializingFlowParameter( - placeholder).toString(); - - else {// execution - // next call fail if no execution context available - Object obj = executionContext.getVariable(placeholder); - if (obj != null) { - return obj.toString(); - } - } - - return null; - } - - public Object resolveValue(String beanName, Object bean, Object value) { - if (value instanceof TypedStringValue) { - TypedStringValue tsv = (TypedStringValue) value; - String originalValue = tsv.getValue(); - - String convertedValue = resolveString(beanName, bean, originalValue); - if (convertedValue == null) - return null; - return convertedValue.equals(originalValue) ? value - : new TypedStringValue(convertedValue); - } else if (value instanceof String) { - String originalValue = value.toString(); - String convertedValue = resolveString(beanName, bean, originalValue); - if (convertedValue == null) - return null; - return convertedValue.equals(originalValue) ? value - : convertedValue; - } else if (value instanceof ManagedMap) { - Map mapVal = (Map) value; - - Map newContent = new ManagedMap(); - boolean entriesModified = false; - for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) { - Map.Entry entry = (Map.Entry) it.next(); - Object key = entry.getKey(); - int keyHash = (key != null ? key.hashCode() : 0); - Object newKey = resolveValue(beanName, bean, key); - int newKeyHash = (newKey != null ? newKey.hashCode() : 0); - Object val = entry.getValue(); - Object newVal = resolveValue(beanName, bean, val); - newContent.put(newKey, newVal); - entriesModified = entriesModified - || (newVal != val || newKey != key || newKeyHash != keyHash); - } - - return entriesModified ? newContent : value; - } else if (value instanceof ManagedList) { - List listVal = (List) value; - List newContent = new ManagedList(); - boolean valueModified = false; - - for (int i = 0; i < listVal.size(); i++) { - Object elem = listVal.get(i); - Object newVal = resolveValue(beanName, bean, elem); - newContent.add(newVal); - if (!ObjectUtils.nullSafeEquals(newVal, elem)) { - valueModified = true; - } - } - return valueModified ? newContent : value; - } else if (value instanceof ManagedSet) { - Set setVal = (Set) value; - Set newContent = new ManagedSet(); - boolean entriesModified = false; - for (Iterator it = setVal.iterator(); it.hasNext();) { - Object elem = it.next(); - int elemHash = (elem != null ? elem.hashCode() : 0); - Object newVal = resolveValue(beanName, bean, elem); - int newValHash = (newVal != null ? newVal.hashCode() : 0); - newContent.add(newVal); - entriesModified = entriesModified - || (newVal != elem || newValHash != elemHash); - } - return entriesModified ? newContent : value; - } else { - // log.debug(beanName + ": " + value.getClass() + " : " + value); - return value; - } - - } - - private String resolveString(String beanName, Object bean, String strVal) { - // in case is passed - if (strVal == null) - return null; - - String value = parseStringValue(bean, strVal, new HashSet()); - - if (value == null) - throw new SlcException("Could not resolve placeholder '" + strVal - + "' in bean '" + beanName + "'"); - - return (value.equals(nullValue) ? null : value); - } - - public void setPlaceholderPrefix(String placeholderPrefix) { - this.placeholderPrefix = placeholderPrefix; - } - - public void setPlaceholderSuffix(String placeholderSuffix) { - this.placeholderSuffix = placeholderSuffix; - } - - public void setNullValue(String nullValue) { - this.nullValue = nullValue; - } - - public void setInstantiationManager( - InstantiationManager instantiationManager) { - this.instantiationManager = instantiationManager; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } - - // - // Following methods hacked from the internals of - // PropertyPlaceholderConfigurer - // - - protected String parseStringValue(Object bean, String strVal, - Set visitedPlaceholders) - throws BeanDefinitionStoreException { - - // in case is passed - if (strVal == null) - return null; - - StringBuffer buf = new StringBuffer(strVal); - - int startIndex = strVal.indexOf(placeholderPrefix); - while (startIndex != -1) { - int endIndex = findPlaceholderEndIndex(buf, startIndex); - if (endIndex != -1) { - String placeholder = buf.substring(startIndex - + placeholderPrefix.length(), endIndex); - if (!visitedPlaceholders.add(placeholder)) { - throw new BeanDefinitionStoreException( - "Circular placeholder reference '" + placeholder - + "' in property definitions"); - } - // Recursive invocation, parsing placeholders contained in - // the placeholder key. - placeholder = parseStringValue(bean, placeholder, - visitedPlaceholders); - // Now obtain the value for the fully resolved key... - String propVal = resolvePlaceholder(bean, placeholder); - if (propVal != null) { - // Recursive invocation, parsing placeholders contained - // in the - // previously resolved placeholder value. - propVal = parseStringValue(bean, propVal, - visitedPlaceholders); - buf.replace(startIndex, - endIndex + placeholderSuffix.length(), propVal); - if (log.isTraceEnabled()) { - log.trace("Resolved placeholder '" + placeholder + "'"); - } - startIndex = buf.indexOf(placeholderPrefix, startIndex - + propVal.length()); - } else { - throw new BeanDefinitionStoreException( - "Could not resolve placeholder '" + placeholder - + "'"); - } - visitedPlaceholders.remove(placeholder); - } else { - startIndex = -1; - } - } - - return buf.toString(); - } - - private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { - int index = startIndex + placeholderPrefix.length(); - int withinNestedPlaceholder = 0; - while (index < buf.length()) { - if (StringUtils.substringMatch(buf, index, placeholderSuffix)) { - if (withinNestedPlaceholder > 0) { - withinNestedPlaceholder--; - index = index + placeholderSuffix.length(); - } else { - return index; - } - } else if (StringUtils - .substringMatch(buf, index, placeholderPrefix)) { - withinNestedPlaceholder++; - index = index + placeholderPrefix.length(); - } else { - index++; - } - } - return -1; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionResources.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionResources.java deleted file mode 100644 index 759a12542..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionResources.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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.core.execution; - -import java.io.File; - -import org.springframework.core.io.Resource; - -/** Provides write access to resources during execution */ -public interface ExecutionResources { - /** The base directory where this execution can write */ - public File getWritableBaseDir(); - - /** Allocates a local file in the writable area and return it as a resource. */ - public Resource getWritableResource(String relativePath); - - /** - * Allocates a local file in the writable area and return it as a fully - * qualified OS path. - */ - public String getWritableOsPath(String relativePath); - - /** - * Allocates a local file in the writable area and return it as a - * {@link File}. - */ - public File getWritableOsFile(String relativePath); - - /** - * Returns the resource as a file path. If the resource is not writable it - * is copied as a file in the writable area and the path to this local file - * is returned. - */ - public String getAsOsPath(Resource resource, Boolean overwrite); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionResourcesFactoryBean.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionResourcesFactoryBean.java deleted file mode 100644 index 0b887da5a..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionResourcesFactoryBean.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.core.execution; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; - -/** Workaround when execution placedholders needs to be passed. */ -public class ExecutionResourcesFactoryBean implements FactoryBean { - private ExecutionResources executionResources; - private String relativePath; - - public Resource getObject() throws Exception { - Assert.notNull(executionResources, "executionResources is null"); - Assert.notNull(relativePath, "relativePath is null"); - return executionResources.getWritableResource(relativePath); - } - - public Class getObjectType() { - return Resource.class; - } - - public boolean isSingleton() { - return true; - } - - public void setExecutionResources(ExecutionResources executionResources) { - this.executionResources = executionResources; - } - - public void setRelativePath(String relativePath) { - this.relativePath = relativePath; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionScope.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionScope.java deleted file mode 100644 index 4ac0de200..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionScope.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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.core.execution; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.UnsupportedException; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionSpec; -import org.argeo.slc.execution.ExecutionStack; -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.config.Scope; - -/** - * When Spring beans are instantiated with this scope, the same instance is - * reused across an execution. - */ -public class ExecutionScope implements Scope { - private final static Log log = LogFactory.getLog(ExecutionScope.class); - - private final ThreadLocal executionStack = new ThreadLocal(); - public final ThreadLocal executionStackBeanName = new ThreadLocal(); - - private final ThreadLocal executionContext = new ThreadLocal(); - private final ThreadLocal executionContextBeanName = new ThreadLocal(); - - public Object get(String name, ObjectFactory objectFactory) { - if (log.isTraceEnabled()) - log.debug("Get execution scoped bean " + name); - - // shortcuts - if (executionStackBeanName.get() != null - && name.equals(executionStackBeanName.get())) { - return executionStack.get(); - } - - if (executionContextBeanName.get() != null - && name.equals(executionContextBeanName.get())) { - return executionContext.get(); - } - - // execution context must be defined first - if (executionContext.get() == null) { - Object obj = objectFactory.getObject(); - if (obj instanceof ExecutionContext) { - return dealWithSpecialScopedObject(name, executionContext, - executionContextBeanName, (ExecutionContext) obj); - } else { - // TODO: use execution context wrapper - throw new SlcException("No execution context has been defined."); - } - } - - // for other scoped objects, an executions stack must be available - if (executionStack.get() == null) { - Object obj = objectFactory.getObject(); - if (obj instanceof ExecutionStack) { - return dealWithSpecialScopedObject(name, executionStack, - executionStackBeanName, (ExecutionStack) obj); - } else { - throw new SlcException("No execution stack has been defined."); - } - } - - // see if the execution stack already knows the object - Object obj = executionStack.get().findScopedObject(name); - if (obj == null) { - obj = objectFactory.getObject(); - if (obj instanceof ExecutionContext) - throw new SlcException( - "Only one execution context can be defined per thread"); - if (obj instanceof ExecutionStack) - throw new SlcException( - "Only one execution stack can be defined per thread"); - - checkForbiddenClasses(obj); - - executionStack.get().addScopedObject(name, obj); - } - return obj; - - } - - protected T dealWithSpecialScopedObject(String name, - ThreadLocal threadLocal, - ThreadLocal threadLocalBeanName, T newObj) { - - T obj = threadLocal.get(); - if (obj == null) { - obj = newObj; - threadLocal.set(obj); - threadLocalBeanName.set(name); - if (log.isTraceEnabled()) { - log.debug(obj.getClass() + " instantiated. (beanName=" + name - + ")"); - } - return obj; - } else { - throw new SlcException("Only one scoped " + obj.getClass() - + " can be defined per thread"); - } - - } - - protected void checkForbiddenClasses(Object obj) { - Class clss = obj.getClass(); - if (ExecutionFlow.class.isAssignableFrom(clss) - || ExecutionSpec.class.isAssignableFrom(clss)) { - throw new UnsupportedException("Execution scoped object", clss); - } - } - - public String getConversationId() { - // TODO: is it the most relevant? - return executionContext.get().getUuid(); - } - - public void registerDestructionCallback(String name, Runnable callback) { - if (Thread.currentThread() instanceof ExecutionThread) { - ExecutionThread executionThread = (ExecutionThread) Thread - .currentThread(); - executionThread.registerDestructionCallback(name, callback); - } - } - - public Object remove(String name) { - if (log.isDebugEnabled()) - log.debug("Remove object " + name); - throw new UnsupportedOperationException(); - } - - public Object resolveContextualObject(String key) { - return executionContext.get().getVariable(key); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionThread.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionThread.java deleted file mode 100644 index 31e952d4a..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ExecutionThread.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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.core.execution; - -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.List; - -import javax.security.auth.Subject; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionFlowDescriptor; -import org.argeo.slc.execution.ExecutionModulesManager; -import org.argeo.slc.execution.ExecutionStep; -import org.argeo.slc.execution.RealizedFlow; - -/** Thread of a single execution */ -public class ExecutionThread extends Thread { - public final static String SYSPROP_EXECUTION_AUTO_UPGRADE = "slc.execution.autoupgrade"; - private final static Log log = LogFactory.getLog(ExecutionThread.class); - - private ExecutionModulesManager executionModulesManager; - private final RealizedFlow realizedFlow; - private final AccessControlContext accessControlContext; - - private List destructionCallbacks = new ArrayList(); - - public ExecutionThread(ProcessThreadGroup processThreadGroup, ExecutionModulesManager executionModulesManager, - RealizedFlow realizedFlow) { - super(processThreadGroup, "Flow " + realizedFlow.getFlowDescriptor().getName()); - this.realizedFlow = realizedFlow; - this.executionModulesManager = executionModulesManager; - accessControlContext = AccessController.getContext(); - } - - public void run() { - // authenticate thread - // Authentication authentication = getProcessThreadGroup() - // .getAuthentication(); - // if (authentication == null) - // throw new SlcException("Can only execute authenticated threads"); - // SecurityContextHolder.getContext().setAuthentication(authentication); - - // Retrieve execution flow descriptor - ExecutionFlowDescriptor executionFlowDescriptor = realizedFlow.getFlowDescriptor(); - String flowName = executionFlowDescriptor.getName(); - - getProcessThreadGroup().dispatchAddStep( - new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.PHASE_START, "Flow " + flowName)); - - try { - Subject subject = Subject.getSubject(accessControlContext); - try { - Subject.doAs(subject, new PrivilegedExceptionAction() { - - @Override - public Void run() throws Exception { - String autoUpgrade = System.getProperty(SYSPROP_EXECUTION_AUTO_UPGRADE); - if (autoUpgrade != null && autoUpgrade.equals("true")) - executionModulesManager.upgrade(realizedFlow.getModuleNameVersion()); - executionModulesManager.start(realizedFlow.getModuleNameVersion()); - // - // START FLOW - // - executionModulesManager.execute(realizedFlow); - // END FLOW - return null; - } - - }); - } catch (PrivilegedActionException privilegedActionException) { - throw (Exception) privilegedActionException.getCause(); - } - } catch (FlowConfigurationException e) { - String msg = "Configuration problem with flow " + flowName + ":\n" + e.getMessage(); - log.error(msg); - getProcessThreadGroup().dispatchAddStep( - new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.ERROR, msg + " " + e.getMessage())); - } catch (Exception e) { - // TODO: re-throw exception ? - String msg = "Execution of flow " + flowName + " failed."; - log.error(msg, e); - getProcessThreadGroup().dispatchAddStep( - new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.ERROR, msg + " " + e.getMessage())); - } finally { - getProcessThreadGroup().dispatchAddStep( - new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.PHASE_END, "Flow " + flowName)); - processDestructionCallbacks(); - } - } - - private synchronized void processDestructionCallbacks() { - for (int i = destructionCallbacks.size() - 1; i >= 0; i--) { - try { - destructionCallbacks.get(i).run(); - } catch (Exception e) { - log.warn("Could not process destruction callback " + i + " in thread " + getName(), e); - } - } - } - - /** - * Gather object destruction callback to be called in reverse order at the - * end of the thread - */ - synchronized void registerDestructionCallback(String name, Runnable callback) { - destructionCallbacks.add(callback); - } - - protected ProcessThreadGroup getProcessThreadGroup() { - return (ProcessThreadGroup) getThreadGroup(); - } -} \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/FileExecutionResources.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/FileExecutionResources.java deleted file mode 100644 index d225cd193..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/FileExecutionResources.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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.core.execution; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.SimpleDateFormat; -import java.util.Date; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionContext; -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; - -/** Implements write access to resources based on standard Java {@link File} */ -public class FileExecutionResources implements ExecutionResources { - private final static Log log = LogFactory - .getLog(FileExecutionResources.class); - protected final static String DEFAULT_EXECUTION_RESOURCES_DIRNAME = "executionResources"; - public final static String DEFAULT_EXECUTION_RESOURCES_TMP_PATH = System - .getProperty("java.io.tmpdir") - + File.separator - + System.getProperty("user.name") - + File.separator - + "slc" - + File.separator + DEFAULT_EXECUTION_RESOURCES_DIRNAME; - - private File baseDir; - private ExecutionContext executionContext; - private String prefixDatePattern = "yyMMdd_HHmmss_SSS"; - private SimpleDateFormat sdf = null; - - private Boolean withExecutionSubdirectory = true; - - public FileExecutionResources() { - // Default base directory - String osgiInstanceArea = System.getProperty("osgi.instance.area"); - String osgiInstanceAreaDefault = System - .getProperty("osgi.instance.area.default"); - - if (osgiInstanceArea != null) { - // within OSGi with -data specified - osgiInstanceArea = removeFilePrefix(osgiInstanceArea); - baseDir = new File(osgiInstanceArea + File.separator - + DEFAULT_EXECUTION_RESOURCES_DIRNAME); - } else if (osgiInstanceAreaDefault != null) { - // within OSGi without -data specified - osgiInstanceAreaDefault = removeFilePrefix(osgiInstanceAreaDefault); - baseDir = new File(osgiInstanceAreaDefault + File.separator - + DEFAULT_EXECUTION_RESOURCES_DIRNAME); - } else {// outside OSGi - baseDir = new File(DEFAULT_EXECUTION_RESOURCES_TMP_PATH); - } - } - - protected SimpleDateFormat sdf() { - // Lazy init in case prefix has been externally set - if (sdf == null) - sdf = new SimpleDateFormat(prefixDatePattern); - return sdf; - } - - public Resource getWritableResource(String relativePath) { - File file = getFile(relativePath); - File parentDir = file.getParentFile(); - - if (!parentDir.exists()) { - // Creates if necessary - if (log.isTraceEnabled()) - log.trace("Creating parent directory " + parentDir); - parentDir.mkdirs(); - } - Resource resource = new FileSystemResource(file); - - if (log.isTraceEnabled()) - log.trace("Returns writable resource " + resource); - return resource; - } - - public String getWritableOsPath(String relativePath) { - try { - return getFile(relativePath).getCanonicalPath(); - } catch (IOException e) { - throw new SlcException("Cannot find canonical path", e); - } - } - - public File getWritableOsFile(String relativePath) { - return getFile(relativePath); - } - - public String getAsOsPath(Resource resource, Boolean overwrite) { - File file = fileFromResource(resource); - if (file != null) - try { - if (log.isTraceEnabled()) - log.debug("Directly interpret " + resource + " as OS file " - + file); - return file.getCanonicalPath(); - } catch (IOException e1) { - // silent - } - - if (log.isTraceEnabled()) - log.trace("Resource " + resource - + " is not available on the file system. Retrieving it..."); - - InputStream in = null; - OutputStream out = null; - try { - String path = resource.getURL().getPath(); - file = getFile(path); - if (file.exists() && !overwrite) - return file.getCanonicalPath(); - - file.getParentFile().mkdirs(); - in = resource.getInputStream(); - out = new FileOutputStream(file); - IOUtils.copy(in, out); - if (log.isDebugEnabled()) - log.debug("Retrieved " + resource + " to OS file " + file); - return file.getCanonicalPath(); - } catch (IOException e) { - throw new SlcException("Could not make resource " + resource - + " an OS file.", e); - } finally { - IOUtils.closeQuietly(in); - IOUtils.closeQuietly(out); - } - } - - /** - * Extract the underlying file from the resource. - * - * @return the file or null if no files support this resource. - */ - protected File fileFromResource(Resource resource) { - try { - return resource.getFile(); - } catch (IOException e) { - return null; - } - - } - - protected File getFile(String relativePath) { - File writableBaseDir = getWritableBaseDir(); - return new File(writableBaseDir.getPath() + File.separator - + relativePath.replace('/', File.separatorChar)); - } - - public File getWritableBaseDir() { - if (withExecutionSubdirectory) { - Date executionContextCreationDate = (Date) executionContext - .getVariable(ExecutionContext.VAR_EXECUTION_CONTEXT_CREATION_DATE); - Assert.notNull(executionContext, "execution context is null"); - String path = baseDir.getPath() + File.separator - + sdf().format(executionContextCreationDate); - // TODO write execution id somewhere? like in a txt file - return new File(path); - } else { - return baseDir; - } - } - - protected String removeFilePrefix(String url) { - if (url.startsWith("file:")) - return url.substring("file:".length()); - else if (url.startsWith("reference:file:")) - return url.substring("reference:file:".length()); - else - return url; - } - - public void setBaseDir(File baseDir) { - this.baseDir = baseDir; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } - - public void setPrefixDatePattern(String prefixDatePattern) { - this.prefixDatePattern = prefixDatePattern; - } - - public File getBaseDir() { - return baseDir; - } - - public ExecutionContext getExecutionContext() { - return executionContext; - } - - public String getPrefixDatePattern() { - return prefixDatePattern; - } - - /** Default is true. */ - public void setWithExecutionSubdirectory(Boolean withExecutionSubdirectory) { - this.withExecutionSubdirectory = withExecutionSubdirectory; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/FlowConfigurationException.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/FlowConfigurationException.java deleted file mode 100644 index aeda5aca5..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/FlowConfigurationException.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.argeo.slc.core.execution; - -import org.argeo.slc.SlcException; - -/** The stack trace of such exceptions does not need to be displayed */ -public class FlowConfigurationException extends SlcException { - private static final long serialVersionUID = 8456260596346797321L; - - public FlowConfigurationException(String message) { - super(message); - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/InstantiationManager.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/InstantiationManager.java deleted file mode 100644 index 60e93ec15..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/InstantiationManager.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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.core.execution; - -import java.util.Stack; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionSpecAttribute; - -/** Manage parameters that need to be set during the instantiation of a flow */ -public class InstantiationManager { - - private final static Log log = LogFactory - .getLog(InstantiationManager.class); - - private ThreadLocal> flowStack = new ThreadLocal>(); - - public Object createRef(String name) { - - if ((flowStack.get() == null) || flowStack.get().empty()) { - throw new SlcException("No flow is currently initializing." - + " Declare ParameterRef as inner beans or prototypes."); - } - - return getInitializingFlowParameter(name); - } - - public void flowInitializationStarted(ExecutionFlow flow, String flowName) { - // set the flow name if it is DefaultExecutionFlow - if (flow instanceof DefaultExecutionFlow) { - ((DefaultExecutionFlow) flow).setBeanName(flowName); - } - - if (log.isTraceEnabled()) - log.trace("Start initialization of " + flow.hashCode() + " (" - + flow + " - " + flow.getClass() + ")"); - - // log.info("# flowInitializationStarted " + flowName); - // create a stack for this thread if there is none - if (flowStack.get() == null) { - flowStack.set(new Stack()); - } - flowStack.get().push(flow); - } - - public void flowInitializationFinished(ExecutionFlow flow, String flowName) { - if (log.isTraceEnabled()) - log.trace("Finish initialization of " + flow.hashCode() + " (" - + flow + " - " + flow.getClass() + ")"); - - if (flowStack.get() != null) { - ExecutionFlow registeredFlow = flowStack.get().pop(); - if (registeredFlow != null) { - if (!flow.getName().equals(registeredFlow.getName())) - throw new SlcException("Current flow is " + flow); - // log.info("# flowInitializationFinished " + flowName); - // initializingFlow.set(null); - } - } else { - // happens for flows imported as services - log.warn("flowInitializationFinished - Flow Stack is null"); - } - } - - protected ExecutionFlow findInitializingFlowWithParameter(String key) { - if ((flowStack.get() == null) || flowStack.get().empty()) - throw new SlcException("No initializing flow available."); - - // first look in the outer flow (that may override parameters) - for (int i = 0; i < flowStack.get().size(); i++) { - if (flowStack.get().elementAt(i).isSetAsParameter(key)) { - return flowStack.get().elementAt(i); - } - } - throw new SlcException("Key " + key + " is not set as parameter in " - + flowStack.get().firstElement().toString() + " (stack size=" - + flowStack.get().size() + ")"); - - } - - public Object getInitializingFlowParameter(String key) { - return findInitializingFlowWithParameter(key).getParameter(key); - } - - public Class getInitializingFlowParameterClass(String key) { - ExecutionSpecAttribute attr = findInitializingFlowWithParameter(key) - .getExecutionSpec().getAttributes().get(key); - if (attr instanceof RefSpecAttribute) - return ((RefSpecAttribute) attr).getTargetClass(); - else if (attr instanceof PrimitiveSpecAttribute) { - String type = ((PrimitiveSpecAttribute) attr).getType(); - Class clss = PrimitiveUtils.typeAsClass(type); - if (clss == null) - throw new SlcException("Cannot convert type " + type - + " to class."); - return clss; - } else - return null; - } - - public Boolean isInFlowInitialization() { - return (flowStack.get() != null) && !flowStack.get().empty(); - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/MapExecutionContext.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/MapExecutionContext.java deleted file mode 100644 index 324f97305..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/MapExecutionContext.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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.core.execution; - -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionStack; -import org.springframework.beans.BeanWrapper; -import org.springframework.beans.BeanWrapperImpl; -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; - -public class MapExecutionContext implements ExecutionContext, - ApplicationContextAware { - private final Map variables = Collections - .synchronizedMap(new HashMap()); - - private final String uuid; - - private ApplicationContext applicationContext; - private ExecutionStack executionStack; - - public MapExecutionContext() { - uuid = UUID.randomUUID().toString(); - variables.put(VAR_EXECUTION_CONTEXT_ID, uuid); - variables.put(VAR_EXECUTION_CONTEXT_CREATION_DATE, new Date()); - } - - public void setVariable(String key, Object value) { - // check if we do not refer to a bean - int lastInd = key.lastIndexOf('.'); - if (applicationContext != null && lastInd > 0) { - String beanName = key.substring(0, lastInd); - String propertyName = key.substring(lastInd + 1); - if (applicationContext.containsBean(beanName)) { - BeanWrapper beanWrapper = new BeanWrapperImpl( - applicationContext.getBean(beanName)); - if (!beanWrapper.isWritableProperty(propertyName)) - throw new SlcException("No writable property " - + propertyName + " in bean " + beanName); - beanWrapper.setPropertyValue(propertyName, value); - } - } - - variables.put(key, value); - } - - public Object getVariable(String key) { - // check if we do not refer to a bean - int lastInd = key.lastIndexOf('.'); - if (applicationContext != null && lastInd > 0) { - String beanName = key.substring(0, lastInd); - String propertyName = key.substring(lastInd + 1); - if (applicationContext.containsBean(beanName)) { - BeanWrapper beanWrapper = new BeanWrapperImpl( - applicationContext.getBean(beanName)); - if (!beanWrapper.isReadableProperty(propertyName)) - throw new SlcException("No readable property " - + propertyName + " in bean " + beanName); - Object obj = beanWrapper.getPropertyValue(propertyName); - return obj; - } - } - - Object value = variables.get(key); - // try system property in last resort - if (value == null) - value = System.getProperty(key); - - // if the variable was not found, look in the stack starting at the - // upper flows - if (value == null) { - value = executionStack.findLocalVariable(key); - } - return value; - } - - public String getUuid() { - return uuid; - } - - @Override - public void beforeFlow(ExecutionFlow executionFlow) { - // getUuid(); - executionStack.enterFlow(executionFlow); - setVariable(ExecutionContext.VAR_FLOW_ID, - executionStack.getCurrentStackLevelUuid()); - setVariable(ExecutionContext.VAR_FLOW_NAME, executionFlow.getName()); - } - - @Override - public void afterFlow(ExecutionFlow executionFlow) { - executionStack.leaveFlow(executionFlow); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof ExecutionContext) - return uuid.equals(((ExecutionContext) obj).getUuid()); - return false; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "#" + uuid; - } - - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - this.applicationContext = applicationContext; - } - - public void setExecutionStack(ExecutionStack executionStack) { - this.executionStack = executionStack; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/OsFileFactoryBean.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/OsFileFactoryBean.java deleted file mode 100644 index e524970cf..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/OsFileFactoryBean.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.core.execution; - -import java.io.File; - -import org.springframework.beans.factory.FactoryBean; -import org.springframework.core.io.Resource; -import org.springframework.util.Assert; - -/** Retrieve an OS File from the given resource. */ -public class OsFileFactoryBean implements FactoryBean { - private ExecutionResources executionResources; - private Resource resource; - private Boolean overwrite = false; - - /** Return an existing file on the file system. */ - public String getObject() throws Exception { - Assert.notNull(executionResources, "executionResources is null"); - Assert.notNull(resource, "resource is null"); - return executionResources.getAsOsPath(resource, overwrite); - } - - /** Return {@link Object} because CGLIB is unable to proxy {@link File}. */ - public Class getObjectType() { - return CharSequence.class; - } - - public boolean isSingleton() { - return false; - } - - /** The execution resources object. */ - public void setExecutionResources(ExecutionResources executionResources) { - this.executionResources = executionResources; - } - - /** The resource to access. */ - public void setResource(Resource resource) { - this.resource = resource; - } - - /** - * Whether to overwrite the resource if it already exists. Default is - * false. - */ - public void setOverwrite(Boolean overwrite) { - this.overwrite = overwrite; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ParameterRef.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ParameterRef.java deleted file mode 100644 index 45dd0964f..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ParameterRef.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.core.execution; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.FactoryBean; - -public class ParameterRef implements FactoryBean { - private final static Log log = LogFactory.getLog(ParameterRef.class); - - private InstantiationManager instantiationManager; - private String name; - - /** Cached object. */ - private Object object; - - public ParameterRef() { - } - - public ParameterRef(String name) { - this.name = name; - } - - public Object getObject() throws Exception { - if (log.isTraceEnabled()) - log.debug("Parameter ref called for " + name); - - if (object == null) - object = instantiationManager.getInitializingFlowParameter(name); - return object; - } - - public Class getObjectType() { - if (object == null) - return instantiationManager.getInitializingFlowParameterClass(name); - else - return object.getClass(); - } - - public boolean isSingleton() { - return true; - } - - public void setInstantiationManager( - InstantiationManager instantiationManager) { - this.instantiationManager = instantiationManager; - } - - public void setName(String name) { - this.name = name; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveAccessor.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveAccessor.java deleted file mode 100644 index 18d1b9894..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveAccessor.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.core.execution; - -/** Abstraction of access to primitive values */ -public interface PrimitiveAccessor { - public final static String TYPE_STRING = "string"; - /** - * As of Argeo 1, passwords are NOT stored encrypted, just hidden in the UI, - * but stored in plain text in JCR. Use keyring instead. - */ - public final static String TYPE_PASSWORD = "password"; - public final static String TYPE_INTEGER = "integer"; - public final static String TYPE_LONG = "long"; - public final static String TYPE_FLOAT = "float"; - public final static String TYPE_DOUBLE = "double"; - public final static String TYPE_BOOLEAN = "boolean"; - - public String getType(); - - public Object getValue(); - - public void setValue(Object value); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveSpecAttribute.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveSpecAttribute.java deleted file mode 100644 index fe8412c81..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveSpecAttribute.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.core.execution; - -import org.argeo.slc.SlcException; - -/** - * A spec attribute wrapping a primitive value. - * - * @see PrimitiveAccessor - */ -public class PrimitiveSpecAttribute extends AbstractSpecAttribute implements - PrimitiveAccessor { - private static final long serialVersionUID = -566676381839825483L; - private String type = "string"; - private Object value = null; - - public PrimitiveSpecAttribute() { - } - - public PrimitiveSpecAttribute(String type, Object value) { - this.type = type; - this.value = value; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - - public String getType() { - return type; - } - - public void setType(String type) { - // check whether type is recognized. - if (PrimitiveUtils.typeAsClass(type) == null) - throw new SlcException("Unrecognized type " + type); - this.type = type; - - } - - @Override - public String toString() { - return "Primitive spec attribute [" + type + "]" - + (value != null ? "=" + value : ""); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveUtils.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveUtils.java deleted file mode 100644 index 4268b8b03..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveUtils.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.core.execution; - -/** Converts to and from primitive types. */ -public class PrimitiveUtils { - /** - * @deprecated Use {@link PrimitiveAccessor#TYPE_STRING} instead - */ - public final static String TYPE_STRING = PrimitiveAccessor.TYPE_STRING; - /** - * @deprecated Use {@link PrimitiveAccessor#TYPE_INTEGER} instead - */ - public final static String TYPE_INTEGER = PrimitiveAccessor.TYPE_INTEGER; - /** - * @deprecated Use {@link PrimitiveAccessor#TYPE_LONG} instead - */ - public final static String TYPE_LONG = PrimitiveAccessor.TYPE_LONG; - /** - * @deprecated Use {@link PrimitiveAccessor#TYPE_FLOAT} instead - */ - public final static String TYPE_FLOAT = PrimitiveAccessor.TYPE_FLOAT; - /** - * @deprecated Use {@link PrimitiveAccessor#TYPE_DOUBLE} instead - */ - public final static String TYPE_DOUBLE = PrimitiveAccessor.TYPE_DOUBLE; - /** - * @deprecated Use {@link PrimitiveAccessor#TYPE_BOOLEAN} instead - */ - public final static String TYPE_BOOLEAN = PrimitiveAccessor.TYPE_BOOLEAN; - - private PrimitiveUtils() { - - } - - /** @return the class or null if the provided type is not a primitive */ - public static Class typeAsClass(String type) { - if (PrimitiveAccessor.TYPE_STRING.equals(type)) - return String.class; - else if (PrimitiveAccessor.TYPE_PASSWORD.equals(type)) - return char[].class; - else if (PrimitiveAccessor.TYPE_INTEGER.equals(type)) - return Integer.class; - else if (PrimitiveAccessor.TYPE_LONG.equals(type)) - return Long.class; - else if (PrimitiveAccessor.TYPE_FLOAT.equals(type)) - return Float.class; - else if (PrimitiveAccessor.TYPE_DOUBLE.equals(type)) - return Double.class; - else if (PrimitiveAccessor.TYPE_BOOLEAN.equals(type)) - return Boolean.class; - else - return null; - } - - /** @return the type or null if the provided class is not a primitive */ - public static String classAsType(Class clss) { - if (String.class.isAssignableFrom(clss)) - return PrimitiveAccessor.TYPE_STRING; - else if (char[].class.isAssignableFrom(clss)) - return PrimitiveAccessor.TYPE_PASSWORD; - else if (Integer.class.isAssignableFrom(clss)) - return PrimitiveAccessor.TYPE_INTEGER; - else if (Long.class.isAssignableFrom(clss)) - return PrimitiveAccessor.TYPE_LONG; - else if (Float.class.isAssignableFrom(clss)) - return PrimitiveAccessor.TYPE_FLOAT; - else if (Double.class.isAssignableFrom(clss)) - return PrimitiveAccessor.TYPE_DOUBLE; - else if (Boolean.class.isAssignableFrom(clss)) - return PrimitiveAccessor.TYPE_BOOLEAN; - else - return null; - } - - /** Parse string as an object. Passwords are returned as String.*/ - public static Object convert(String type, String str) { - if (PrimitiveAccessor.TYPE_STRING.equals(type)) { - return str; - } else if (PrimitiveAccessor.TYPE_PASSWORD.equals(type)) { - return str; - } else if (PrimitiveAccessor.TYPE_INTEGER.equals(type)) { - return (Integer.parseInt(str)); - } else if (PrimitiveAccessor.TYPE_LONG.equals(type)) { - return (Long.parseLong(str)); - } else if (PrimitiveAccessor.TYPE_FLOAT.equals(type)) { - return (Float.parseFloat(str)); - } else if (PrimitiveAccessor.TYPE_DOUBLE.equals(type)) { - return (Double.parseDouble(str)); - } else if (PrimitiveAccessor.TYPE_BOOLEAN.equals(type)) { - return (Boolean.parseBoolean(str)); - } else { - return str; - } - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveValue.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveValue.java deleted file mode 100644 index 3dedb9c22..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/PrimitiveValue.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.core.execution; - -/** Primitive value to be used by an execution. */ -public class PrimitiveValue extends AbstractExecutionValue implements - PrimitiveAccessor { - private static final long serialVersionUID = 533414290998374166L; - - private String type; - - private Object value; - - public PrimitiveValue() { - } - - public PrimitiveValue(String type, Object value) { - super(); - this.type = type; - this.value = value; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ProcessThread.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ProcessThread.java deleted file mode 100644 index 926789677..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ProcessThread.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * 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.core.execution; - -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import javax.security.auth.Subject; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.execution.ExecutionModulesManager; -import org.argeo.slc.execution.ExecutionProcess; -import org.argeo.slc.execution.ExecutionStep; -import org.argeo.slc.execution.RealizedFlow; - -/** - * Main thread coordinating an {@link ExecutionProcess}, launching parallel or - * sequential {@link ExecutionThread}s. - */ -public class ProcessThread extends Thread { - private final static Log log = LogFactory.getLog(ProcessThread.class); - - private final ExecutionModulesManager executionModulesManager; - private final ExecutionProcess process; - private final ProcessThreadGroup processThreadGroup; - - private Set executionThreads = Collections.synchronizedSet(new HashSet()); - - // private Boolean hadAnError = false; - private Boolean killed = false; - - private final AccessControlContext accessControlContext; - - public ProcessThread(ThreadGroup processesThreadGroup, ExecutionModulesManager executionModulesManager, - ExecutionProcess process) { - super(processesThreadGroup, "SLC Process #" + process.getUuid()); - this.executionModulesManager = executionModulesManager; - this.process = process; - processThreadGroup = new ProcessThreadGroup(process); - accessControlContext = AccessController.getContext(); - } - - public final void run() { - // authenticate thread - // Authentication authentication = getProcessThreadGroup() - // .getAuthentication(); - // if (authentication == null) - // throw new SlcException("Can only execute authenticated threads"); - // SecurityContextHolder.getContext().setAuthentication(authentication); - - log.info("\n##\n## SLC Process #" + process.getUuid() + " STARTED\n##\n"); - - // Start logging - new LoggingThread().start(); - - process.setStatus(ExecutionProcess.RUNNING); - try { - Subject subject = Subject.getSubject(accessControlContext); - try { - Subject.doAs(subject, new PrivilegedExceptionAction() { - - @Override - public Void run() throws Exception { - process(); - return null; - } - - }); - } catch (PrivilegedActionException privilegedActionException) { - Throwable cause = privilegedActionException.getCause(); - if (cause instanceof InterruptedException) - throw (InterruptedException) cause; - else - throw new SlcException("Cannot process", cause); - } - // process(); - } catch (InterruptedException e) { - die(); - return; - } catch (Exception e) { - String msg = "Process " + getProcess().getUuid() + " failed unexpectedly."; - log.error(msg, e); - getProcessThreadGroup() - .dispatchAddStep(new ExecutionStep("Process", ExecutionStep.ERROR, msg + " " + e.getMessage())); - } - - // waits for all execution threads to complete (in case they were - // started asynchronously) - for (ExecutionThread executionThread : executionThreads) { - if (executionThread.isAlive()) { - try { - executionThread.join(); - } catch (InterruptedException e) { - die(); - return; - } - } - } - - computeFinalStatus(); - } - - /** Make sure this is called BEFORE all the threads are interrupted. */ - private void computeFinalStatus() { - // String oldStatus = process.getStatus(); - // TODO: error management at flow level? - if (killed) - process.setStatus(ExecutionProcess.KILLED); - else if (processThreadGroup.hadAnError()) - process.setStatus(ExecutionProcess.ERROR); - else - process.setStatus(ExecutionProcess.COMPLETED); - // executionModulesManager.dispatchUpdateStatus(process, oldStatus, - // process.getStatus()); - log.info("\n## SLC Process #" + process.getUuid() + " " + process.getStatus() + "\n"); - } - - /** Called when being killed */ - private synchronized void die() { - killed = true; - computeFinalStatus(); - for (ExecutionThread executionThread : executionThreads) { - try { - executionThread.interrupt(); - } catch (Exception e) { - log.error("Cannot interrupt " + executionThread); - } - } - processThreadGroup.interrupt(); - } - - /** - * Implementation specific execution. To be overridden in order to deal with - * custom process types. Default expects an {@link SlcExecution}. - */ - protected void process() throws InterruptedException { - List flowsToProcess = new ArrayList(); - flowsToProcess.addAll(process.getRealizedFlows()); - while (flowsToProcess.size() > 0) { - RealizedFlow realizedFlow = flowsToProcess.remove(0); - execute(realizedFlow, true); - } - } - - /** @return the (distinct) thread used for this execution */ - protected final void execute(RealizedFlow realizedFlow, Boolean synchronous) throws InterruptedException { - if (killed) - return; - - ExecutionThread thread = new ExecutionThread(processThreadGroup, executionModulesManager, realizedFlow); - executionThreads.add(thread); - thread.start(); - - if (synchronous) - thread.join(); - - return; - } - - // public void notifyError() { - // hadAnError = true; - // } - // - // public synchronized void flowCompleted() { - // // notifyAll(); - // } - - public ExecutionProcess getProcess() { - return process; - } - - public ProcessThreadGroup getProcessThreadGroup() { - return processThreadGroup; - } - - public ExecutionModulesManager getExecutionModulesManager() { - return executionModulesManager; - } - - private class LoggingThread extends Thread { - - public LoggingThread() { - super("SLC Process Logger #" + process.getUuid()); - } - - public void run() { - boolean run = true; - while (run) { - List newSteps = new ArrayList(); - processThreadGroup.getSteps().drainTo(newSteps); - if (newSteps.size() > 0) { - // System.out.println(steps.size() + " steps"); - process.addSteps(newSteps); - } - - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; - } - - if (!ProcessThread.this.isAlive() && processThreadGroup.getSteps().size() == 0) - run = false; - } - } - - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ProcessThreadGroup.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/ProcessThreadGroup.java deleted file mode 100644 index 17dbff83b..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/ProcessThreadGroup.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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.core.execution; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; - -import org.argeo.slc.execution.ExecutionProcess; -import org.argeo.slc.execution.ExecutionStep; - -/** The thread group attached to a given {@link SlcExecution}. */ -public class ProcessThreadGroup extends ThreadGroup { -// private final Authentication authentication; - private final static Integer STEPS_BUFFER_CAPACITY = 5000; - - private BlockingQueue steps = new ArrayBlockingQueue( - STEPS_BUFFER_CAPACITY); - - private Boolean hadAnError = false; - - public ProcessThreadGroup(ExecutionProcess executionProcess) { - super("SLC Process #" + executionProcess.getUuid() + " thread group"); -// this.authentication = SecurityContextHolder.getContext() -// .getAuthentication(); - } - -// public Authentication getAuthentication() { -// return authentication; -// } - - public void dispatchAddStep(ExecutionStep step) { - // ExecutionProcess slcProcess = processThread.getProcess(); - // List steps = new ArrayList(); - // steps.add(step); - // TODO clarify why we don't dispatch steps, must be a reason - // dispatchAddSteps(steps); - // slcProcess.addSteps(steps); - if (step.getType().equals(ExecutionStep.ERROR)) - hadAnError = true; - this.steps.add(step); - } - - // public void dispatchAddSteps(List steps) { - // ExecutionProcess slcProcess = processThread.getProcess(); - // executionModulesManager.dispatchAddSteps(slcProcess, steps); - // } - - public BlockingQueue getSteps() { - return steps; - } - - public Boolean hadAnError() { - return hadAnError; - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefSpecAttribute.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefSpecAttribute.java deleted file mode 100644 index 8e4f617c8..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefSpecAttribute.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.core.execution; - -import java.util.List; - -/** A spec attribute whose value is a reference to a full fledged object. */ -public class RefSpecAttribute extends AbstractSpecAttribute implements - Cloneable { - private static final long serialVersionUID = -3427797452955753574L; - private transient Class targetClass = String.class; - /** Read only. */ - private String targetClassName; - private transient Object value = null; - - /** List to be chosen from */ - private List choices = null; - - public Object getValue() { - return value; - } - - public void setValue(Object value) { - this.value = value; - } - - /** Default is {@link String} */ - public Class getTargetClass() { - return targetClass; - } - - public void setTargetClass(Class targetClass) { - this.targetClass = targetClass; - this.targetClassName = targetClass.getName(); - } - - public String getTargetClassName() { - return targetClassName; - } - - /** @return can be null */ - public List getChoices() { - return choices; - } - - public void setChoices(List choices) { - this.choices = choices; - } - - @Override - protected Object clone() throws CloneNotSupportedException { - RefSpecAttribute rsa = new RefSpecAttribute(); - rsa.setTargetClass(targetClass); - rsa.setChoices(choices); - return rsa; - } - - @Override - public String toString() { - return "Ref spec attribute [" + targetClass + "]" - + (value != null ? "=" + value : ""); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefValue.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefValue.java deleted file mode 100644 index 0a24bc4b4..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefValue.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.core.execution; - -/** Reference value to be used by an execution */ -public class RefValue extends AbstractExecutionValue { - private static final long serialVersionUID = -8951231456757181687L; - private String ref; - private String type; - - public RefValue() { - } - - public RefValue(String ref) { - super(); - this.ref = ref; - } - - public String getRef() { - return ref; - } - - public void setRef(String ref) { - this.ref = ref; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - @Override - public String toString() { - return "Ref Value [" + type + "=" + ref + "]"; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefValueChoice.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefValueChoice.java deleted file mode 100644 index 5e1f9c2ab..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/RefValueChoice.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.core.execution; - -import java.io.Serializable; - -/** A choice of ref value to be shown to the end user. */ -public class RefValueChoice implements Serializable { - private static final long serialVersionUID = -1133645722307507774L; - private String name; - private String description; - - public RefValueChoice() { - } - - public RefValueChoice(String name, String description) { - this.name = name; - this.description = description; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/SedFilteredResource.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/SedFilteredResource.java deleted file mode 100644 index c793f4963..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/SedFilteredResource.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.core.execution; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.channels.FileChannel; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.io.IOUtils; -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.FactoryBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; - -/** Experimental and suboptimal */ -public class SedFilteredResource implements FactoryBean, - InitializingBean { - private Resource source; - - private List filters = new ArrayList(); - private Map patterns = new HashMap(); - - private String charset = "UTF-8"; - private Charset cs; - private CharsetDecoder decoder; - - // private CharsetEncoder encoder; - - public Resource getObject() throws Exception { - if (filters.size() == 0) - return source; - - // int capacity = 100 * 1024;// 100 KB - ByteBuffer bb; - if (source instanceof ByteArrayResource) { - bb = ByteBuffer.wrap(((ByteArrayResource) source).getByteArray()); - } else { - FileInputStream fis = null; - try { - File file = source.getFile(); - fis = new FileInputStream(file); - FileChannel fc = fis.getChannel(); - - // Get the file's size and then map it into memory - int sz = (int) fc.size(); - bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz); - } catch (IOException e) { - // ReadableByteChannel channel = Channels.newChannel(source - // .getInputStream()); - // bb = ByteBuffer.allocateDirect(capacity); - // int read = 0; - // do { - // read = channel.read(bb); - // } while (read > 0); - // FIXME : use nio to parse the stream as it goes - bb = ByteBuffer.wrap(IOUtils.toByteArray(source - .getInputStream())); - } finally { - IOUtils.closeQuietly(fis); - } - } - CharBuffer cb = decoder.decode(bb); - for (Pattern pattern : patterns.keySet()) { - Matcher matcher = pattern.matcher(cb); - String output = matcher.replaceAll(patterns.get(pattern)); - cb = CharBuffer.wrap(output); - } - // ByteBuffer bbout = encoder.encode(cb); - // ByteArrayOutputStream out = new ByteArrayOutputStream(capacity); - // WritableByteChannel wchannel = Channels.newChannel(out); - // wchannel.write(bbout); - ByteArrayResource res = new ByteArrayResource(cb.toString().getBytes()); - return res; - } - - public Class getObjectType() { - return Resource.class; - } - - public boolean isSingleton() { - return true; - } - - public void afterPropertiesSet() throws Exception { - cs = Charset.forName(charset); - decoder = cs.newDecoder(); - // encoder = cs.newEncoder(); - - for (String sedStr : filters) { - sedStr = sedStr.trim(); - if (sedStr.length() < 4) - throw new SlcException(sedStr + " not properly formatted."); - if (sedStr.charAt(0) != 's') - throw new SlcException(sedStr + " not properly formatted."); - Character sep = sedStr.charAt(1); - List tokens = new ArrayList(4); - StringTokenizer st = new StringTokenizer(sedStr, sep.toString()); - while (st.hasMoreTokens()) - tokens.add(st.nextToken()); - if (tokens.size() != 3 && tokens.size() != 4) - throw new SlcException(sedStr + " not properly formatted."); - patterns.put(Pattern.compile(tokens.get(1)), tokens.get(2)); - } - } - - public void setSource(Resource source) { - this.source = source; - } - - public void setFilters(List filters) { - this.filters = filters; - } - - public void setCharset(String charset) { - this.charset = charset; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/defaults.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/defaults.xml deleted file mode 100644 index d84ba10eb..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/defaults.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/doc/ConsoleContextDescriber.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/doc/ConsoleContextDescriber.java deleted file mode 100644 index 6504a3de3..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/doc/ConsoleContextDescriber.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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.core.execution.doc; - -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.PropertyValue; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; - -public class ConsoleContextDescriber implements ContextDescriber { - public void describeContext(BeanDefinitionRegistry registry) { - String[] beanNames = registry.getBeanDefinitionNames(); - for (String beanName : beanNames) { - log("\n## BEAN: " + beanName); - describeBean(registry.getBeanDefinition(beanName)); - } - } - - public void describeBean(BeanDefinition beanDefinition) { - log("BeanDefinition class: "+beanDefinition.getClass()); - log("# ATTRIBUTES"); - for(String attr:beanDefinition.attributeNames()){ - log(attr+"="+beanDefinition.getAttribute(attr)); - } - log("# PROPERTIES"); - MutablePropertyValues pValues = beanDefinition.getPropertyValues(); - for (PropertyValue pv : pValues.getPropertyValues()) { - log(pv.getName() + "= (" + pv.getValue().getClass() + ") " - + pv.getValue()); - } - } - - protected void log(Object obj){ - System.out.println(obj); - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/doc/ContextDescriber.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/doc/ContextDescriber.java deleted file mode 100644 index 713019b37..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/doc/ContextDescriber.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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.core.execution.doc; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; - -public interface ContextDescriber { - public void describeContext(BeanDefinitionRegistry registry); - public void describeBean(BeanDefinition bd); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/CompositeRunnableFactory.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/CompositeRunnableFactory.java deleted file mode 100644 index f1e80d390..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/CompositeRunnableFactory.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.Map; - -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; - -/** - * Composite RunnableFactory, redirecting the Runnable - * creation to on of the configured RunnableFactory depending - * on an entry of the data of the RunnableDataNode. - */ -public class CompositeRunnableFactory implements RunnableFactory { - - /** - * Key used to access factory ID in the data of the RunnableDataNode - */ - private String factoryKey; - - /** - * Maps a factory ID to an ExecutionFlowFactory - */ - private Map factories; - - public void createAndRegisterRunnable(RunnableDataNode node, - BeanDefinitionRegistry beanDefinitionRegistry) { - findFactory(node).createAndRegisterRunnable(node, beanDefinitionRegistry); - } - - /** - * Finds the RunnableFactory to use for a RunnableDataNode - * @param node - * @return the RunnableFactory to use for the RunnableDataNode - */ - private RunnableFactory findFactory(RunnableDataNode node) { - // get the factory ID from the data of the RunnableDescriptor - Map data = node.getData(); - if (!data.containsKey(factoryKey)) { - throw new SlcException("No data value for key '" + factoryKey + "'"); - } - String factoryId = data.get(factoryKey).toString(); - - // see if we have a factory for the factory ID - if ((factories != null) && factories.containsKey(factoryId)) { - return factories.get(factoryId); - } - // if not, look for a bean of name equals to the factory ID - else { - throw new SlcException("Not implemented"); - } - } - - public void setFactoryKey(String factoryKey) { - this.factoryKey = factoryKey; - } - - public void setFactories(Map factories) { - this.factories = factories; - } - - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/DefaultRunnableDataNode.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/DefaultRunnableDataNode.java deleted file mode 100644 index daed350b2..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/DefaultRunnableDataNode.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Default implementation of RunnableDataNode - * - */ -public class DefaultRunnableDataNode implements RunnableDataNode { - - private List children = new ArrayList(); - - private RunnableDataNode parent; - - /** - * Data of the RunnableDataNode. Does not contain - * parent data. - */ - private Map properData = new HashMap(); - - private String path; - - private String beanName; - - public boolean isLeaf() { - return children.size() == 0; - } - - public List getChildren() { - return children; - } - - public void addChild(RunnableDataNode child) { - child.setParent(this); - children.add(child); - } - - public Map getData() { - Map data = new HashMap(); - if(parent != null) { - Map parentData = parent.getData(); - if(parentData != null) { - data.putAll(parentData); - } - } - // entries defined in parentData can be overridden - // in properData - if(properData != null) { - data.putAll(properData); - } - return data; - } - - public Map getProperData() { - return properData; - } - - public void setProperData(Map properData) { - this.properData = properData; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public String getBeanName() { - return beanName; - } - - public void setBeanName(String beanName) { - this.beanName = beanName; - } - - public void setParent(RunnableDataNode parent) { - this.parent = parent; - } - - public RunnableDataNode getParent() { - return parent; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/ExecutionFlowGenerator.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/ExecutionFlowGenerator.java deleted file mode 100644 index d9400e42e..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/ExecutionFlowGenerator.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.HashMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.springframework.aop.scope.ScopedProxyUtils; -import org.springframework.beans.BeansException; -import org.springframework.beans.MutablePropertyValues; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.GenericBeanDefinition; -import org.springframework.core.Ordered; - -/** - * Generates ExecutionFlows and Runnables as - * beans in the Spring Application Context. - * Called by the Application Context as a BeanFactoryPostProcessor. - * Two kinds of beans are generated: - * RunnableCallFlow, calling a list of Runnables from the - * Application Context after configuring the ExecutionContext, - * and outputs of a RunnableFactory. - */ -public class ExecutionFlowGenerator implements BeanFactoryPostProcessor, - Ordered { - - private final Log log = LogFactory.getLog(getClass()); - - /** - * Source providing a list of RunnableCallFlowDescriptor - * used to create RunnableCallFlow and a list of - * RunnableDataNode used to create any kind of flow via a factory - */ - protected ExecutionFlowGeneratorSource source; - - /** - * Factory used to create Runnables in the Application context from - * the RunnableDataNode provided from the source. - */ - protected RunnableFactory runnableFactory; - - /** - * Bean name of the ExecutionContext. - * Used to provide the created RunnableCallFlow beans - * with a RuntimeBeanReference to - * the ExecutionContext - */ - private String executionContextBeanName = "executionContext"; - - /** - * Bean name of the context values Map. - * A bean of class HashMap is created with this name, and a - * RuntimeBeanReference is provided to the created - * RunnableCallFlow beans. - */ - private String contextValuesBeanName = "executionFlowGenerator.contextValues"; - - /** - * Prefix added to the bean names defined in each - * RunnableCallFlowDescriptor - */ - private String flowBeanNamesPrefix = ""; - - private int order = Ordered.HIGHEST_PRECEDENCE; - - public void postProcessBeanFactory( - ConfigurableListableBeanFactory beanFactory) throws BeansException { - - // assert that the beanFactory is a BeanDefinitionRegistry - if (!(beanFactory instanceof BeanDefinitionRegistry)) { - throw new SlcException("Can only work on " - + BeanDefinitionRegistry.class); - } - - // add bean for the Context Values Map - createAndRegisterContextValuesBean((BeanDefinitionRegistry) beanFactory); - - // add beans for each RunnableDataNode - for(RunnableDataNode node : source.getRunnableDataNodes()) { - runnableFactory.createAndRegisterRunnable(node, (BeanDefinitionRegistry) beanFactory); - } - - // add beans for each RunnableCallFlowDescriptor of the source to the application context - for (RunnableCallFlowDescriptor descriptor : source - .getRunnableCallFlowDescriptors()) { - createAndRegisterFlowFor(descriptor, (BeanDefinitionRegistry) beanFactory); - } - } - - /** - * Creates a RunnableCallFlow bean - * for a RunnableCallFlowDescriptor and registers - * it in the BeanDefinitionRegistry - * @param flowDescriptor - * @param registry - */ - private void createAndRegisterFlowFor(RunnableCallFlowDescriptor flowDescriptor, BeanDefinitionRegistry registry) { - // create the flow bean - GenericBeanDefinition flowBean = new GenericBeanDefinition(); - flowBean.setBeanClass(RunnableCallFlow.class); - - String beanName = flowBeanNamesPrefix + flowDescriptor.getBeanName(); - - MutablePropertyValues mpv = new MutablePropertyValues(); - mpv.addPropertyValue("runnableCalls", flowDescriptor.getRunnableCalls()); - mpv.addPropertyValue("sharedContextValuesMap", new RuntimeBeanReference(contextValuesBeanName)); - - mpv.addPropertyValue("name", beanName); - mpv.addPropertyValue("path", flowDescriptor.getPath()); - - mpv.addPropertyValue("executionContext", new RuntimeBeanReference(executionContextBeanName)); - - flowBean.setPropertyValues(mpv); - - // register it - if(log.isDebugEnabled()) { - log.debug("Registering bean definition for RunnableCallFlow " + beanName); - } - registry.registerBeanDefinition(beanName, flowBean); - } - - /** - * Creates the Context Values bean and register it in the - * BeanDefinitionRegistry - * @param registry - */ - private void createAndRegisterContextValuesBean(BeanDefinitionRegistry registry) { - GenericBeanDefinition contextValuesBean = new GenericBeanDefinition(); - contextValuesBean.setBeanClass(HashMap.class); - - BeanDefinitionHolder bdh = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(contextValuesBean, contextValuesBeanName), registry, true); - registry.registerBeanDefinition(contextValuesBeanName, bdh.getBeanDefinition()); - } - - public int getOrder() { - return order; - } - - public void setOrder(int order) { - this.order = order; - } - - public void setSource(ExecutionFlowGeneratorSource source) { - this.source = source; - } - - public void setRunnableFactory(RunnableFactory runnableFactory) { - this.runnableFactory = runnableFactory; - } - - public void setExecutionContextBeanName(String executionContextBeanName) { - this.executionContextBeanName = executionContextBeanName; - } - - public void setContextValuesBeanName(String contextValuesBeanName) { - this.contextValuesBeanName = contextValuesBeanName; - } - - public void setFlowBeanNamesPrefix(String flowBeanNamesPrefix) { - this.flowBeanNamesPrefix = flowBeanNamesPrefix; - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/ExecutionFlowGeneratorSource.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/ExecutionFlowGeneratorSource.java deleted file mode 100644 index 8d699c660..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/ExecutionFlowGeneratorSource.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.List; - -/** - * Provides 2 types of information required by an ExecutionFlowGenerator: - * a list of RunnableCallFlowDescriptor used to create RunnableCallFlow - * and a list of RunnableDataNode used to create any kind of flow via a factory. - */ -public interface ExecutionFlowGeneratorSource { - - /** - * @return a list of RunnableCallFlowDescriptor used - * by a ExecutionFlowGenerator to create RunnableCallFlow - */ - public List getRunnableCallFlowDescriptors(); - - /** - * @return a list of RunnableDataNode used - * by a ExecutionFlowGenerator to create any kind of flow via a factory - */ - public List getRunnableDataNodes(); - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCall.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCall.java deleted file mode 100644 index c3fd5f2d8..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCall.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.Map; - -/** - * Storage class for information required to call a flow - * of the Spring execution context: - * bean name of the flow, - * variables to add to the Execution Context before the call - * and variables (context values) to add to a Map - * potentially referenced by the called flow - */ -public class RunnableCall { - - /** - * Bean name of the flow to call - */ - private String beanName; - - /** - * Variables to add to the execution context before the call - */ - private Map executionVariables; - - /** - * Variables to add to the Map potentially referenced by - * the called flow - */ - private Map contextValues; - - public String getBeanName() { - return beanName; - } - - public void setBeanName(String beanName) { - this.beanName = beanName; - } - - public Map getExecutionVariables() { - return executionVariables; - } - - public void setExecutionVariables(Map executionVariables) { - this.executionVariables = executionVariables; - } - - public Map getContextValues() { - return contextValues; - } - - public void setContextValues(Map contextValues) { - this.contextValues = contextValues; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCallFlow.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCallFlow.java deleted file mode 100644 index 695606c21..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCallFlow.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.core.execution.DefaultExecutionSpec; -import org.argeo.slc.execution.ExecutionContext; -import org.argeo.slc.execution.ExecutionFlow; -import org.argeo.slc.execution.ExecutionSpec; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; - -/** - * Execution Flow calling a list of Runnable (identified by their - * bean name in the Spring Application Context) after configuring the Execution - * context and a Map potentially shared by the called Runnable - * - */ -public class RunnableCallFlow implements ExecutionFlow, ApplicationContextAware { - - private final static Log log = LogFactory.getLog(RunnableCallFlow.class); - - /** - * Key in the execution context for the index of the call (e.g. 0 for the - * first runnable called, ...) - */ - public final static String VAR_CALL_INDEX = "slcVar.runnableCallFlow.callIndex"; - - /** - * Name of the flow. Also bean name - */ - private String name; - - /** - * Path of the flow - */ - private String path; - - /** - * Whether an exception in a Runnable shall stop the execution - * of the flow - */ - private Boolean failOnError = true; - - /** - * List of Runnable to call, with bean name, execution - * variables and context values - */ - private List runnableCalls; - - /** - * Map potentially referenced by called flows. Updated with the context - * values of a Runnable before calling it. - */ - private Map sharedContextValuesMap; - - /** - * ExecutionSpec of the flow. Does not contain any attribute. - */ - private ExecutionSpec executionSpec = new DefaultExecutionSpec(); - - /** - * Reference to the ExecutionContext - */ - private ExecutionContext executionContext; - - /** - * Reference to the Spring ApplicationContext. Set via - * setApplicationContext, the class implementing - * ApplicationContextAware - */ - private ApplicationContext applicationContext; - - /** - * Runs a Runnable after configuring the Execution Context and - * sharedContextValuesMap - * - * @param runnable - * the Runnable to call - * @param executionVariables - * the variables to add to the ExecutionContext - * @param contextValues - * the variables to add to sharedContextValuesMap - * @param callIndex - * index of the call (0 for the first called - * Runnable) set as variable of the - * ExecutionContext - */ - private void run(Runnable runnable, Map executionVariables, - Map contextValues, int callIndex) { - // add all variables to the Execution Context - for (Map.Entry entry : executionVariables.entrySet()) { - executionContext.setVariable(entry.getKey(), entry.getValue()); - } - - // add call Index Variable - executionContext.setVariable(VAR_CALL_INDEX, callIndex); - - // clear sharedContextValues and add all values of contextValues - if (sharedContextValuesMap != null) { - sharedContextValuesMap.clear(); - sharedContextValuesMap.putAll(contextValues); - } - - // then run the runnable - doExecuteRunnable(runnable); - } - - public void doExecuteRunnable(Runnable runnable) { - runnable.run(); - } - - /** - * Executes the flow. For each RunnableCall, the corresponding - * flow is retrieved from the Spring Application Context, the - * ExecutionContext and sharedContextValuesMap are - * configured and the Runnable is called. - */ - public void run() { - if (applicationContext == null) { - throw new SlcException("No ApplicationContext defined"); - } - - try { - for (int callIndex = 0; callIndex < runnableCalls.size(); ++callIndex) { - RunnableCall runnableCall = runnableCalls.get(callIndex); - Object bean = applicationContext.getBean( - runnableCall.getBeanName(), Runnable.class); - if (log.isDebugEnabled()) - log.debug("Running flow '" + runnableCall.getBeanName() - + "'"); - run((Runnable) bean, runnableCall.getExecutionVariables(), - runnableCall.getContextValues(), callIndex); - } - } catch (RuntimeException e) { - if (failOnError) - throw e; - else { - log.error("Execution flow failed," - + " but process did not fail" - + " because failOnError property" - + " is set to false: " + e); - if (log.isTraceEnabled()) - e.printStackTrace(); - } - } - } - - public Iterator runnables() { - List runnables = new ArrayList(); - for (int callIndex = 0; callIndex < runnableCalls.size(); ++callIndex) { - RunnableCall runnableCall = runnableCalls.get(callIndex); - Object bean = applicationContext.getBean( - runnableCall.getBeanName(), Runnable.class); - runnables.add((Runnable) bean); - } - return runnables.iterator(); - } - - public Runnable getRunnable() { - if (runnableCalls.size() == 1) - return runnables().next(); - else - throw new SlcException("There are " + runnableCalls.size() - + " runnables in flow " + getName()); - } - - @Override - public String toString() { - return new StringBuffer("RunnableCallFlow ").append(name).toString(); - } - - public ExecutionSpec getExecutionSpec() { - return executionSpec; - } - - public String getName() { - return name; - } - - public Object getParameter(String key) { - throw new SlcException("RunnableCallFlow have no parameters"); - } - - public String getPath() { - return path; - } - - public Boolean isSetAsParameter(String key) { - // The ExecutionSpec having no attribute, - // always return false - return false; - } - - public void setName(String name) { - this.name = name; - } - - public void setPath(String path) { - this.path = path; - } - - public void setExecutionContext(ExecutionContext executionContext) { - this.executionContext = executionContext; - } - - public void setRunnableCalls(List runnableCalls) { - this.runnableCalls = runnableCalls; - } - - public void setApplicationContext(ApplicationContext applicationContext) { - this.applicationContext = applicationContext; - } - - public void setSharedContextValuesMap(Map contextValues) { - this.sharedContextValuesMap = contextValues; - } - - public void setFailOnError(Boolean failOnError) { - this.failOnError = failOnError; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCallFlowDescriptor.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCallFlowDescriptor.java deleted file mode 100644 index e0bbbdda9..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableCallFlowDescriptor.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.ArrayList; -import java.util.List; - -/** - * Storage Class for information required to - * instantiate a RunnableCallFlow: - * bean name of the flow, - * path of the flow - * and list of RunnableCall. - * - */ -public class RunnableCallFlowDescriptor { - - /** - * Bean name of the flow to instantiate - */ - private String beanName; - - /** - * Path of the flow to instantiate - */ - private String path; - - /** - * List of RunnableCall - */ - private List runnableCalls = new ArrayList(); - - public String getBeanName() { - return beanName; - } - - public void setBeanName(String beanName) { - this.beanName = beanName; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public List getRunnableCalls() { - return runnableCalls; - } - - public void setRunnableCalls(List runnableCalls) { - this.runnableCalls = runnableCalls; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableDataNode.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableDataNode.java deleted file mode 100644 index 51843dcd0..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableDataNode.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.core.execution.generator; - -import java.util.List; -import java.util.Map; - -/** - * Stores information relative to a Runnable. - * Allows to structure the information as a tree, each node - * storing data as a Map. - */ -public interface RunnableDataNode { - - /** - * @return a Map containing the data associated with this node. - * Data associated with parent nodes are expected - * to be contained in the returned Map - */ - public Map getData(); - - /** - * @return the name of the bean to create. - * Can be null if no bean shall be created for the - * RunnableDataNode (e.g. is is a sub-node) - */ - public String getBeanName(); - - /** - * @return the path of the flow bean to create. - * Can be null if the bean to created is not an - * ExecutionFlow or if no bean shall be created for the - * RunnableDataNode (e.g. is is a sub-node) - */ - public String getPath(); - - /** - * @return whether the RunnableDataNode has - * children or not. - * Expected to be equivalent to getChildren().empty() - */ - public boolean isLeaf(); - - /** - * @return the list of RunnableDataNode children. - * Can be empty. Shall not be null. - */ - public List getChildren(); - - /** - * @return the RunnableDataNode parent. - * Can be null if no parent is defined (top node). - */ - public RunnableDataNode getParent(); - - /** - * Sets the RunnableDataNode parent - * @param parent - */ - public void setParent(RunnableDataNode parent); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableFactory.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableFactory.java deleted file mode 100644 index 2b3702889..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/generator/RunnableFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.core.execution.generator; - -import org.springframework.beans.factory.support.BeanDefinitionRegistry; - -/** - * Interprets a RunnableDataNode by creating corresponding - * beans and registering them in a BeanDefinitionRegistry - * - */ -public interface RunnableFactory { - - public void createAndRegisterRunnable(RunnableDataNode node, - BeanDefinitionRegistry beanDefinitionRegistry); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/runtime.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/runtime.xml deleted file mode 100644 index 33542ee20..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/runtime.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - Bare minimal runtime configuration. In general you will - want to use simple.xml instead. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/simple.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/simple.xml deleted file mode 100644 index ff243baf6..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/simple.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - Default Capabilities - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/specs.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/specs.xml deleted file mode 100644 index 7cc960475..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/specs.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/spring.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/spring.xml deleted file mode 100644 index de1c06b1e..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/spring.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - Simple runtime enriched with defaults and templates used - to simplify XML files. These templates have been deprecated by the - custom XML namespace and will be removed in SLC 2.x. Use the XML - namespace instead. - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/CloseTestResult.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/CloseTestResult.java deleted file mode 100644 index 43b296106..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/CloseTestResult.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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.core.execution.tasks; - -import org.argeo.slc.test.TestResult; - -public class CloseTestResult implements Runnable { - private TestResult testResult; - - public void run() { - testResult.close(); - } - - public void setTestResult(TestResult testResult) { - this.testResult = testResult; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/Echo.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/Echo.java deleted file mode 100644 index d47149b86..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/Echo.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.core.execution.tasks; - -import java.io.File; -import java.io.IOException; - -import org.apache.commons.io.FileUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.springframework.core.io.Resource; - -public class Echo implements Runnable { - private final static Log defaultLog = LogFactory.getLog(Echo.class); - private Resource writeTo = null; - - private Log log; - private Object message; - - public void run() { - log().info(message); - - if (writeTo != null) { - try { - File file = writeTo.getFile(); - if (log().isDebugEnabled()) - log().debug("Write to " + file); - if (message != null) - FileUtils.writeStringToFile(file, message.toString()); - } catch (IOException e) { - throw new SlcException("Could not write to " + writeTo, e); - } - } - } - - private Log log() { - return log != null ? log : defaultLog; - } - - public void setMessage(Object message) { - this.message = message; - } - - public void setWriteTo(Resource writeTo) { - this.writeTo = writeTo; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/If.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/If.java deleted file mode 100644 index 0d22e437d..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/If.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.core.execution.tasks; - -import org.argeo.slc.SlcException; - -/** Conditional execution */ -public class If implements Runnable { - private Boolean is; - private Boolean not; - private Runnable then; - private Runnable els; - - public void run() { - if (is == null && not == null) - throw new SlcException("No condition set"); - if (is != null && not != null) - throw new SlcException("Both is and not cannot be set"); - - boolean bool = (is != null ? is : !not); - if (bool) { - if (then != null) - then.run(); - } else { - if (els != null) - els.run(); - } - - } - - public void setIs(Boolean bool) { - this.is = bool; - } - - public void setThen(Runnable then) { - this.then = then; - } - - public void setEls(Runnable els) { - this.els = els; - } - - public Boolean getNot() { - return not; - } - - public void setNot(Boolean not) { - this.not = not; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/JvmProcess.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/JvmProcess.java deleted file mode 100644 index 01f11012f..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/JvmProcess.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * 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.core.execution.tasks; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.apache.commons.io.IOUtils; -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.core.io.Resource; - -/** A Java Virtual Machine process. */ -public class JvmProcess extends SystemCall implements InitializingBean { - private Properties systemProperties = new Properties(); - private List classpath = new ArrayList(); - private List pBootClasspath = new ArrayList(); - private Resource jvm = null; - private String mainClass; - private String mainJar; - private List jvmArgs = new ArrayList(); - private List args = new ArrayList(); - - private String systemPropertiesFileProperty = null; - private String systemPropertiesFileDir = null; - private String systemPropertiesFileName = null; - - public void afterPropertiesSet() throws Exception { - List command = new ArrayList(); - if (jvm != null) - command.add(asFile(jvm).getPath()); - else - command.add("java"); - - if (pBootClasspath.size() > 0) { - StringBuffer buf = new StringBuffer("-Xbootclasspath/p:"); - Boolean first = true; - for (Resource res : pBootClasspath) { - if (first) - first = false; - else - buf.append(File.pathSeparatorChar); - - buf.append(asFile(res)); - } - command.add(buf.toString()); - } - - for (String jvmArg : jvmArgs) { - command.add(jvmArg); - } - - if (classpath.size() > 0) { - command.add("-cp"); - StringBuffer buf = new StringBuffer(""); - for (Resource res : classpath) { - if (buf.length() != 0) - buf.append(File.pathSeparatorChar); - buf.append(asFile(res)); - } - command.add(buf.toString()); - } - - if (systemPropertiesFileProperty == null) { - // pass system properties as argument - for (Map.Entry entry : systemProperties.entrySet()) { - command.add("-D" + entry.getKey() + "=" + entry.getValue()); - } - } else { - // write system properties in a file to work around OS limitations - // with command line (e.g. Win XP) - String dir = systemPropertiesFileDir; - if (dir == null) - dir = getExecDirToUse(); - String fileName = systemPropertiesFileName; - if (fileName == null) - fileName = systemPropertiesFileProperty + ".properties"; - - // Write file - FileOutputStream fos = null; - File file = new File(dir + File.separator + fileName); - try { - - if (!file.getParentFile().exists()) - file.getParentFile().mkdirs(); - fos = new FileOutputStream(file); - systemProperties.store(fos, "Automatically generated by " - + getClass()); - command.add("-D" + systemPropertiesFileProperty + "=" - + file.getCanonicalPath()); - } catch (IOException e) { - throw new SlcException("Cannot write to system properties to " - + file, e); - } finally { - IOUtils.closeQuietly(fos); - } - } - - // Program - if (mainClass != null) { - command.add(mainClass); - } else if (mainJar != null) { - command.add("-jar"); - command.add(mainJar); - } else { - throw new SlcException("No main class or jar defined"); - } - - for (String arg : args) { - command.add(arg); - } - - setCommand(command); - } - - protected File asFile(Resource res) { - try { - return res.getFile(); - } catch (FileNotFoundException e) { - return copyToTempFile(res); - } catch (IOException e) { - throw new SlcException("Cannot convert resource to file", e); - } - - } - - protected File copyToTempFile(Resource res) { - File tempFile; - FileOutputStream fos; - try { - tempFile = File.createTempFile("slcJvmProcess-", res.getFilename()); - tempFile.deleteOnExit(); - fos = new FileOutputStream(tempFile); - IOUtils.copy(res.getInputStream(), fos); - } catch (IOException e) { - throw new SlcException("Cannot copy " + res + " to temp file.", e); - } - IOUtils.closeQuietly(fos); - return tempFile; - } - - /** Append the argument (for chaining) */ - @Override - public SystemCall arg(String arg) { - args.add(arg); - return this; - } - - /** Append the argument (for chaining) */ - @Override - public SystemCall arg(String arg, String value) { - args.add(arg); - args.add(value); - return this; - } - - public Properties getSystemProperties() { - return systemProperties; - } - - public void setSystemProperties(Properties systemProperties) { - this.systemProperties = systemProperties; - } - - public List getClasspath() { - return classpath; - } - - public void setClasspath(List classpath) { - this.classpath = classpath; - } - - public List getPBootClasspath() { - return pBootClasspath; - } - - public void setPBootClasspath(List bootClasspath) { - pBootClasspath = bootClasspath; - } - - public Resource getJvm() { - return jvm; - } - - public void setJvm(Resource jvm) { - this.jvm = jvm; - } - - public String getMainClass() { - return mainClass; - } - - public void setMainClass(String mainClass) { - this.mainClass = mainClass; - } - - public String getMainJar() { - return mainJar; - } - - public void setMainJar(String mainJar) { - this.mainJar = mainJar; - } - - public List getJvmArgs() { - return jvmArgs; - } - - public void setJvmArgs(List jvmArgs) { - this.jvmArgs = jvmArgs; - } - - public List getArgs() { - return args; - } - - public void setArgs(List args) { - this.args = args; - } - - public void setSystemPropertiesFileProperty( - String systemPropertiesFilePropertyName) { - this.systemPropertiesFileProperty = systemPropertiesFilePropertyName; - } - - public void setSystemPropertiesFileDir(String systemPropertiesFileDir) { - this.systemPropertiesFileDir = systemPropertiesFileDir; - } - - public void setSystemPropertiesFileName(String systemPropertiesFileName) { - this.systemPropertiesFileName = systemPropertiesFileName; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/MergedLists.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/MergedLists.java deleted file mode 100644 index e1740e659..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/MergedLists.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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.core.execution.tasks; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.beans.factory.FactoryBean; - -/** Merge the provided lists in one single list, in the order provided. */ -public class MergedLists implements FactoryBean> { - private List> lists = new ArrayList>(); - - public void setLists(List> lists) { - this.lists = lists; - } - - public List getObject() throws Exception { - List merged = new ArrayList(); - for (List lst : lists) { - merged.addAll(lst); - } - return merged; - } - - public Class getObjectType() { - return List.class; - } - - public boolean isSingleton() { - return false; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/MethodCall.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/MethodCall.java deleted file mode 100644 index e4fa77222..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/MethodCall.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.core.execution.tasks; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; - -import org.springframework.util.Assert; -import org.springframework.util.ReflectionUtils; - -public class MethodCall implements Runnable { - private Object target; - private String method; - private List args = new ArrayList(); - - public void run() { - Assert.notNull(target, "target"); - Assert.notNull(method, "method"); - Method methodRef = ReflectionUtils - .findMethod(target.getClass(), method); - if (args.size() == 0) - ReflectionUtils.invokeMethod(methodRef, target); - else - ReflectionUtils.invokeMethod(methodRef, methodRef, args.toArray()); - } - - public void setTarget(Object target) { - this.target = target; - } - - public void setMethod(String method) { - this.method = method; - } - - public void setArgs(List args) { - this.args = args; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/OverrideContextAware.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/OverrideContextAware.java deleted file mode 100644 index 9afa8468c..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/OverrideContextAware.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.core.execution.tasks; - -import org.argeo.slc.SlcException; -import org.argeo.slc.core.test.context.SimpleContextAware; -import org.argeo.slc.test.context.ContextAware; - -/** - * Overrides Values and Expected values of a target - * SimpleContextAware with the corresponding - * values and expected values of a source ContextAware - * - */ -public class OverrideContextAware implements Runnable { - - private ContextAware source; - - private SimpleContextAware target; - - /** - * Whether an exception shall be thrown if a value - * or expected value of the source is not defined - * in the target - */ - private Boolean failIfUndefinedInSource = true; - - public void run() { - // override values - if(source.getValues() != null) - for(String key : source.getValues().keySet()) { - if(failIfUndefinedInSource && !target.getValues().containsKey(key)) { - throw new SlcException("No entry in target values for key '" + key + "'"); - } - target.getValues().put(key, source.getValues().get(key)); - } - - // override expected values - if(source.getExpectedValues() != null) - for(String key : source.getExpectedValues().keySet()) { - if(failIfUndefinedInSource && !target.getExpectedValues().containsKey(key)) { - throw new SlcException("No entry in target expected values for key '" + key + "'"); - } - target.getExpectedValues().put(key, source.getExpectedValues().get(key)); - } - } - - public void setSource(ContextAware source) { - this.source = source; - } - - public void setTarget(SimpleContextAware target) { - this.target = target; - } - - public void setFailIfUndefinedInSource(Boolean failIfUndefinedInSource) { - this.failIfUndefinedInSource = failIfUndefinedInSource; - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/SystemCall.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/SystemCall.java deleted file mode 100644 index 27cc59d60..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/SystemCall.java +++ /dev/null @@ -1,782 +0,0 @@ -/* - * 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.core.execution.tasks; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.security.auth.callback.CallbackHandler; - -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.DefaultExecutor; -import org.apache.commons.exec.ExecuteException; -import org.apache.commons.exec.ExecuteResultHandler; -import org.apache.commons.exec.ExecuteStreamHandler; -import org.apache.commons.exec.ExecuteWatchdog; -import org.apache.commons.exec.Executor; -import org.apache.commons.exec.LogOutputStream; -import org.apache.commons.exec.PumpStreamHandler; -import org.apache.commons.exec.ShutdownHookProcessDestroyer; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.UnsupportedException; -import org.argeo.slc.core.execution.ExecutionResources; -import org.argeo.slc.core.test.SimpleResultPart; -import org.argeo.slc.test.TestResult; -import org.argeo.slc.test.TestStatus; -import org.springframework.core.io.Resource; - -/** Execute an OS specific system call. */ -public class SystemCall implements Runnable { - public final static String LOG_STDOUT = "System.out"; - - private final Log log = LogFactory.getLog(getClass()); - - private String execDir; - - private String cmd = null; - private List command = null; - - private Executor executor = new DefaultExecutor(); - private Boolean synchronous = true; - - private String stdErrLogLevel = "ERROR"; - private String stdOutLogLevel = "INFO"; - - private Resource stdOutFile = null; - private Resource stdErrFile = null; - - private Resource stdInFile = null; - /** - * If no {@link #stdInFile} provided, writing to this stream will write to - * the stdin of the process. - */ - private OutputStream stdInSink = null; - - private Boolean redirectStdOut = false; - - private List outputListeners = Collections - .synchronizedList(new ArrayList()); - - private Map> osCommands = new HashMap>(); - private Map osCmds = new HashMap(); - private Map environmentVariables = new HashMap(); - - private Boolean logCommand = false; - private Boolean redirectStreams = true; - private Boolean exceptionOnFailed = true; - private Boolean mergeEnvironmentVariables = true; - -// private Authentication authentication; - - private String osConsole = null; - private String generateScript = null; - - /** 24 hours */ - private Long watchdogTimeout = 24 * 60 * 60 * 1000l; - - private TestResult testResult; - - private ExecutionResources executionResources; - - /** Sudo the command, as root if empty or as user if not. */ - private String sudo = null; - // TODO make it more secure and robust, test only once - private final String sudoPrompt = UUID.randomUUID().toString(); - private String askPassProgram = "/usr/libexec/openssh/ssh-askpass"; - @SuppressWarnings("unused") - private boolean firstLine = true; - @SuppressWarnings("unused") - private CallbackHandler callbackHandler; - /** Chroot to the this path (must not be empty) */ - private String chroot = null; - - // Current - /** Current watchdog, null if process is completed */ - ExecuteWatchdog currentWatchdog = null; - - /** Empty constructor */ - public SystemCall() { - - } - - /** - * Constructor based on the provided command list. - * - * @param command - * the command list - */ - public SystemCall(List command) { - this.command = command; - } - - /** - * Constructor based on the provided command. - * - * @param cmd - * the command. If the provided string contains no space a - * command list is initialized with the argument as first - * component (useful for chained construction) - */ - public SystemCall(String cmd) { - if (cmd.indexOf(' ') < 0) { - command = new ArrayList(); - command.add(cmd); - } else { - this.cmd = cmd; - } - } - - /** Executes the system call. */ - public void run() { -// authentication = SecurityContextHolder.getContext().getAuthentication(); - - // Manage streams - Writer stdOutWriter = null; - OutputStream stdOutputStream = null; - Writer stdErrWriter = null; - InputStream stdInStream = null; - if (stdOutFile != null) - if (redirectStdOut) - stdOutputStream = createOutputStream(stdOutFile); - else - stdOutWriter = createWriter(stdOutFile, true); - - if (stdErrFile != null) { - stdErrWriter = createWriter(stdErrFile, true); - } else { - if (stdOutFile != null && !redirectStdOut) - stdErrWriter = createWriter(stdOutFile, true); - } - - try { - if (stdInFile != null) - stdInStream = stdInFile.getInputStream(); - else { - stdInStream = new PipedInputStream(); - stdInSink = new PipedOutputStream( - (PipedInputStream) stdInStream); - } - } catch (IOException e2) { - throw new SlcException("Cannot open a stream for " + stdInFile, e2); - } - - if (log.isTraceEnabled()) { - log.debug("os.name=" + System.getProperty("os.name")); - log.debug("os.arch=" + System.getProperty("os.arch")); - log.debug("os.version=" + System.getProperty("os.version")); - } - - // Execution directory - File dir = new File(getExecDirToUse()); - // if (!dir.exists()) - // dir.mkdirs(); - - // Watchdog to check for lost processes - Executor executorToUse; - if (executor != null) - executorToUse = executor; - else - executorToUse = new DefaultExecutor(); - executorToUse.setWatchdog(createWatchdog()); - - if (redirectStreams) { - // Redirect standard streams - executorToUse.setStreamHandler(createExecuteStreamHandler( - stdOutWriter, stdOutputStream, stdErrWriter, stdInStream)); - } else { - // Dummy stream handler (otherwise pump is used) - executorToUse.setStreamHandler(new DummyexecuteStreamHandler()); - } - - executorToUse.setProcessDestroyer(new ShutdownHookProcessDestroyer()); - executorToUse.setWorkingDirectory(dir); - - // Command line to use - final CommandLine commandLine = createCommandLine(); - if (logCommand) - log.info("Execute command:\n" + commandLine - + "\n in working directory: \n" + dir + "\n"); - - // Env variables - Map environmentVariablesToUse = null; - environmentVariablesToUse = new HashMap(); - if (mergeEnvironmentVariables) - environmentVariablesToUse.putAll(System.getenv()); - if (environmentVariables.size() > 0) - environmentVariablesToUse.putAll(environmentVariables); - - // Execute - ExecuteResultHandler executeResultHandler = createExecuteResultHandler(commandLine); - - // - // THE EXECUTION PROPER - // - try { - if (synchronous) - try { - int exitValue = executorToUse.execute(commandLine, - environmentVariablesToUse); - executeResultHandler.onProcessComplete(exitValue); - } catch (ExecuteException e1) { - if (e1.getExitValue() == Executor.INVALID_EXITVALUE) { - Thread.currentThread().interrupt(); - return; - } - // Sleep 1s in order to make sure error logs are flushed - Thread.sleep(1000); - executeResultHandler.onProcessFailed(e1); - } - else - executorToUse.execute(commandLine, environmentVariablesToUse, - executeResultHandler); - } catch (SlcException e) { - throw e; - } catch (Exception e) { - throw new SlcException("Could not execute command " + commandLine, - e); - } finally { - IOUtils.closeQuietly(stdOutWriter); - IOUtils.closeQuietly(stdErrWriter); - IOUtils.closeQuietly(stdInStream); - IOUtils.closeQuietly(stdInSink); - } - - } - - public synchronized String function() { - final StringBuffer buf = new StringBuffer(""); - SystemCallOutputListener tempOutputListener = new SystemCallOutputListener() { - private Long lineCount = 0l; - - public void newLine(SystemCall systemCall, String line, - Boolean isError) { - if (!isError) { - if (lineCount != 0l) - buf.append('\n'); - buf.append(line); - lineCount++; - } - } - }; - addOutputListener(tempOutputListener); - run(); - removeOutputListener(tempOutputListener); - return buf.toString(); - } - - public String asCommand() { - return createCommandLine().toString(); - } - - @Override - public String toString() { - return asCommand(); - } - - /** - * Build a command line based on the properties. Can be overridden by - * specific command wrappers. - */ - protected CommandLine createCommandLine() { - // Check if an OS specific command overrides - String osName = System.getProperty("os.name"); - List commandToUse = null; - if (osCommands.containsKey(osName)) - commandToUse = osCommands.get(osName); - else - commandToUse = command; - String cmdToUse = null; - if (osCmds.containsKey(osName)) - cmdToUse = osCmds.get(osName); - else - cmdToUse = cmd; - - CommandLine commandLine = null; - - // Which command definition to use - if (commandToUse == null && cmdToUse == null) - throw new SlcException("Please specify a command."); - else if (commandToUse != null && cmdToUse != null) - throw new SlcException( - "Specify the command either as a line or as a list."); - else if (cmdToUse != null) { - if (chroot != null && !chroot.trim().equals("")) - cmdToUse = "chroot \"" + chroot + "\" " + cmdToUse; - if (sudo != null) { - environmentVariables.put("SUDO_ASKPASS", askPassProgram); - if (!sudo.trim().equals("")) - cmdToUse = "sudo -p " + sudoPrompt + " -u " + sudo + " " - + cmdToUse; - else - cmdToUse = "sudo -p " + sudoPrompt + " " + cmdToUse; - } - - // GENERATE COMMAND LINE - commandLine = CommandLine.parse(cmdToUse); - } else if (commandToUse != null) { - if (commandToUse.size() == 0) - throw new SlcException("Command line is empty."); - - if (chroot != null && sudo != null) { - commandToUse.add(0, "chroot"); - commandToUse.add(1, chroot); - } - - if (sudo != null) { - environmentVariables.put("SUDO_ASKPASS", askPassProgram); - commandToUse.add(0, "sudo"); - commandToUse.add(1, "-p"); - commandToUse.add(2, sudoPrompt); - if (!sudo.trim().equals("")) { - commandToUse.add(3, "-u"); - commandToUse.add(4, sudo); - } - } - - // GENERATE COMMAND LINE - commandLine = new CommandLine(commandToUse.get(0).toString()); - - for (int i = 1; i < commandToUse.size(); i++) { - if (log.isTraceEnabled()) - log.debug(commandToUse.get(i)); - commandLine.addArgument(commandToUse.get(i).toString()); - } - } else { - // all cases covered previously - throw new UnsupportedException(); - } - - if (generateScript != null) { - File scriptFile = new File(getExecDirToUse() + File.separator - + generateScript); - try { - FileUtils.writeStringToFile(scriptFile, - (osConsole != null ? osConsole + " " : "") - + commandLine.toString()); - } catch (IOException e) { - throw new SlcException("Could not generate script " - + scriptFile, e); - } - commandLine = new CommandLine(scriptFile); - } else { - if (osConsole != null) - commandLine = CommandLine.parse(osConsole + " " - + commandLine.toString()); - } - - return commandLine; - } - - /** - * Creates a {@link PumpStreamHandler} which redirects streams to the custom - * logging mechanism. - */ - protected ExecuteStreamHandler createExecuteStreamHandler( - final Writer stdOutWriter, final OutputStream stdOutputStream, - final Writer stdErrWriter, final InputStream stdInStream) { - - // Log writers - OutputStream stdout = stdOutputStream != null ? stdOutputStream - : new LogOutputStream() { - protected void processLine(String line, int level) { - // if (firstLine) { - // if (sudo != null && callbackHandler != null - // && line.startsWith(sudoPrompt)) { - // try { - // PasswordCallback pc = new PasswordCallback( - // "sudo password", false); - // Callback[] cbs = { pc }; - // callbackHandler.handle(cbs); - // char[] pwd = pc.getPassword(); - // char[] arr = Arrays.copyOf(pwd, - // pwd.length + 1); - // arr[arr.length - 1] = '\n'; - // IOUtils.write(arr, stdInSink); - // stdInSink.flush(); - // } catch (Exception e) { - // throw new SlcException( - // "Cannot retrieve sudo password", e); - // } - // } - // firstLine = false; - // } - - if (line != null && !line.trim().equals("")) - logStdOut(line); - - if (stdOutWriter != null) - appendLineToFile(stdOutWriter, line); - } - }; - - OutputStream stderr = new LogOutputStream() { - protected void processLine(String line, int level) { - if (line != null && !line.trim().equals("")) - logStdErr(line); - if (stdErrWriter != null) - appendLineToFile(stdErrWriter, line); - } - }; - - PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdout, - stderr, stdInStream) { - - @Override - public void stop() throws IOException { - // prevents the method to block when joining stdin - if (stdInSink != null) - IOUtils.closeQuietly(stdInSink); - - super.stop(); - } - }; - return pumpStreamHandler; - } - - /** Creates the default {@link ExecuteResultHandler}. */ - protected ExecuteResultHandler createExecuteResultHandler( - final CommandLine commandLine) { - return new ExecuteResultHandler() { - - public void onProcessComplete(int exitValue) { - String msg = "System call '" + commandLine - + "' properly completed."; - if (log.isTraceEnabled()) - log.trace(msg); - if (testResult != null) { - forwardPath(testResult); - testResult.addResultPart(new SimpleResultPart( - TestStatus.PASSED, msg)); - } - releaseWatchdog(); - } - - public void onProcessFailed(ExecuteException e) { - - String msg = "System call '" + commandLine + "' failed."; - if (testResult != null) { - forwardPath(testResult); - testResult.addResultPart(new SimpleResultPart( - TestStatus.ERROR, msg, e)); - } else { - if (exceptionOnFailed) - throw new SlcException(msg, e); - else - log.error(msg, e); - } - releaseWatchdog(); - } - }; - } - - @Deprecated - protected void forwardPath(TestResult testResult) { - // TODO: allocate a TreeSPath - } - - /** - * Shortcut method getting the execDir to use - */ - protected String getExecDirToUse() { - try { - if (execDir != null) { - return execDir; - } - return System.getProperty("user.dir"); - } catch (Exception e) { - throw new SlcException("Cannot find exec dir", e); - } - } - - protected void logStdOut(String line) { - for (SystemCallOutputListener outputListener : outputListeners) - outputListener.newLine(this, line, false); - log(stdOutLogLevel, line); - } - - protected void logStdErr(String line) { - for (SystemCallOutputListener outputListener : outputListeners) - outputListener.newLine(this, line, true); - log(stdErrLogLevel, line); - } - - /** Log from the underlying streams. */ - protected void log(String logLevel, String line) { - // TODO optimize -// if (SecurityContextHolder.getContext().getAuthentication() == null) { -// SecurityContextHolder.getContext() -// .setAuthentication(authentication); -// } - - if ("ERROR".equals(logLevel)) - log.error(line); - else if ("WARN".equals(logLevel)) - log.warn(line); - else if ("INFO".equals(logLevel)) - log.info(line); - else if ("DEBUG".equals(logLevel)) - log.debug(line); - else if ("TRACE".equals(logLevel)) - log.trace(line); - else if (LOG_STDOUT.equals(logLevel)) - System.out.println(line); - else if ("System.err".equals(logLevel)) - System.err.println(line); - else - throw new SlcException("Unknown log level " + logLevel); - } - - /** Append line to a log file. */ - protected void appendLineToFile(Writer writer, String line) { - try { - writer.append(line).append('\n'); - } catch (IOException e) { - log.error("Cannot write to log file", e); - } - } - - /** Creates the writer for the output/err files. */ - protected Writer createWriter(Resource target, Boolean append) { - FileWriter writer = null; - try { - - final File file; - if (executionResources != null) - file = new File(executionResources.getAsOsPath(target, true)); - else - file = target.getFile(); - writer = new FileWriter(file, append); - } catch (IOException e) { - log.error("Cannot get file for " + target, e); - IOUtils.closeQuietly(writer); - } - return writer; - } - - /** Creates an outputstream for the output/err files. */ - protected OutputStream createOutputStream(Resource target) { - FileOutputStream out = null; - try { - - final File file; - if (executionResources != null) - file = new File(executionResources.getAsOsPath(target, true)); - else - file = target.getFile(); - out = new FileOutputStream(file, false); - } catch (IOException e) { - log.error("Cannot get file for " + target, e); - IOUtils.closeQuietly(out); - } - return out; - } - - /** Append the argument (for chaining) */ - public SystemCall arg(String arg) { - if (command == null) - command = new ArrayList(); - command.add(arg); - return this; - } - - /** Append the argument (for chaining) */ - public SystemCall arg(String arg, String value) { - if (command == null) - command = new ArrayList(); - command.add(arg); - command.add(value); - return this; - } - - // CONTROL - public synchronized Boolean isRunning() { - return currentWatchdog != null; - } - - private synchronized ExecuteWatchdog createWatchdog() { -// if (currentWatchdog != null) -// throw new SlcException("A process is already being monitored"); - currentWatchdog = new ExecuteWatchdog(watchdogTimeout); - return currentWatchdog; - } - - private synchronized void releaseWatchdog() { - currentWatchdog = null; - } - - public synchronized void kill() { - if (currentWatchdog != null) - currentWatchdog.destroyProcess(); - } - - /** */ - public void setCmd(String command) { - this.cmd = command; - } - - public void setCommand(List command) { - this.command = command; - } - - public void setExecDir(String execdir) { - this.execDir = execdir; - } - - public void setStdErrLogLevel(String stdErrLogLevel) { - this.stdErrLogLevel = stdErrLogLevel; - } - - public void setStdOutLogLevel(String stdOutLogLevel) { - this.stdOutLogLevel = stdOutLogLevel; - } - - public void setSynchronous(Boolean synchronous) { - this.synchronous = synchronous; - } - - public void setOsCommands(Map> osCommands) { - this.osCommands = osCommands; - } - - public void setOsCmds(Map osCmds) { - this.osCmds = osCmds; - } - - public void setEnvironmentVariables(Map environmentVariables) { - this.environmentVariables = environmentVariables; - } - - public Map getEnvironmentVariables() { - return environmentVariables; - } - - public void setWatchdogTimeout(Long watchdogTimeout) { - this.watchdogTimeout = watchdogTimeout; - } - - public void setStdOutFile(Resource stdOutFile) { - this.stdOutFile = stdOutFile; - } - - public void setStdErrFile(Resource stdErrFile) { - this.stdErrFile = stdErrFile; - } - - public void setStdInFile(Resource stdInFile) { - this.stdInFile = stdInFile; - } - - public void setTestResult(TestResult testResult) { - this.testResult = testResult; - } - - public void setLogCommand(Boolean logCommand) { - this.logCommand = logCommand; - } - - public void setRedirectStreams(Boolean redirectStreams) { - this.redirectStreams = redirectStreams; - } - - public void setExceptionOnFailed(Boolean exceptionOnFailed) { - this.exceptionOnFailed = exceptionOnFailed; - } - - public void setMergeEnvironmentVariables(Boolean mergeEnvironmentVariables) { - this.mergeEnvironmentVariables = mergeEnvironmentVariables; - } - - public void setOsConsole(String osConsole) { - this.osConsole = osConsole; - } - - public void setGenerateScript(String generateScript) { - this.generateScript = generateScript; - } - - public void setExecutionResources(ExecutionResources executionResources) { - this.executionResources = executionResources; - } - - public void setRedirectStdOut(Boolean redirectStdOut) { - this.redirectStdOut = redirectStdOut; - } - - public void addOutputListener(SystemCallOutputListener outputListener) { - outputListeners.add(outputListener); - } - - public void removeOutputListener(SystemCallOutputListener outputListener) { - outputListeners.remove(outputListener); - } - - public void setOutputListeners( - List outputListeners) { - this.outputListeners = outputListeners; - } - - public void setExecutor(Executor executor) { - this.executor = executor; - } - - public void setSudo(String sudo) { - this.sudo = sudo; - } - - public void setCallbackHandler(CallbackHandler callbackHandler) { - this.callbackHandler = callbackHandler; - } - - public void setChroot(String chroot) { - this.chroot = chroot; - } - - private class DummyexecuteStreamHandler implements ExecuteStreamHandler { - - public void setProcessErrorStream(InputStream is) throws IOException { - } - - public void setProcessInputStream(OutputStream os) throws IOException { - } - - public void setProcessOutputStream(InputStream is) throws IOException { - } - - public void start() throws IOException { - } - - public void stop() { - } - - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/SystemCallOutputListener.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/SystemCallOutputListener.java deleted file mode 100644 index b28f1ade2..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/SystemCallOutputListener.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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.core.execution.tasks; - -public interface SystemCallOutputListener { - public void newLine(SystemCall systemCall, String line, Boolean isError); -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/UploadAttachments.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/UploadAttachments.java deleted file mode 100644 index 13cc51918..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/UploadAttachments.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.core.execution.tasks; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import org.argeo.slc.SlcException; -import org.argeo.slc.core.attachment.Attachment; -import org.argeo.slc.core.attachment.AttachmentUploader; -import org.argeo.slc.core.attachment.AttachmentsEnabled; -import org.springframework.core.io.Resource; - -public class UploadAttachments implements Runnable { - private AttachmentUploader attachmentUploader; - private Attachment attachment = null; - private Resource resource = null; - private Map attachments = new HashMap(); - private List attachTo = new ArrayList(); - private Boolean newUuidPerExecution = true; - - public void run() { - if (attachment != null) { - if (resource == null) - throw new SlcException("A resource must be specified."); - uploadAndAdd(attachment, resource); - } - - for (Attachment attachmentT : attachments.keySet()) { - Resource resourceT = attachments.get(attachmentT); - uploadAndAdd(attachmentT, resourceT); - } - - } - - protected void uploadAndAdd(Attachment attachment, Resource resource) { - if (newUuidPerExecution) - attachment.setUuid(UUID.randomUUID().toString()); - attachmentUploader.upload(attachment, resource); - for (AttachmentsEnabled attachmentsEnabled : attachTo) { - attachmentsEnabled.addAttachment(attachment); - } - } - - public void setAttachmentUploader(AttachmentUploader attachmentUploader) { - this.attachmentUploader = attachmentUploader; - } - - public void setAttachments(Map attachments) { - this.attachments = attachments; - } - - public void setAttachTo(List attachTo) { - this.attachTo = attachTo; - } - - public void setAttachment(Attachment attachment) { - this.attachment = attachment; - } - - public void setResource(Resource resource) { - this.resource = resource; - } - - public void setNewUuidPerExecution(Boolean newUuidPerExecution) { - this.newUuidPerExecution = newUuidPerExecution; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/core.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/core.xml deleted file mode 100644 index df35944ee..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/tasks/core.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/templates.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/templates.xml deleted file mode 100644 index 28b742af7..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/templates.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/utils.xml b/org.argeo.slc.core/src/org/argeo/slc/core/execution/utils.xml deleted file mode 100644 index 527e701f6..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/utils.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/AsFlowDecorator.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/AsFlowDecorator.java deleted file mode 100644 index dceec1c5a..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/AsFlowDecorator.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.core.execution.xml; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.core.execution.DefaultExecutionFlow; -import org.argeo.slc.execution.ExecutionFlow; -import org.springframework.beans.BeanMetadataElement; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.xml.BeanDefinitionDecorator; -import org.springframework.beans.factory.xml.ParserContext; -import org.w3c.dom.Attr; -import org.w3c.dom.Node; - -/** Publishes a {@link Runnable} as an {@link ExecutionFlow} */ -public class AsFlowDecorator implements BeanDefinitionDecorator { - private Log log = LogFactory.getLog(AsFlowDecorator.class); - - public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder bean, - ParserContext ctx) { - String attrValue = ((Attr) node).getValue(); - if (attrValue.charAt(attrValue.length() - 1) == '/') - throw new SlcException(attrValue + " cannot end with a path"); - final String flowBeanName = attrValue; - - if (log.isTraceEnabled()) - log.trace("flowBeanName=" + flowBeanName); - - if (ctx.getRegistry().containsBeanDefinition(flowBeanName)) - throw new SlcException("A bean named " + flowBeanName - + " is already defined."); - BeanDefinitionBuilder flow = BeanDefinitionBuilder - .rootBeanDefinition(DefaultExecutionFlow.class); - ManagedList executables = new ManagedList( - 1); - - String beanName = bean.getBeanName(); - if (beanName == null) - executables.add(bean.getBeanDefinition()); - else - executables.add(new RuntimeBeanReference(beanName)); - - // if (path != null) - // flow.addPropertyValue("path", path); - flow.addPropertyValue("executables", executables); - - if (beanName != null) - ctx.getRegistry().registerBeanDefinition(flowBeanName, - flow.getBeanDefinition()); - return bean; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/ExecutionScopeDecorator.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/ExecutionScopeDecorator.java deleted file mode 100644 index dfca9d512..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/ExecutionScopeDecorator.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.core.execution.xml; - -import org.springframework.aop.scope.ScopedProxyUtils; -import org.springframework.beans.factory.config.BeanDefinitionHolder; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -import org.springframework.beans.factory.xml.BeanDefinitionDecorator; -import org.springframework.beans.factory.xml.ParserContext; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -/** - * Inspired by org.springframework.aop.config.ScopedProxyBeanDefinitionDecorator - */ -public class ExecutionScopeDecorator implements BeanDefinitionDecorator { - private static final String PROXY_TARGET_CLASS = "proxy-target-class"; - - public BeanDefinitionHolder decorate(Node node, - BeanDefinitionHolder definition, ParserContext parserContext) { - - definition.getBeanDefinition().setScope("execution"); - - // Default: CGLib not used - boolean proxyTargetClass = false; - if (node instanceof Element) { - Element ele = (Element) node; - if (ele.hasAttribute(PROXY_TARGET_CLASS)) { - proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS)).booleanValue(); - } - } - - // Register the original bean definition as it will be referenced by the scoped proxy and is relevant for tooling (validation, navigation). - String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName()); - parserContext.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName)); - - return ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass); - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/FlowBeanDefinitionParser.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/FlowBeanDefinitionParser.java deleted file mode 100644 index 7d2ab49a1..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/FlowBeanDefinitionParser.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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.core.execution.xml; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.core.execution.DefaultExecutionFlow; -import org.argeo.slc.execution.ExecutionFlow; -import org.springframework.beans.factory.BeanDefinitionStoreException; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.StringUtils; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** Interprets the tag */ -public class FlowBeanDefinitionParser extends - AbstractSingleBeanDefinitionParser { - private Log log = LogFactory.getLog(FlowBeanDefinitionParser.class); - - /** Whether the user has already be warned on path attribute usage. */ - private Boolean warnedAboutPathAttribute = false; - - @Override - protected void doParse(Element element, ParserContext parserContext, - BeanDefinitionBuilder builder) { - String path = element.getAttribute("path"); - if (StringUtils.hasText(path)) { - builder.addPropertyValue("path", path); - - // warns user only once - if (!warnedAboutPathAttribute) - log.warn("The path=\"\" attribute is deprecated" - + " and will be removed in a later release." - + " Use ."); - warnedAboutPathAttribute = true; - } - - String spec = element.getAttribute("spec"); - if (StringUtils.hasText(spec)) - builder.getBeanDefinition().getConstructorArgumentValues() - .addGenericArgumentValue(new RuntimeBeanReference(spec)); - - String abstrac = element.getAttribute("abstract"); - if (StringUtils.hasText(abstrac)) - builder.setAbstract(Boolean.parseBoolean(abstrac)); - - String parent = element.getAttribute("parent"); - if (StringUtils.hasText(parent)) - builder.setParentName(parent); - - builder.getBeanDefinition().setDescription( - DomUtils.getChildElementValueByTagName(element, "description")); - - List argsElems = new ArrayList(); - List execElems = new ArrayList(); - List specElems = new ArrayList(); - NodeList nodeList = element.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node node = nodeList.item(i); - if (node instanceof Element) { - if (DomUtils.nodeNameEquals(node, "arg")) - argsElems.add((Element) node); - else if (DomUtils.nodeNameEquals(node, "spec")) - specElems.add((Element) node); - else if (!DomUtils.nodeNameEquals(node, "description")) - execElems.add((Element) node); - } - } - - // Arguments - if (argsElems.size() != 0) { - ManagedMap args = new ManagedMap( - argsElems.size()); - for (Element argElem : argsElems) { - Object value = NamespaceUtils.parseValue(argElem, - parserContext, builder.getBeanDefinition(), null); - if (value != null) - args.put(argElem.getAttribute("name"), value); - else - throw new SlcException("No value defined."); - } - builder.getBeanDefinition().getConstructorArgumentValues() - .addGenericArgumentValue(args); - } - - // Execution specs - if (StringUtils.hasText(spec) && specElems.size() != 0) - throw new SlcException("A flow cannot have multiple specs"); - if (specElems.size() == 1) { - Object specObj = NamespaceUtils.parseBeanOrReference( - specElems.get(0), parserContext, - builder.getBeanDefinition()); - builder.getBeanDefinition().getConstructorArgumentValues() - .addGenericArgumentValue(specObj); - } else if (specElems.size() > 1) - throw new SlcException("A flow cannot have multiple specs"); - - // Executables - if (execElems.size() != 0) { - ManagedList executables = new ManagedList( - execElems.size()); - for (Element child : execElems) { - // child validity check is performed in xsd - executables.add(NamespaceUtils.parseBeanOrReference(child, - parserContext, builder.getBeanDefinition())); - } - if (executables.size() > 0) - builder.addPropertyValue("executables", executables); - } - } - - @SuppressWarnings("unchecked") - @Override - protected Class getBeanClass(Element element) { - String clss = element.getAttribute("class"); - if (StringUtils.hasText(clss)) - // TODO: check that it actually works - try { - return (Class) getClass() - .getClassLoader().loadClass(clss); - } catch (ClassNotFoundException e) { - try { - return (Class) Thread - .currentThread().getContextClassLoader() - .loadClass(clss); - } catch (ClassNotFoundException e1) { - throw new SlcException("Cannot load class " + clss, e); - } - } - else - return DefaultExecutionFlow.class; - } - - // parse nested bean definition - // private Object parseBeanReference(Element element, - // ParserContext parserContext, BeanDefinitionBuilder builder) { - // return parserContext.getDelegate().parsePropertySubElement(element, - // builder.getBeanDefinition()); - // } - - @Override - protected String resolveId(Element element, - AbstractBeanDefinition definition, ParserContext parserContext) - throws BeanDefinitionStoreException { - String name = element.getAttribute("name"); - if (StringUtils.hasText(name)) { - return name; - } else { - return super.resolveId(element, definition, parserContext); - } - } - - protected boolean shouldGenerateIdAsFallback() { - return true; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/FlowNamespaceHandler.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/FlowNamespaceHandler.java deleted file mode 100644 index 2deba8bb2..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/FlowNamespaceHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.core.execution.xml; - -import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - -public class FlowNamespaceHandler extends NamespaceHandlerSupport { - - public void init() { - registerBeanDefinitionParser("flow", new FlowBeanDefinitionParser()); - registerBeanDefinitionParser("spec", new SpecBeanDefinitionParser()); - registerBeanDefinitionDecoratorForAttribute("as-flow", - new AsFlowDecorator()); - registerBeanDefinitionParser("param", new ParamDecorator()); - - // The objective was to replace - // - attribute scope="execution" - // - and element "aop:scoped-proxy" - // by a single attribute, using an attribute decorator - // this does not work correctly with other attribute decorators (e.g. - // p namespace) since this decorator needs to be called after all - // properties have been set on target bean. - // It works properly with element decorators (called after all attribute - // decorators - registerBeanDefinitionDecorator("variable", new ExecutionScopeDecorator()); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/NamespaceUtils.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/NamespaceUtils.java deleted file mode 100644 index ccf94f131..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/NamespaceUtils.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.core.execution.xml; - -import org.argeo.slc.SlcException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * Utilities to simplify common tasks when interpreting a custom namespace and - * converting it into bean definitions. - */ -public class NamespaceUtils { - // private final static Log log = LogFactory.getLog(NamespaceUtils.class); - - /** - * Returns the value defined either: directly by the the 'value' attribute, - * as reference by the 'ref' attribute or as a nested bean. - */ - public static Object parseValue(Element element, - ParserContext parserContext, - BeanDefinition containingBeanDefintion, String valueTagName) { - Object value = null; - if (element.hasAttribute("value")) { - value = element.getAttribute("value"); - } - - if (element.hasAttribute("ref")) { - if (value != null) - throw new SlcException("Multiple value definition for " - + element); - value = new RuntimeBeanReference(element.getAttribute("ref")); - } - - Element uniqueSubElem = null; - if (valueTagName != null) { - Element valueElem = DomUtils.getChildElementByTagName(element, - valueTagName); - if (valueElem != null) { - uniqueSubElem = findUniqueSubElement(valueElem); - if (uniqueSubElem == null) - throw new SlcException("No subelement found under " - + valueElem); - } - } else {// no intermediary tag - uniqueSubElem = findUniqueSubElement(element); - } - - if (uniqueSubElem != null) { - if (value != null) - throw new SlcException("Multiple value definition for " - + element); - value = parseBeanOrReference(uniqueSubElem, parserContext, - containingBeanDefintion); - } - return value; - } - - public static Element findUniqueSubElement(Element element) { - NodeList childNodes = element.getChildNodes(); - - Element uniqueSubElem = null; - for (int i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - if (node != null && node instanceof Element) { - if (uniqueSubElem == null) - uniqueSubElem = (Element) node; - else - throw new SlcException( - "There are more than one sub element under " - + element); - } - } - return uniqueSubElem; - } - - public static Object parseBeanOrReference(Element element, - ParserContext parserContext, BeanDefinition beanDefinition) { - // return parserContext.getDelegate().parsePropertySubElement(element, - // beanDefinition); - - BeanDefinitionParserDelegate deleg = parserContext.getDelegate(); - // if ("bean".equals(element.getNodeName())) - // return deleg.parseBeanDefinitionElement(element, beanDefinition); - // else - return deleg.parsePropertySubElement(element, beanDefinition); - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/ParamDecorator.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/ParamDecorator.java deleted file mode 100644 index 16839c042..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/ParamDecorator.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.core.execution.xml; - -import org.argeo.slc.core.execution.ParameterRef; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -public class ParamDecorator extends AbstractSingleBeanDefinitionParser { - - // public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder - // bean, - // ParserContext ctx) { - // String paramName = ((Element) node).getAttribute("name"); - // String propertyName = ((Element) node.getParentNode()) - // .getAttribute("name"); - // BeanDefinitionBuilder parameterRef = BeanDefinitionBuilder - // .genericBeanDefinition(ParameterRef.class); - // parameterRef.addPropertyReference("instantiationManager", - // "instantiationManager"); - // parameterRef.addConstructorArgValue(paramName); - // bean.getBeanDefinition().getPropertyValues().addPropertyValue( - // propertyName, parameterRef.getBeanDefinition()); - // return bean; - // } - - @Override - protected void doParse(Element element, ParserContext parserContext, - BeanDefinitionBuilder builder) { - String paramName = element.getAttribute("name"); - - String instantationManagerRef = element - .getAttribute("instantiationManager"); - if (!StringUtils.hasText(instantationManagerRef)) - instantationManagerRef = "instantiationManager"; - builder.addPropertyReference("instantiationManager", - instantationManagerRef); - builder.addConstructorArgValue(paramName); - } - - @Override - protected Class getBeanClass(Element element) { - return ParameterRef.class; - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/SpecBeanDefinitionParser.java b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/SpecBeanDefinitionParser.java deleted file mode 100644 index 761e26dd1..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/SpecBeanDefinitionParser.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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.core.execution.xml; - -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.core.execution.DefaultExecutionSpec; -import org.argeo.slc.core.execution.PrimitiveSpecAttribute; -import org.argeo.slc.core.execution.RefSpecAttribute; -import org.argeo.slc.core.execution.RefValueChoice; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.ManagedList; -import org.springframework.beans.factory.support.ManagedMap; -import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.util.StringUtils; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Element; - -/** Interprets the tag */ -public class SpecBeanDefinitionParser extends - AbstractSingleBeanDefinitionParser { - private Log log = LogFactory.getLog(SpecBeanDefinitionParser.class); - - @Override - protected void doParse(Element element, ParserContext parserContext, - BeanDefinitionBuilder builder) { - builder.getBeanDefinition().setDescription( - DomUtils.getChildElementValueByTagName(element, "description")); - - ManagedMap attributes = new ManagedMap(); - - // Primitives - for (Element child : (List) DomUtils - .getChildElementsByTagName(element, "primitive")) { - BeanDefinitionBuilder childBuilder = BeanDefinitionBuilder - .genericBeanDefinition(PrimitiveSpecAttribute.class); - addCommonProperties(child, parserContext, childBuilder); - - String type = child.getAttribute("type"); - if (StringUtils.hasText(type)) - childBuilder.addPropertyValue("type", type); - - putInAttributes(attributes, child, - childBuilder.getBeanDefinition(), "primitive"); - } - - // Refs - for (Element refAttrElem : (List) DomUtils - .getChildElementsByTagName(element, "ref")) { - BeanDefinitionBuilder refAttrBuilder = BeanDefinitionBuilder - .genericBeanDefinition(RefSpecAttribute.class); - addCommonProperties(refAttrElem, parserContext, refAttrBuilder); - - String targetClassName = refAttrElem.getAttribute("targetClass"); - if (StringUtils.hasText(targetClassName)) - refAttrBuilder.addPropertyValue("targetClass", targetClassName); - - // Choices - Element choicesElem = DomUtils.getChildElementByTagName( - refAttrElem, "choices"); - if (choicesElem != null) { - List choices = DomUtils.getChildElementsByTagName( - choicesElem, "choice"); - ManagedList choiceBeans = new ManagedList( - choices.size()); - for (Element choiceElem : choices) { - BeanDefinitionBuilder choiceBuilder = BeanDefinitionBuilder - .genericBeanDefinition(RefValueChoice.class); - choiceBuilder.addPropertyValue("name", - choiceElem.getAttribute("name")); - String desc = choiceElem.getAttribute("description"); - if (StringUtils.hasText(desc)) - choiceBuilder.addPropertyValue("description", desc); - - choiceBeans.add(choiceBuilder.getBeanDefinition()); - } - refAttrBuilder.addPropertyValue("choices", choiceBeans); - } - - putInAttributes(attributes, refAttrElem, - refAttrBuilder.getBeanDefinition(), "ref"); - } - - builder.addPropertyValue("attributes", attributes); - } - - protected void addCommonProperties(Element element, - ParserContext parserContext, BeanDefinitionBuilder specAttr) { - addBooleanProperty("isImmutable", specAttr, element); - addBooleanProperty("isConstant", specAttr, element); - addBooleanProperty("isHidden", specAttr, element); - addBooleanProperty("isParameter", specAttr, element); - addBooleanProperty("isFrozen", specAttr, element); - - Object value = NamespaceUtils.parseValue(element, parserContext, - specAttr.getBeanDefinition(), "value"); - if (value != null) - specAttr.addPropertyValue("value", value); - - } - - protected void putInAttributes( - ManagedMap attributes, Element child, - BeanDefinition beanDefinition, String nature) { - String name = child.getAttribute("name"); - attributes.put(name, beanDefinition); - if (log.isTraceEnabled()) - log.debug("Added " + nature + " attribute " + name); - - } - - private void addBooleanProperty(String name, - BeanDefinitionBuilder specAttr, Element element) { - String bool = element.getAttribute(name); - if (StringUtils.hasText(bool)) - specAttr.addPropertyValue(name, Boolean.parseBoolean(bool)); - - } - - @Override - protected Class getBeanClass(Element element) { - return DefaultExecutionSpec.class; - } - - protected boolean shouldGenerateIdAsFallback() { - return false; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd deleted file mode 100644 index 8b31a60bf..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd +++ /dev/null @@ -1,384 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd b/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd deleted file mode 100644 index a70798f2d..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd +++ /dev/null @@ -1,402 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/BasicTestData.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/BasicTestData.java deleted file mode 100644 index 39a97f290..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/BasicTestData.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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.core.test; - -import org.argeo.slc.test.TestData; - -public class BasicTestData implements TestData { - private Object expected; - private Object reached; - - public Object getExpected() { - return expected; - } - - public void setExpected(Object expected) { - this.expected = expected; - } - - public Object getReached() { - return reached; - } - - public void setReached(Object reached) { - this.reached = reached; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/BasicTestDefinition.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/BasicTestDefinition.java deleted file mode 100644 index 6b92135e8..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/BasicTestDefinition.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.core.test; - -import org.argeo.slc.SlcException; -import org.argeo.slc.core.test.context.ContextUtils; -import org.argeo.slc.test.IncompatibleTestDataException; -import org.argeo.slc.test.TestData; -import org.argeo.slc.test.TestDefinition; -import org.argeo.slc.test.TestResult; -import org.argeo.slc.test.TestRun; -import org.argeo.slc.test.TestStatus; -import org.argeo.slc.test.context.ContextAware; - -/** Understands basic test data and context aware test data. */ -public class BasicTestDefinition implements TestDefinition { - - public void execute(TestRun testRun) { - if (testRun. getTestData() instanceof BasicTestData) { - BasicTestData testData = testRun.getTestData(); - TestResult result = testRun.getTestResult(); - - if (result == null) - throw new SlcException("No test result defined."); - - try { - if (testData.getExpected().equals(testData.getReached())) { - result.addResultPart(new SimpleResultPart( - TestStatus.PASSED, "Reached and expected equals")); - } else { - result.addResultPart(new SimpleResultPart( - TestStatus.FAILED, "Expected " - + testData.getExpected() + " but reached " - + testData.getReached())); - } - } catch (Exception e) { - result.addResultPart(new SimpleResultPart(TestStatus.ERROR, - "Could not compare", e)); - } - } else if (testRun. getTestData() instanceof ContextAware) { - TestData testData = testRun.getTestData(); - ContextUtils.compareReachedExpected((ContextAware) testData, - testRun.getTestResult()); - } else { - throw new IncompatibleTestDataException(testRun); - } - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleResultPart.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleResultPart.java deleted file mode 100644 index 8ad81af1c..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleResultPart.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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.core.test; - -import java.io.Serializable; - -import org.argeo.slc.test.TestResultPart; -import org.argeo.slc.test.TestRun; -import org.argeo.slc.test.TestRunAware; -import org.argeo.slc.test.TestStatus; - -/** - *

- * Basic implementation of a result part, implementing the standard three status - * approach for test results. - *

- * - * @see TestStatus - */ -public class SimpleResultPart implements TestResultPart, TestStatus, - TestRunAware, Serializable { - private static final long serialVersionUID = 6669675957685071901L; - - private Long tid; - - private String testRunUuid; - - /** The status. Default to ERROR since it should always be explicitely set. */ - private Integer status = ERROR; - private String message; - private String exceptionMessage; - - public SimpleResultPart() { - } - - public SimpleResultPart(Integer status, String message) { - this(status, message, null); - } - - public SimpleResultPart(Integer status, String message, Exception exception) { - this.status = status; - this.message = message; - setException(exception); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public void setStatus(Integer status) { - this.status = status; - } - - public Integer getStatus() { - return status; - } - - public String getExceptionMessage() { - return exceptionMessage; - } - - public void setException(Exception exception) { - if (exception == null) - return; - - StringBuffer buf = new StringBuffer(""); - buf.append(exception.toString()); - buf.append('\n'); - for (StackTraceElement elem : exception.getStackTrace()) { - buf.append('\t').append(elem.toString()).append('\n'); - } - - if (exception.getCause() != null) - addRootCause(buf, exception.getCause()); - - this.exceptionMessage = buf.toString(); - } - - protected void addRootCause(StringBuffer buf, Throwable cause) { - if (cause == null) - return; - - buf.append("Caused by: " + cause.getMessage()); - for (StackTraceElement elem : cause.getStackTrace()) { - buf.append('\t').append(elem.toString()).append('\n'); - } - - if (cause.getCause() != null) { - addRootCause(buf, cause.getCause()); - } - } - - @Override - public String toString() { - StringBuffer buf = new StringBuffer(""); - buf.append(SlcTestUtils.statusToString(status)); - if (status == PASSED || status == FAILED) { - buf.append(' '); - } else if (status == ERROR) { - buf.append(" "); - } - buf.append(message); - return buf.toString(); - } - - /** @deprecated */ - Long getTid() { - return tid; - } - - /** @deprecated */ - void setTid(Long tid) { - this.tid = tid; - } - - public String getTestRunUuid() { - return testRunUuid; - } - - /** For ORM */ - public void setTestRunUuid(String testRunUuid) { - this.testRunUuid = testRunUuid; - } - - public void notifyTestRun(TestRun testRun) { - testRunUuid = testRun.getUuid(); - } - - public void setExceptionMessage(String exceptionMessage) { - this.exceptionMessage = exceptionMessage; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleTestResult.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleTestResult.java deleted file mode 100644 index 93306a5b4..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleTestResult.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.core.test; - -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.UUID; -import java.util.Vector; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -import org.argeo.slc.test.TestResult; -import org.argeo.slc.test.TestResultPart; -import org.argeo.slc.test.TestRun; - -/** - * Basic implementation of a test result containing only a list of result parts. - */ -public class SimpleTestResult implements TestResult { - private static Log log = LogFactory.getLog(SimpleTestResult.class); - - private String uuid; - private String currentTestRunUuid; - - private Boolean throwError = true; - - private Date closeDate; - private List parts = new Vector(); - - private Map attributes = new TreeMap(); - - public void addResultPart(TestResultPart part) { - if (throwError && part.getStatus() == ERROR) { - throw new SlcException( - "There was an error in the underlying test: " - + part.getExceptionMessage()); - } - parts.add(part); - if (log.isDebugEnabled()) - log.debug(part); - } - - public void close() { - parts.clear(); - closeDate = new Date(); - } - - public List getParts() { - return parts; - } - - public Date getCloseDate() { - return closeDate; - } - - public void setThrowError(Boolean throwError) { - this.throwError = throwError; - } - - public void notifyTestRun(TestRun testRun) { - currentTestRunUuid = testRun.getUuid(); - } - - public String getUuid() { - if (uuid == null) { - uuid = UUID.randomUUID().toString(); - } - return uuid; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public String getCurrentTestRunUuid() { - return currentTestRunUuid; - } - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleTestRun.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleTestRun.java deleted file mode 100644 index 4f6a12f81..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/SimpleTestRun.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * 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.core.test; - -import java.util.UUID; - -import org.argeo.slc.deploy.DeployedSystem; -import org.argeo.slc.test.ExecutableTestRun; -import org.argeo.slc.test.TestData; -import org.argeo.slc.test.TestDefinition; -import org.argeo.slc.test.TestResult; -import org.argeo.slc.test.WritableTestRun; - -/** - * A basic bean implementation of a WritableTestRun, holding - * references to the various parts of a test run. - */ -public class SimpleTestRun implements WritableTestRun, ExecutableTestRun { - private String uuid; - - // private String slcExecutionUuid; - // private String slcExecutionStepUuid; - - private DeployedSystem deployedSystem; - private TestData testData; - private TestDefinition testDefinition; - private TestResult testResult; - - /** Executes the underlying test definition. */ - public void run() { - uuid = UUID.randomUUID().toString(); - if (testResult != null) - testResult.notifyTestRun(this); - - testDefinition.execute(this); - } - - @SuppressWarnings("unchecked") - public T getDeployedSystem() { - return (T) deployedSystem; - } - - public void setDeployedSystem(DeployedSystem deployedSystem) { - this.deployedSystem = deployedSystem; - } - - @SuppressWarnings("unchecked") - public T getTestData() { - return (T) testData; - } - - public void setTestData(TestData testData) { - this.testData = testData; - } - - @SuppressWarnings("unchecked") - public T getTestDefinition() { - return (T) testDefinition; - } - - public void setTestDefinition(TestDefinition testDefinition) { - this.testDefinition = testDefinition; - } - - @SuppressWarnings("unchecked") - public T getTestResult() { - return (T) testResult; - } - - public void setTestResult(TestResult testResult) { - this.testResult = testResult; - } - - public String getUuid() { - return uuid; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - // public String getSlcExecutionUuid() { - // return slcExecutionUuid; - // } - // - // public void setSlcExecutionUuid(String slcExecutionUuid) { - // this.slcExecutionUuid = slcExecutionUuid; - // } - // - // public String getSlcExecutionStepUuid() { - // return slcExecutionStepUuid; - // } - // - // public void setSlcExecutionStepUuid(String slcExecutionStepUuid) { - // this.slcExecutionStepUuid = slcExecutionStepUuid; - // } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/SlcTestUtils.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/SlcTestUtils.java deleted file mode 100644 index c926a691d..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/SlcTestUtils.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.core.test; - -import org.argeo.slc.SlcException; -import org.argeo.slc.test.TestStatus; - -public abstract class SlcTestUtils { - public static String statusToString(Integer status) { - if (status.equals(TestStatus.PASSED)) { - return TestStatus.STATUSSTR_PASSED; - } else if (status.equals(TestStatus.FAILED)) { - return TestStatus.STATUSSTR_FAILED; - } else if (status.equals(TestStatus.ERROR)) { - return TestStatus.STATUSSTR_ERROR; - } else { - throw new SlcException("Unrecognized status " + status); - } - } - - public static Integer stringToStatus(String statusStr) { - if (statusStr.equals(TestStatus.STATUSSTR_PASSED)) { - return TestStatus.PASSED; - } else if (statusStr.equals(TestStatus.STATUSSTR_FAILED)) { - return TestStatus.FAILED; - } else if (statusStr.equals(TestStatus.STATUSSTR_ERROR)) { - return TestStatus.ERROR; - } else { - throw new SlcException("Unrecognized status string " + statusStr); - } - } - - private SlcTestUtils() { - - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/TestDataUtils.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/TestDataUtils.java deleted file mode 100644 index b32da3801..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/TestDataUtils.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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.core.test; - -import org.argeo.slc.UnsupportedException; -import org.argeo.slc.test.TestData; -import org.argeo.slc.test.TestDataProvider; - -/** Utilities for dealing with test datas. */ -public class TestDataUtils { - /** Extracts the test data from the given provider. */ - public static T getFromProvider(Object obj, - Class clss, String key) { - if (obj instanceof TestDataProvider) { - TestDataProvider testDataProvider = (TestDataProvider) obj; - return testDataProvider.getTestData(clss, key); - } else { - throw new UnsupportedException("test data provider", obj); - } - } - - /** - * Extracts the test data from the given provider using null - * as key. - */ - public static T getFromProvider(Object obj, - Class clss) { - return getFromProvider(obj, clss, null); - } - - /** - * Returns it self after making the proper checks. Used for test data being - * their own data providers. - */ - @SuppressWarnings("unchecked") - public static T getItSelf(Class clss, - TestData testDataObject) { - if (clss.isAssignableFrom(testDataObject.getClass())) { - return (T) testDataObject; - } else { - throw new UnsupportedException("test data", testDataObject); - } - - } - - /** Makes sure this is an utility class. */ - private TestDataUtils() { - - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/ContextUtils.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/context/ContextUtils.java deleted file mode 100644 index f62fb5ca3..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/ContextUtils.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * 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.core.test.context; - -import java.util.Map; -import java.util.TreeMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.core.test.SimpleResultPart; -import org.argeo.slc.test.TestResult; -import org.argeo.slc.test.TestStatus; -import org.argeo.slc.test.context.ContextAware; -import org.argeo.slc.test.context.ParentContextAware; - -/** Utilities for comparing and synchronising contexts. */ -public class ContextUtils { - private final static Log log = LogFactory.getLog(ContextUtils.class); - - public static void compareReachedExpected(ContextAware contextAware, - TestResult testResult) { - for (String key : contextAware.getExpectedValues().keySet()) { - - // Compare expected values with reached ones - Object expectedValue = contextAware.getExpectedValues().get(key); - - if (expectedValue.toString().equals( - contextAware.getContextSkipFlag())) { - if (log.isDebugEnabled()) - log.debug("Skipped check for key '" + key + "'"); - continue; - } - - if (contextAware.getValues().containsKey(key)) { - Object reachedValue = contextAware.getValues().get(key); - - if (expectedValue.equals(contextAware.getContextAnyFlag())) { - testResult.addResultPart(new SimpleResultPart( - TestStatus.PASSED, "Expected any value for key '" - + key + "'")); - } else if (expectedValue.equals(reachedValue)) { - testResult.addResultPart(new SimpleResultPart( - TestStatus.PASSED, "Values matched for key '" + key - + "'")); - } else { - testResult.addResultPart(new SimpleResultPart( - TestStatus.FAILED, "Mismatch for key '" + key - + "': expected '" + expectedValue - + "' but reached '" + reachedValue + "'")); - } - } else { - testResult.addResultPart(new SimpleResultPart( - TestStatus.FAILED, "No value reached for key '" + key - + "'")); - } - } - } - - /** - * Makes sure that all children and sub-children of parent share the same - * maps for values and expected values. - */ - public static void synchronize(ParentContextAware parent) { - Map expectedValuesCommon = new TreeMap( - parent.getExpectedValues()); - synchronize(parent, expectedValuesCommon); - if (log.isDebugEnabled()) - log.debug("Synchronized context " + parent); - - } - - private static void synchronize(ParentContextAware parent, - Map expectedValuesCommon) { - for (ContextAware child : parent.getChildContexts()) { - // Values - putNotContained(parent.getValues(), child.getValues()); - child.setValues(parent.getValues()); - - // Expected Values - // Expected values reference is not overridden: each child has its - // own expected values map. - overrideContained(expectedValuesCommon, child.getExpectedValues()); - - // Creates a new Map in order not to disturb other context using the - // same keys - Map expectedValuesCommonChild = new TreeMap( - expectedValuesCommon); - putNotContained(expectedValuesCommonChild, - child.getExpectedValues()); - - if (child instanceof ParentContextAware) { - // Recursive sync - synchronize((ParentContextAware) child, - expectedValuesCommonChild); - } - } - - } - - /** - * Put into common map the values from child map which are not already - * defined in common map. - */ - public static void putNotContained(Map commonMap, - Map childMap) { - for (String key : childMap.keySet()) { - if (!commonMap.containsKey(key)) { - commonMap.put(key, childMap.get(key)); - } - } - } - - /** Overrides child map values with the values already set in common map */ - public static void overrideContained(Map commonMap, - Map childMap) { - for (String key : childMap.keySet()) { - if (commonMap.containsKey(key)) { - childMap.put(key, commonMap.get(key)); - } - } - } - - /** Makes sure this cannot be instantiated. */ - private ContextUtils() { - - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/DefaultContextTestData.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/context/DefaultContextTestData.java deleted file mode 100644 index ca0bf5ffb..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/DefaultContextTestData.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.core.test.context; - -import org.argeo.slc.core.test.TestDataUtils; -import org.argeo.slc.test.TestData; -import org.argeo.slc.test.TestDataProvider; - -public class DefaultContextTestData extends SimpleContextAware implements - TestData, TestDataProvider { - - public T getTestData(Class clss, String key) { - return TestDataUtils.getItSelf(clss, this); - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/SimpleContextAware.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/context/SimpleContextAware.java deleted file mode 100644 index f10be5659..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/SimpleContextAware.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.core.test.context; - -import java.util.Map; -import java.util.TreeMap; - -import org.argeo.slc.SlcException; -import org.argeo.slc.test.context.ContextAware; -import org.argeo.slc.test.context.ParentContextAware; -import org.springframework.beans.factory.InitializingBean; - -public class SimpleContextAware implements ContextAware, InitializingBean { - private ParentContextAware parentContext; - - private Map values = new TreeMap(); - private Map expectedValues = new TreeMap(); - - private String contextSkipFlag = DEFAULT_SKIP_FLAG; - private String contextAnyFlag = DEFAULT_ANY_FLAG; - - public Map getValues() { - return values; - } - - public void setValues(Map values) { - this.values = values; - } - - public Map getExpectedValues() { - return expectedValues; - } - - public void setExpectedValues(Map expectedValues) { - this.expectedValues = expectedValues; - } - - /** Used to add this context as a child by setting a property. */ - public void setParentContext(ParentContextAware parentContextAware) { - if (parentContext != null) - throw new SlcException("Parent context already set"); - this.parentContext = parentContextAware; - this.parentContext.addChildContext(this); - } - - protected ParentContextAware getParentContext() { - return parentContext; - } - - public void afterPropertiesSet() throws Exception { - if (parentContext != null) { - ContextUtils.synchronize(parentContext); - } - } - - public String getContextSkipFlag() { - return contextSkipFlag; - } - - public void setContextSkipFlag(String contextSkipFlag) { - this.contextSkipFlag = contextSkipFlag; - } - - public String getContextAnyFlag() { - return contextAnyFlag; - } - - public void setContextAnyFlag(String contextAnyFlag) { - this.contextAnyFlag = contextAnyFlag; - } - -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/SimpleParentContextAware.java b/org.argeo.slc.core/src/org/argeo/slc/core/test/context/SimpleParentContextAware.java deleted file mode 100644 index b8abf7fde..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/SimpleParentContextAware.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.core.test.context; - -import java.util.Collection; -import java.util.List; -import java.util.Vector; - -import org.argeo.slc.test.context.ContextAware; -import org.argeo.slc.test.context.ParentContextAware; -import org.springframework.beans.factory.InitializingBean; - -public class SimpleParentContextAware extends SimpleContextAware implements - ParentContextAware, InitializingBean { - private List children = new Vector(); - - public Collection getChildContexts() { - return children; - } - - public void addChildContext(ContextAware contextAware) { - children.add(contextAware); - } - - @Override - public void afterPropertiesSet() throws Exception { - if (getParentContext() != null) { - // If has a parent, sync it. - super.afterPropertiesSet(); - } else { - if (children.size() > 0) { - // No need to synchronize if no children - ContextUtils.synchronize(this); - } - } - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/package.html b/org.argeo.slc.core/src/org/argeo/slc/core/test/context/package.html deleted file mode 100644 index cd08d63f3..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/context/package.html +++ /dev/null @@ -1,6 +0,0 @@ - - - -Context variables to be passed between parts of tests. - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/package.html b/org.argeo.slc.core/src/org/argeo/slc/core/test/package.html deleted file mode 100644 index c70d2d151..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/package.html +++ /dev/null @@ -1,6 +0,0 @@ - - - -SLC Test: test of software systems. - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/core/test/spring.xml b/org.argeo.slc.core/src/org/argeo/slc/core/test/spring.xml deleted file mode 100644 index 31cf67167..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/core/test/spring.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file 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 deleted file mode 100644 index c4922d325..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrMetadataWriter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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; -import org.argeo.slc.SlcNames; - -/** - * 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 deleted file mode 100644 index c9ec874ea..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/JcrTestResult.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * 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.SlcNames; -import org.argeo.slc.SlcTypes; -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 deleted file mode 100644 index 3190c85b9..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrConstants.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 org.argeo.slc.SlcNames; - -/** 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 deleted file mode 100644 index 6353804df..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrResultUtils.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * 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.node.NodeUtils; -import org.argeo.slc.SlcException; -import org.argeo.slc.SlcNames; -import org.argeo.slc.SlcTypes; - -/** - * 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 = NodeUtils.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 = NodeUtils.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 deleted file mode 100644 index 137e298be..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrUtils.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * 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.node.NodeUtils; -import org.argeo.slc.DefaultNameVersion; -import org.argeo.slc.NameVersion; -import org.argeo.slc.SlcException; -import org.argeo.slc.SlcNames; -import org.argeo.slc.SlcTypes; -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 DefaultNameVersion(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 = NodeUtils.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/execution/JcrAgent.java b/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAgent.java deleted file mode 100644 index 89b4530ac..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAgent.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * 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 javax.jcr.security.Privilege; - -import org.argeo.jcr.JcrUtils; -import org.argeo.slc.SlcConstants; -import org.argeo.slc.SlcException; -import org.argeo.slc.SlcNames; -import org.argeo.slc.SlcTypes; -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; - -/** 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); - JcrUtils.addPrivilege(session, SlcJcrConstants.SLC_BASE_PATH, SlcConstants.ROLE_SLC, Privilege.JCR_ALL); - 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 deleted file mode 100644 index 105d549cd..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrAttachmentUploader.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 deleted file mode 100644 index 1a2576e06..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * 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.SlcNames; -import org.argeo.slc.SlcTypes; -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; - -/** - * 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 deleted file mode 100644 index e1ad69e3b..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrExecutionProcess.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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.SlcNames; -import org.argeo.slc.SlcTypes; -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; - -/** 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 deleted file mode 100644 index a73e1a94a..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrProcessThread.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - - * 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.jcr.JcrUtils; -import org.argeo.slc.SlcException; -import org.argeo.slc.SlcNames; -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; - -/** 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 SlcException("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 deleted file mode 100644 index c371b1114..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/jcr/execution/JcrRealizedFlow.java +++ /dev/null @@ -1,143 +0,0 @@ -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.SlcNames; -import org.argeo.slc.SlcTypes; -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; - -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/osgi/BundleRegister.java b/org.argeo.slc.core/src/org/argeo/slc/osgi/BundleRegister.java deleted file mode 100644 index 747785fee..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/BundleRegister.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 deleted file mode 100644 index 9877c31e6..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/BundlesManager.java +++ /dev/null @@ -1,443 +0,0 @@ -/* - * 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.Collection; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.slc.SlcException; -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.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.springframework.util.Assert; - -/** Wraps low-level access to a {@link BundleContext} */ -@SuppressWarnings("deprecation") -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 - Collection> srs = getServiceRefSynchronous( - ApplicationContext.class, filter); - ServiceReference sr = srs.iterator().next(); - 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); - 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 Collection> getServiceRefSynchronous( - Class clss, String filter) throws InvalidSyntaxException { - if (log.isTraceEnabled()) - log.debug("Filter: '" + filter + "'"); - Collection> 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, - null); - st.open(); - return st; - } - - public T getSingleService(Class clss, String filter, - Boolean synchronous) { - if (filter != null) - Assert.isTrue(OsgiFilterUtils.isValidFilter(filter), "valid filter"); - Collection> sfs; - try { - if (synchronous) - sfs = getServiceRefSynchronous(clss, filter); - else - sfs = bundleContext.getServiceReferences(clss, filter); - } catch (InvalidSyntaxException e) { - throw new SlcException("Cannot retrieve service reference for " - + filter, e); - } - - if (sfs == null || sfs.size() == 0) - return null; - else if (sfs.size() > 1) - throw new SlcException("More than one execution flow found for " - + filter); - return (T) bundleContext.getService(sfs.iterator().next()); - } - - 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 deleted file mode 100644 index 03f21c530..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/FileSystemBundleRegister.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.io.IOUtils; -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 { - JarFile jarFile = null; - try { - 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(); - } finally { - IOUtils.closeQuietly(jarFile); - } - } - } - 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 deleted file mode 100644 index 2d8b0311c..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/MultipleServiceExporterPostProcessor.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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 deleted file mode 100644 index cb11615b6..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiBundle.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 deleted file mode 100644 index df7ae9bc1..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModule.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 deleted file mode 100644 index 046cfb646..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * 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.eclipse.gemini.blueprint.service.importer.OsgiServiceLifecycleListener; -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; - -/** 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, 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) { - // FIXME why are properties null? - if (properties == null) - return; - 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) { - // FIXME why are properties null? - if (properties == null) - return; - 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); - } - } - - 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 deleted file mode 100644 index 306ad07a8..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiExecutionResources.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * 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.eclipse.gemini.blueprint.context.BundleContextAware; -import org.eclipse.gemini.blueprint.io.OsgiBundleResource; -import org.osgi.framework.BundleContext; -import org.springframework.core.io.Resource; - -/** 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 deleted file mode 100644 index 8286eccd5..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/OsgiRuntime.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.eclipse.gemini.blueprint.context.BundleContextAware; -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; - -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 deleted file mode 100644 index c76659f09..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/AbstractOsgiModularDistribution.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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.eclipse.gemini.blueprint.context.BundleContextAware; -import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; -import org.springframework.beans.factory.InitializingBean; - -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 deleted file mode 100644 index db7c7e8a1..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/BundleModularDistribution.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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"; - - 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 deleted file mode 100644 index e38d9c024..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSite.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 deleted file mode 100644 index c71656236..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteCategory.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 deleted file mode 100644 index f28c0cb12..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/EclipseUpdateSiteFeature.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 deleted file mode 100644 index 5523e6efe..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/build/OsgiRuntimeModularDistribution.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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.eclipse.gemini.blueprint.util.OsgiBundleUtils; -import org.osgi.framework.Bundle; -import org.springframework.context.ResourceLoaderAware; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; - -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 deleted file mode 100644 index 2414788c8..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/deploy/OsgiResourceSet.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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.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; -import org.osgi.framework.Bundle; -import org.osgi.framework.BundleContext; -import org.springframework.core.io.ResourceLoader; - -/** - * 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 deleted file mode 100644 index cc0aac069..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/osgi/execution.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/org.argeo.slc.core/src/org/argeo/slc/spring/AbstractSystemExecution.java b/org.argeo.slc.core/src/org/argeo/slc/spring/AbstractSystemExecution.java deleted file mode 100644 index 7813b9a5f..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/spring/AbstractSystemExecution.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.spring; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.argeo.node.NodeConstants; -import org.argeo.slc.SlcException; - -/** Provides base method for executing code with system authorization. */ -abstract class AbstractSystemExecution { - private final static Log log = LogFactory.getLog(AbstractSystemExecution.class); - private final Subject subject = new Subject(); - - /** Authenticate the calling thread */ - protected void authenticateAsSystem() { - ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); - try { - LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN, subject); - lc.login(); - } catch (LoginException e) { - throw new SlcException("Cannot login as system", e); - } finally { - Thread.currentThread().setContextClassLoader(origClassLoader); - } - if (log.isTraceEnabled()) - log.trace("System authenticated"); - } - - protected void deauthenticateAsSystem() { - ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); - try { - LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN, subject); - lc.logout(); - } catch (LoginException e) { - throw new SlcException("Cannot logout as system", e); - } finally { - Thread.currentThread().setContextClassLoader(origClassLoader); - } - } - - protected Subject getSubject() { - return subject; - } -} diff --git a/org.argeo.slc.core/src/org/argeo/slc/spring/AuthenticatedApplicationContextInitialization.java b/org.argeo.slc.core/src/org/argeo/slc/spring/AuthenticatedApplicationContextInitialization.java deleted file mode 100644 index 68a9cc993..000000000 --- a/org.argeo.slc.core/src/org/argeo/slc/spring/AuthenticatedApplicationContextInitialization.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.spring; - -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.List; - -import javax.security.auth.Subject; - -import org.eclipse.gemini.blueprint.context.DependencyInitializationAwareBeanPostProcessor; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.support.AbstractBeanFactory; -import org.springframework.beans.factory.support.SecurityContextProvider; -import org.springframework.beans.factory.support.SimpleSecurityContextProvider; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; - -/** - * Executes with a system authentication the instantiation and initialization - * methods of the application context where it has been defined. - */ -public class AuthenticatedApplicationContextInitialization extends - AbstractSystemExecution implements - DependencyInitializationAwareBeanPostProcessor, ApplicationContextAware { - /** If non empty, restricts to these beans */ - private List beanNames = new ArrayList(); - - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - if (beanNames.size() == 0 || beanNames.contains(beanName)) - authenticateAsSystem(); - return bean; - } - - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - if (beanNames.size() == 0 || beanNames.contains(beanName)) - deauthenticateAsSystem(); - return bean; - } - - public void setBeanNames(List beanNames) { - this.beanNames = beanNames; - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) - throws BeansException { - if (applicationContext.getAutowireCapableBeanFactory() instanceof AbstractBeanFactory) { - final AbstractBeanFactory beanFactory = ((AbstractBeanFactory) applicationContext - .getAutowireCapableBeanFactory()); - // retrieve subject's access control context - // and set it as the bean factory security context - Subject.doAs(getSubject(), new PrivilegedAction() { - @Override - public Void run() { - SecurityContextProvider scp = new SimpleSecurityContextProvider( - AccessController.getContext()); - beanFactory.setSecurityContextProvider(scp); - return null; - } - }); - } - } -} diff --git a/org.argeo.slc.spring/.classpath b/org.argeo.slc.spring/.classpath new file mode 100644 index 000000000..70b08e830 --- /dev/null +++ b/org.argeo.slc.spring/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.argeo.slc.spring/.gitignore b/org.argeo.slc.spring/.gitignore new file mode 100644 index 000000000..09e3bc9b2 --- /dev/null +++ b/org.argeo.slc.spring/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/target/ diff --git a/org.argeo.slc.spring/.project b/org.argeo.slc.spring/.project new file mode 100644 index 000000000..c45aff266 --- /dev/null +++ b/org.argeo.slc.spring/.project @@ -0,0 +1,28 @@ + + + org.argeo.slc.spring + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + + diff --git a/org.argeo.slc.spring/META-INF/.gitignore b/org.argeo.slc.spring/META-INF/.gitignore new file mode 100644 index 000000000..4854a41b9 --- /dev/null +++ b/org.argeo.slc.spring/META-INF/.gitignore @@ -0,0 +1 @@ +/MANIFEST.MF diff --git a/org.argeo.slc.spring/META-INF/spring.handlers b/org.argeo.slc.spring/META-INF/spring.handlers new file mode 100644 index 000000000..417a952e8 --- /dev/null +++ b/org.argeo.slc.spring/META-INF/spring.handlers @@ -0,0 +1 @@ +http\://www.argeo.org/schema/slc-flow=org.argeo.slc.core.execution.xml.FlowNamespaceHandler \ No newline at end of file diff --git a/org.argeo.slc.spring/META-INF/spring.schemas b/org.argeo.slc.spring/META-INF/spring.schemas new file mode 100644 index 000000000..229d4c5f6 --- /dev/null +++ b/org.argeo.slc.spring/META-INF/spring.schemas @@ -0,0 +1,3 @@ +http\://www.argeo.org/schema/slc-flow.xsd=org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd +http\://www.argeo.org/schema/slc-flow-1.2.xsd=org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd +http\://www.argeo.org/schema/slc-flow-0.12.xsd=org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd diff --git a/org.argeo.slc.spring/bnd.bnd b/org.argeo.slc.spring/bnd.bnd new file mode 100644 index 000000000..fb76254e2 --- /dev/null +++ b/org.argeo.slc.spring/bnd.bnd @@ -0,0 +1,6 @@ +Import-Package: javax.jcr.nodetype,\ +javax.jcr.security,\ +org.apache.tools.ant.*;resolution:="optional",\ +junit.framework;resolution:="optional",\ +org.osgi.*;version=0.0.0,\ +* diff --git a/org.argeo.slc.spring/build.properties b/org.argeo.slc.spring/build.properties new file mode 100644 index 000000000..7abe0796a --- /dev/null +++ b/org.argeo.slc.spring/build.properties @@ -0,0 +1,3 @@ +additional.bundles = org.springframework.context +bin.includes = META-INF/,. +source.. = src/ diff --git a/org.argeo.slc.spring/ext/test/log4j.properties b/org.argeo.slc.spring/ext/test/log4j.properties new file mode 100644 index 000000000..0133bab88 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/log4j.properties @@ -0,0 +1,22 @@ +# 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.spring/ext/test/org/argeo/slc/core/deploy/DefaultResourceSetTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/DefaultResourceSetTest.java new file mode 100644 index 000000000..15fb42903 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/DefaultResourceSetTest.java @@ -0,0 +1,42 @@ +/* + * 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.core.deploy; + +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.core.test.context.AbstractInternalSpringTestCase; +import org.springframework.core.io.Resource; + +public class DefaultResourceSetTest extends AbstractInternalSpringTestCase { + private final static Log log = LogFactory + .getLog(DefaultResourceSetTest.class); + + public void testListResources() { + DefaultResourceSet rrs = getBean("relativeResourceSet"); + Map res = rrs.listResources(); + for (String relativePath : res.keySet()) + log.debug(relativePath + "=" + res.get(relativePath)); + assertEquals(2, res.size()); + } + + @Override + protected String getApplicationContextLocation() { + return inPackage("relativeResourceSet.xml"); + } + +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/data/file1.txt b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/data/file1.txt new file mode 100644 index 000000000..e69de29bb diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/data/subdir/file2.txt b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/data/subdir/file2.txt new file mode 100644 index 000000000..e69de29bb diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/relativeResourceSet.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/relativeResourceSet.xml new file mode 100644 index 000000000..074c205a5 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/deploy/relativeResourceSet.xml @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.java new file mode 100644 index 000000000..004605cab --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/AbstractExecutionFlowTestCase.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.core.execution; + +import junit.framework.TestCase; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.core.test.SimpleTestResult; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.test.TestResultPart; +import org.argeo.slc.test.TestStatus; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public abstract class AbstractExecutionFlowTestCase extends TestCase { + + protected final Log log = LogFactory.getLog(getClass()); + + protected void logException(Throwable ex) { + log.info("Got Exception of class " + ex.getClass().toString() + + " with message '" + ex.getMessage() + "'."); + } + + protected void validateTestResult(SimpleTestResult testResult) { + validateTestResult(testResult, TestStatus.PASSED); + } + + protected void validateTestResult(SimpleTestResult testResult, + int expectedStatus) { + for (TestResultPart part : testResult.getParts()) { + if (part.getStatus() != expectedStatus) { + fail("Error found in TestResult: " + part.getMessage()); + } + } + } + + protected ConfigurableApplicationContext createApplicationContext( + String applicationContextSuffix) { + ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext( + inPackage(applicationContextSuffix)); + // applicationContext.start(); + return applicationContext; + } + + protected void configureAndExecuteSlcFlow(String applicationContextSuffix, + String beanName) { + ConfigurableApplicationContext applicationContext = createApplicationContext(applicationContextSuffix); + ExecutionContext executionContext = (ExecutionContext) applicationContext + .getBean("executionContext"); + ExecutionFlow executionFlow = (ExecutionFlow) applicationContext + .getBean(beanName); + if (executionFlow instanceof DefaultExecutionFlow) + ((DefaultExecutionFlow) executionFlow) + .setExecutionContext(executionContext); + try { + executionContext.beforeFlow(executionFlow); + executionFlow.run(); + } finally { + executionContext.afterFlow(executionFlow); + } + applicationContext.close(); + } + + protected String inPackage(String suffix) { + String prefix = getClass().getPackage().getName().replace('.', '/'); + return prefix + '/' + suffix; + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/BasicExecutionFlowTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/BasicExecutionFlowTest.java new file mode 100644 index 000000000..91be3bdbe --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/BasicExecutionFlowTest.java @@ -0,0 +1,185 @@ +/* + * 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.core.execution; + +import java.util.HashMap; +import java.util.Map; + +import org.argeo.slc.core.test.SimpleTestResult; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.test.TestStatus; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.ConfigurableApplicationContext; + +public class BasicExecutionFlowTest extends AbstractExecutionFlowTestCase { + // TO TEST + // - post-processing for @{} replacement in beans with complex properties + // - bean of scope other than execution are not resolved at execution + + // public void testMyTest() throws Exception { + // ConfigurableApplicationContext applicationContext = + // createApplicationContext("test.xml"); + // log.info("Start Execution"); + // ((ExecutionFlow) applicationContext.getBean("flow1")).execute(); + // applicationContext.close(); + // } + + public void testSpecOverriding() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("specOverriding.xml"); + ((ExecutionFlow) applicationContext.getBean("flow2")).run(); + SimpleTestResult res = (SimpleTestResult) applicationContext + .getBean("myTestResult"); + validateTestResult(res); + } + + public void testMultipleFlows() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("multipleFlow.xml"); + ((ExecutionFlow) applicationContext.getBean("flow1")).run(); + SimpleTestResult res = (SimpleTestResult) applicationContext + .getBean("myTestResult"); + validateTestResult(res); + res.getParts().clear(); + ((ExecutionFlow) applicationContext.getBean("flow2")).run(); + validateTestResult(res, TestStatus.FAILED); + applicationContext.close(); + } + + /** + * Test placeholder resolution in a context without scope execution or proxy + * and with cascading flows (the flow A contains the flow B) + * + * @throws Exception + */ + public void testPlaceHolders() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("placeHolders.cascading.xml"); + ((ExecutionFlow) applicationContext.getBean("flowA")).run(); + validateTestResult((SimpleTestResult) applicationContext + .getBean("myTestResult")); + applicationContext.close(); + } + + /** + * Test placeholder resolution in a context without scope execution or proxy + * and with cascading flows (the flow A contains the flow B) setting + * execution values (should have no effect) + * + * @throws Exception + */ + public void testPlaceHoldersWithExecutionValues() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("placeHolders.cascading.xml"); + + ExecutionContext executionContext = (ExecutionContext) applicationContext + .getBean("executionContext"); + Map executionParameters = new HashMap(); + executionParameters.put("p1", "e1"); + executionParameters.put("p2", "e2"); + executionParameters.put("p3", "e3"); + executionParameters.put("p4", "e4"); + executionParameters.put("p5", "e5"); + executionParameters.put("p6", "e6"); + executionParameters.put("p7", "e7"); + executionParameters.put("p8", "e8"); + addVariables(executionContext, executionParameters); + + ((ExecutionFlow) applicationContext.getBean("flowA")).run(); + validateTestResult((SimpleTestResult) applicationContext + .getBean("myTestResult")); + applicationContext.close(); + } + + public void testPlaceHoldersExec() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("placeHolders.cascading.exec.xml"); + + ExecutionContext executionContext = (ExecutionContext) applicationContext + .getBean("executionContext"); + Map executionParameters = new HashMap(); + executionParameters.put("p1", "e1"); + executionParameters.put("p2", "e2"); + executionParameters.put("p3", "e3"); + executionParameters.put("p4", "e4"); + executionParameters.put("p5", "e5"); + executionParameters.put("p6", "e6"); + addVariables(executionContext, executionParameters); + + ((ExecutionFlow) applicationContext.getBean("flowA")).run(); + validateTestResult((SimpleTestResult) applicationContext + .getBean("myTestResult")); + applicationContext.close(); + } + + public void testCanonicFlowParameters() throws Exception { + configureAndExecuteSlcFlow("canonic-001.xml", "canonic.001"); + } + + public void testCanonicDefaultValues() throws Exception { + configureAndExecuteSlcFlow("canonic-002.xml", "canonic.002"); + } + + public void testCanonicMissingValues() throws Exception { + try { + configureAndExecuteSlcFlow("canonic-003.error.xml", "canonic.003"); + fail("Parameter not set - should be rejected."); + } catch (BeanCreationException e) { + // exception expected + logException(e); + } + } + + public void testCanonicUnknownParameter() throws Exception { + try { + configureAndExecuteSlcFlow("canonic-004.error.xml", "canonic.004"); + fail("Unknown parameter set - should be rejected."); + } catch (BeanCreationException e) { + // exception expected + logException(e); + } + } + + public void testListSetMap() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("listSetMap.xml"); + ExecutionFlow executionFlow = (ExecutionFlow) applicationContext + .getBean("myFlow"); + executionFlow.run(); + + validateTestResult((SimpleTestResult) applicationContext + .getBean("myTestResult")); + + // BasicTestData res = (BasicTestData) + // applicationContext.getBean("cascadingComplex.testData"); + // log.info("res=" + res.getReached().toString()); + + applicationContext.close(); + } + + public void testListSetMapMultipleFlows() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("listSetMapMultipleFlow.xml"); + ((ExecutionFlow) applicationContext.getBean("flow1")).run(); + SimpleTestResult res = (SimpleTestResult) applicationContext + .getBean("myTestResult"); + validateTestResult(res); + res.getParts().clear(); + ((ExecutionFlow) applicationContext.getBean("flow2")).run(); + validateTestResult(res, TestStatus.FAILED); + applicationContext.close(); + } + + protected void addVariables(ExecutionContext executionContext, + Map vars) { + for (String key : vars.keySet()) + executionContext.setVariable(key, vars.get(key)); + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/DefaultAgentCliTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/DefaultAgentCliTest.java new file mode 100644 index 000000000..a7d9b8b78 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/DefaultAgentCliTest.java @@ -0,0 +1,18 @@ +package org.argeo.slc.core.execution; + +import java.net.URI; +import java.util.List; + +import junit.framework.TestCase; + +public class DefaultAgentCliTest extends TestCase { + public void testArgsToUris() { + String[] args = { "org.argeo.slc.demo.minimal", "HelloWorld/WithVar", + "--testKey", "555" }; + List uris = DefaultAgentCli.asURIs(args); + assertEquals(1, uris.size()); + assertEquals( + "flow:/org.argeo.slc.demo.minimal/HelloWorld/WithVar?testKey=555", + uris.get(0).toString()); + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java new file mode 100644 index 000000000..55afdc0c8 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/ExceptionIfInitCalledTwice.java @@ -0,0 +1,42 @@ +/* + * 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.core.execution; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.InitializingBean; + +public class ExceptionIfInitCalledTwice implements Runnable, InitializingBean { + private final static Log log = LogFactory + .getLog(ExceptionIfInitCalledTwice.class); + + private Boolean calledOnce = false; + + public void run() { + log.info(getClass().getSimpleName() + " ran properly"); + } + + public void afterPropertiesSet() throws Exception { + log.info(getClass().getSimpleName() + " init method called"); + + if (calledOnce) + throw new SlcException(getClass().getSimpleName() + + "init method called twice."); + else + calledOnce = true; + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.java new file mode 100644 index 000000000..8b3d2ec25 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesSpringTest.java @@ -0,0 +1,68 @@ +/* + * 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.core.execution; + +import java.io.File; + +public class FileExecutionResourcesSpringTest extends + AbstractExecutionFlowTestCase { + private String basePath = FileExecutionResources.DEFAULT_EXECUTION_RESOURCES_TMP_PATH; + + public void testSimple() throws Exception { + File file = getFile("subdir/writeTo"); + try { + assertFalse(file.exists()); + configureAndExecuteSlcFlow("executionResources.xml", + "executionResources.simple"); + assertTrue(file.exists()); + } finally { + file.deleteOnExit(); + } + } + + public void testPlaceholderPass() throws Exception { + File file = getFile("subdir/60"); + try { + assertFalse(file.exists()); + configureAndExecuteSlcFlow("executionResources.xml", + "executionResources.placeholderPass"); + assertTrue(file.exists()); + } finally { + file.deleteOnExit(); + } + } + + /** + * Test that it generate the wrong file because of issue when using + * execution placeholder in contructor-arg + */ + public void testPlaceholderFail() throws Exception { + File file = getFile("subdir/@{var}"); + try { + assertFalse(file.exists()); + configureAndExecuteSlcFlow("executionResources.xml", + "executionResources.placeholderFail"); + assertTrue(file.exists()); + } finally { + file.deleteOnExit(); + } + } + + protected File getFile(String relativePath) { + return new File(basePath + File.separator + + relativePath.replace('/', File.separatorChar)); + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesTest.java new file mode 100644 index 000000000..e2dae6564 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/FileExecutionResourcesTest.java @@ -0,0 +1,58 @@ +/* + * 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.core.execution; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.commons.io.FileUtils; +import org.argeo.slc.execution.ExecutionContext; +import org.springframework.core.io.Resource; + +public class FileExecutionResourcesTest extends TestCase { + public void testGetWritableFile() throws Exception { + FileExecutionResources executionResources = new FileExecutionResources(); + ExecutionContext executionContext = new MapExecutionContext(); + executionResources.setExecutionContext(executionContext); + + String expected = "TEST"; + String reached = ""; + try { + // Resource + Resource resource = executionResources + .getWritableResource("subdir1/textRes.txt"); + assertTrue(resource.getFile().getParentFile().exists()); + assertFalse(resource.getFile().exists()); + FileUtils.writeStringToFile(resource.getFile(), expected); + reached = FileUtils.readFileToString(resource.getFile()); + assertEquals(expected, reached); + + // File + File file = executionResources.getFile("subdir2/textFile.txt"); + assertFalse(file.getParentFile().exists()); + assertFalse(file.exists()); + FileUtils.writeStringToFile(file, expected); + reached = FileUtils.readFileToString(file); + assertEquals(expected, reached); + } finally { + if (executionResources.getBaseDir() != null + && executionResources.getBaseDir().exists()) + FileUtils.deleteDirectory(executionResources.getBaseDir()); + } + + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/ParameterRefTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/ParameterRefTest.java new file mode 100644 index 000000000..35df7eb53 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/ParameterRefTest.java @@ -0,0 +1,36 @@ +/* + * 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.core.execution; + +import org.argeo.slc.core.test.SimpleTestResult; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.test.TestStatus; +import org.springframework.context.ConfigurableApplicationContext; + +public class ParameterRefTest extends AbstractExecutionFlowTestCase { + public void test001() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("parameterRef.xml"); + ((ExecutionFlow) applicationContext.getBean("parameterRef.001")).run(); + + SimpleTestResult res = (SimpleTestResult) applicationContext + .getBean("parameterRef.testResult"); + assertEquals(res.getParts().get(0).getStatus(), TestStatus.PASSED); + assertEquals(res.getParts().get(1).getStatus(), TestStatus.FAILED); + + applicationContext.close(); + } + +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/applicationContext.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/applicationContext.xml new file mode 100644 index 000000000..d83c2c125 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/applicationContext.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-001.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-001.xml new file mode 100644 index 000000000..a1c59c9b1 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-001.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-002.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-002.xml new file mode 100644 index 000000000..57f0c8a89 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-002.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-003.error.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-003.error.xml new file mode 100644 index 000000000..6de881047 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-003.error.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-004.error.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-004.error.xml new file mode 100644 index 000000000..2638ed6ee --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic-004.error.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic.xml new file mode 100644 index 000000000..8d6af0ef1 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/canonic.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/executionResources.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/executionResources.xml new file mode 100644 index 000000000..654f8b420 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/executionResources.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/imports.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/imports.xml new file mode 100644 index 000000000..7ddb4ea80 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/imports.xml @@ -0,0 +1,36 @@ + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/listSetMap.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/listSetMap.xml new file mode 100644 index 000000000..8cf72e354 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/listSetMap.xml @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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.spring/ext/test/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml new file mode 100644 index 000000000..b8626f851 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/listSetMapMultipleFlow.xml @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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.spring/ext/test/org/argeo/slc/core/execution/minimal.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/minimal.xml new file mode 100644 index 000000000..5b166970b --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/minimal.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/multipleFlow.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/multipleFlow.xml new file mode 100644 index 000000000..58a43e418 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/multipleFlow.xml @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/parameterRef.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/parameterRef.xml new file mode 100644 index 000000000..98cc14d3d --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/parameterRef.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml new file mode 100644 index 000000000..a36b4a167 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.exec.xml @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.xml new file mode 100644 index 000000000..893768be3 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/placeHolders.cascading.xml @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/specOverriding.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/specOverriding.xml new file mode 100644 index 000000000..de1dc8504 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/specOverriding.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/tasks/SystemCallTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/tasks/SystemCallTest.java new file mode 100644 index 000000000..8301b8517 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/tasks/SystemCallTest.java @@ -0,0 +1,59 @@ +/* + * 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.core.execution.tasks; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.core.execution.AbstractExecutionFlowTestCase; + +public class SystemCallTest extends AbstractExecutionFlowTestCase { + private final static Log log = LogFactory.getLog(SystemCallTest.class); + + private final String defFile = "systemCall.xml"; + + public void testSystemCallSimple() throws Exception { + if (isOsSupported()) + configureAndExecuteSlcFlow(defFile, "systemCallSimple"); + } + + public void testSystemCallList() throws Exception { + if (isOsSupported()) + configureAndExecuteSlcFlow(defFile, "systemCallList"); + } + + public void testSystemCallOsSpecific() throws Exception { + if (isOsSupported()) + configureAndExecuteSlcFlow(defFile, "systemCallOsSpecific"); + } + + public void testSystemCallWithVar() throws Exception { + if (isOsSupported()) + configureAndExecuteSlcFlow(defFile, "systemCallWithVar"); + } + + protected boolean isOsSupported() { + String osName = System.getProperty("os.name"); + final Boolean ret; + if (osName.contains("Windows")) + ret = false; + else + ret = true; + + if (ret == false) + log.warn("Skip test because OS '" + osName + "' is not supported."); + return ret; + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/tasks/systemCall.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/tasks/systemCall.xml new file mode 100644 index 000000000..8d3565040 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/tasks/systemCall.xml @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + echo + Hello + World + + + + + + + + + + + + + + + + + + + + + + + + + dir + + + + + + + ls + + + + + ls + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/test.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/test.xml new file mode 100644 index 000000000..d8bec3df0 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/test.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From basic @{testedComponentId} + + + testData1='@{testData1}' + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/FlowNamespaceTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/FlowNamespaceTest.java new file mode 100644 index 000000000..f673020e6 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/FlowNamespaceTest.java @@ -0,0 +1,65 @@ +/* + * 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.core.execution.xml; + +import org.argeo.slc.core.execution.AbstractExecutionFlowTestCase; +import org.argeo.slc.core.test.SimpleTestResult; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.springframework.context.ConfigurableApplicationContext; + +public class FlowNamespaceTest extends AbstractExecutionFlowTestCase { + public void testCanonical() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("canonic-ns.xml"); + ((ExecutionFlow) applicationContext.getBean("canonic-ns.001")).run(); + ((ExecutionFlow) applicationContext.getBean("canonic-ns.002")).run(); + } + + public void testAdvanced() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("advanced.xml"); + ((ExecutionFlow) applicationContext.getBean("flow1")).run(); + ((ExecutionFlow) applicationContext.getBean("flow2")).run(); + ((ExecutionFlow) applicationContext.getBean("flow3")).run(); + + validateTestResult((SimpleTestResult) applicationContext + .getBean("testResult")); + } + + public void testAdvancedExecution() throws Exception { + ConfigurableApplicationContext applicationContext = createApplicationContext("advanced.xml"); + + ExecutionContext executionContext = (ExecutionContext) applicationContext + .getBean("executionContext"); + executionContext.setVariable("param2", 4); + + ((ExecutionFlow) applicationContext.getBean("flow4")).run(); + + validateTestResult((SimpleTestResult) applicationContext + .getBean("testResult")); + } + + // These tests causes pb when using Spring 3 + + // public void testContainers() throws Exception { + // ConfigurableApplicationContext applicationContext = + // createApplicationContext("containers.xml"); + // ((ExecutionFlow) applicationContext.getBean("test.list.flow1")).run(); + // ((ExecutionFlow) applicationContext.getBean("test.list.flow2")).run(); + // + // validateTestResult((SimpleTestResult) applicationContext + // .getBean("testResult")); + // } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/advanced.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/advanced.xml new file mode 100644 index 000000000..49b6f7e1d --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/advanced.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + 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.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-001.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-001.xml new file mode 100644 index 000000000..aeef3a3af --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-001.xml @@ -0,0 +1,34 @@ + + + + + + Canonic 001 + + + + + + + diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-002.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-002.xml new file mode 100644 index 000000000..ac5f085eb --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns-002.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns.xml new file mode 100644 index 000000000..facb27761 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/canonic-ns.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/containers.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/containers.xml new file mode 100644 index 000000000..61bfa0703 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/containers.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + val1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + val1 + val2 + + + + + val1 + val2 + + + + + + + + + + + + + + + + + + use default value for parameter "list1" + + + val1 + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/tests.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/tests.xml new file mode 100644 index 000000000..ee58a1869 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/execution/xml/tests.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.java new file mode 100644 index 000000000..61eb3b2b3 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/AbstractInternalSpringTestCase.java @@ -0,0 +1,101 @@ +/* + * 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.core.test.context; + +import java.util.Map; + +import junit.framework.TestCase; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** Helper for tests using a Spring application context. */ +public abstract class AbstractInternalSpringTestCase extends TestCase { + protected final Log log = LogFactory.getLog(getClass()); + private ConfigurableApplicationContext context; + + /** + * Gets (and create if necessary) the application context to use. Default + * implementation uses a class path xml application context and calls + * {@link #getApplicationContextLocation()}. + */ + protected ConfigurableApplicationContext getContext() { + if (context == null) { + context = new ClassPathXmlApplicationContext( + getApplicationContextLocation()); + } + return context; + } + + /** Returns a bean from the underlying context */ + @SuppressWarnings(value = { "unchecked" }) + protected T getBean(String beanId) { + return (T) getContext().getBean(beanId); + } + + protected T getBean(Class clss) { + T bean = loadSingleFromContext(getContext(), clss); + if (bean == null) { + throw new SlcException("Cannot retrieve a unique bean of type " + + clss); + } else { + return bean; + } + } + + /** + * Th location of the application to load. The default implementation + * returns applicationContext.xml found in the same package as the + * test. + */ + protected String getApplicationContextLocation() { + return inPackage("applicationContext.xml"); + } + + /** + * Prefixes the package of the class after converting the '.' to '/' in + * order to have a resource path. + */ + protected String inPackage(String suffix) { + String prefix = getClass().getPackage().getName().replace('.', '/'); + return prefix + '/' + suffix; + } + + @SuppressWarnings(value = { "unchecked" }) + protected T loadSingleFromContext(ListableBeanFactory context, + Class clss) { + Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors( + context, clss, false, false); + if (beans.size() == 1) { + return beans.values().iterator().next(); + } else if (beans.size() > 1) { + if (log.isDebugEnabled()) { + log + .debug(("Found more that on bean for type " + clss + + ": " + beans.keySet())); + } + return null; + } else { + return null; + } + } + +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/ContextTest.java b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/ContextTest.java new file mode 100644 index 000000000..694851c82 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/ContextTest.java @@ -0,0 +1,45 @@ +/* + * 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.core.test.context; + +import java.util.List; + +import org.argeo.slc.core.test.SimpleTestResult; +import org.argeo.slc.test.TestResultPart; +import org.argeo.slc.test.TestStatus; +import org.argeo.slc.test.context.ContextAware; + +public class ContextTest extends AbstractInternalSpringTestCase { + + public void testComplexContext() { + SimpleTestResult testResult = new SimpleTestResult(); + ContextUtils.compareReachedExpected( + (ContextAware) getBean("context.c1"), testResult); + ContextUtils.compareReachedExpected( + (ContextAware) getBean("context.c2"), testResult); + ContextUtils.compareReachedExpected( + (ContextAware) getBean("context.c3"), testResult); + + List parts = testResult.getParts(); + assertEquals(6, parts.size()); + assertEquals(TestStatus.PASSED, parts.get(0).getStatus()); + assertEquals(TestStatus.PASSED, parts.get(1).getStatus()); + assertEquals(TestStatus.PASSED, parts.get(2).getStatus()); + assertEquals(TestStatus.FAILED, parts.get(3).getStatus()); + assertEquals(TestStatus.PASSED, parts.get(4).getStatus()); + assertEquals(TestStatus.PASSED, parts.get(5).getStatus()); + } +} diff --git a/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/applicationContext.xml b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/applicationContext.xml new file mode 100644 index 000000000..4949c4eb1 --- /dev/null +++ b/org.argeo.slc.spring/ext/test/org/argeo/slc/core/test/context/applicationContext.xml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/pom.xml b/org.argeo.slc.spring/pom.xml new file mode 100644 index 000000000..29ba3cf97 --- /dev/null +++ b/org.argeo.slc.spring/pom.xml @@ -0,0 +1,92 @@ + + 4.0.0 + + org.argeo.slc + argeo-slc + 2.1.17-SNAPSHOT + .. + + org.argeo.slc.spring + SLC Spring Runtime + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + + + + + org.argeo.commons + org.argeo.enterprise + ${version.argeo-commons} + + + org.argeo.commons + org.argeo.node.api + ${version.argeo-commons} + + + org.argeo.commons + org.argeo.cms + ${version.argeo-commons} + + + org.argeo.commons + org.argeo.jcr + ${version.argeo-commons} + + + org.argeo.commons + org.argeo.util + ${version.argeo-commons} + + + + + org.argeo.slc + org.argeo.slc.api + 2.1.17-SNAPSHOT + + + + + org.argeo.tp.spring + org.springframework.beans + + + org.argeo.tp.spring + org.springframework.core + + + org.argeo.tp.spring + org.springframework.context + + + org.argeo.tp.spring + org.springframework.aop + + + org.argeo.tp.gemini + org.eclipse.gemini.blueprint.core + + + org.argeo.tp.gemini + org.eclipse.gemini.blueprint.io + + + + + org.argeo.tp.apache.ant + org.apache.ant + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/ant/AntFlowGenerator.java b/org.argeo.slc.spring/src/org/argeo/slc/ant/AntFlowGenerator.java new file mode 100644 index 000000000..9dea43e49 --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/ant/AntRun.java b/org.argeo.slc.spring/src/org/argeo/slc/ant/AntRun.java new file mode 100644 index 000000000..1e2dcb940 --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/core/attachment/Attachment.java b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/Attachment.java new file mode 100644 index 000000000..ecde0b936 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/Attachment.java @@ -0,0 +1,26 @@ +/* + * 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.core.attachment; + +public interface Attachment { + public String getUuid(); + + public void setUuid(String uuid); + + public String getName(); + + public String getContentType(); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentUploader.java b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentUploader.java new file mode 100644 index 000000000..eb484c92c --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentUploader.java @@ -0,0 +1,22 @@ +/* + * 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.core.attachment; + +import org.springframework.core.io.Resource; + +public interface AttachmentUploader { + public void upload(Attachment attachment, Resource resource); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentsEnabled.java b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentsEnabled.java new file mode 100644 index 000000000..780a6a483 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentsEnabled.java @@ -0,0 +1,20 @@ +/* + * 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.core.attachment; + +public interface AttachmentsEnabled { + public void addAttachment(Attachment attachment); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentsStorage.java b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentsStorage.java new file mode 100644 index 000000000..2214afabf --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/AttachmentsStorage.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.core.attachment; + +import java.io.InputStream; +import java.io.OutputStream; + +public interface AttachmentsStorage { + public void retrieveAttachment(Attachment attachment, + OutputStream outputStream); + + /** Does NOT close the provided input stream. */ + public void storeAttachment(Attachment attachment, InputStream inputStream); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/FileAttachmentsStorage.java b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/FileAttachmentsStorage.java new file mode 100644 index 000000000..3b7e62dac --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/FileAttachmentsStorage.java @@ -0,0 +1,176 @@ +/* + * 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.core.attachment; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; + +public class FileAttachmentsStorage implements AttachmentsStorage, + AttachmentUploader, InitializingBean { + private final static Log log = LogFactory + .getLog(FileAttachmentsStorage.class); + + private File attachmentsDirectory; + + private String attachmentsTocFileName = "attachmentsToc.csv"; + + private DateFormat dateFormatDay = new SimpleDateFormat("yyyy-MM-dd"); + private DateFormat dateFormatTime = new SimpleDateFormat("HH:mm:ss"); + + public void afterPropertiesSet() { + if (attachmentsDirectory == null) { + + String osgiInstanceArea = System.getProperty("osgi.instance.area"); + if (osgiInstanceArea != null) { + if (osgiInstanceArea.startsWith("file:")) + osgiInstanceArea = osgiInstanceArea.substring("file:" + .length()); + attachmentsDirectory = new File(osgiInstanceArea + + File.separator + "slcAttachments"); + } + + if (attachmentsDirectory == null) { + String tempDir = System.getProperty("java.io.tmpdir"); + attachmentsDirectory = new File(tempDir + File.separator + + "slcAttachments"); + } + } + if (!attachmentsDirectory.exists()) + attachmentsDirectory.mkdirs(); + if (log.isDebugEnabled()) + log.debug("File attachment storage initialized in directory " + + attachmentsDirectory); + } + + public void retrieveAttachment(Attachment attachment, + OutputStream outputStream) { + File file = getFile(attachment); + InputStream in = null; + try { + byte[] buffer = new byte[1024 * 1024]; + in = new FileInputStream(file); + int read = -1; + while ((read = in.read(buffer)) >= 0) { + outputStream.write(buffer, 0, read); + } + if (log.isTraceEnabled()) + log.trace("Read " + attachment + " from " + file); + } catch (IOException e) { + throw new SlcException("Cannot write attachment " + attachment + + " to " + file, e); + } finally { + IOUtils.closeQuietly(in); + } + } + + public void storeAttachment(Attachment attachment, InputStream inputStream) { + File file = getFile(attachment); + FileOutputStream out = null; + try { + byte[] buffer = new byte[1024 * 1024]; + out = new FileOutputStream(file); + int read = -1; + while ((read = inputStream.read(buffer)) >= 0) { + out.write(buffer, 0, read); + } + if (log.isTraceEnabled()) + log.trace("Wrote " + attachment + " to " + file); + updateAttachmentToc(attachment, file); + } catch (IOException e) { + throw new SlcException("Cannot write attachment " + attachment + + " to " + file, e); + } finally { + IOUtils.closeQuietly(out); + } + + } + + public void upload(Attachment attachment, Resource resource) { + try { + storeAttachment(attachment, resource.getInputStream()); + } catch (IOException e) { + throw new SlcException("Cannot upload attachment " + attachment, e); + } + } + + /** For monitoring purposes only */ + protected void updateAttachmentToc(Attachment attachment, File file) { + Date date = new Date(file.lastModified()); + FileWriter writer = null; + try { + writer = new FileWriter(attachmentsDirectory + File.separator + + attachmentsTocFileName, true); + writer.append(dateFormatDay.format(date)); + writer.append(','); + writer.append(dateFormatTime.format(date)); + writer.append(','); + writer.append(attachment.getUuid()); + writer.append(','); + writer.append(attachment.getName()); + writer.append(','); + writer.append(attachment.getContentType()); + writer.append(','); + writer.append(Long.toString(file.length())); + writer.append(','); + writer.append(file.getCanonicalPath()); + writer.append('\n'); + } catch (IOException e) { + log.warn("Could not update attachments TOC for " + attachment + + " and file " + file, e); + } finally { + IOUtils.closeQuietly(writer); + } + + } + + protected File getFile(Attachment attachment) { + File file = new File(attachmentsDirectory + File.separator + + attachment.getUuid()); + return file; + } + + public void setAttachmentsDirectory(File attachmentsDirectory) { + this.attachmentsDirectory = attachmentsDirectory; + } + + public void setAttachmentsTocFileName(String attachmentsTocFileName) { + this.attachmentsTocFileName = attachmentsTocFileName; + } + + public void setDateFormatDay(DateFormat dateFormatDay) { + this.dateFormatDay = dateFormatDay; + } + + public void setDateFormatTime(DateFormat dateFormatTime) { + this.dateFormatTime = dateFormatTime; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/SimpleAttachment.java b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/SimpleAttachment.java new file mode 100644 index 000000000..6248dd71e --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/attachment/SimpleAttachment.java @@ -0,0 +1,78 @@ +/* + * 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.core.attachment; + +import java.io.Serializable; +import java.util.UUID; + +public class SimpleAttachment implements Attachment, Serializable { + private static final long serialVersionUID = 6615155908800610606L; + private String uuid = UUID.randomUUID().toString(); + private String name; + private String contentType = ""; + + public SimpleAttachment() { + } + + public SimpleAttachment(String uuid, String name, String contentType) { + super(); + this.uuid = uuid; + this.name = name; + this.contentType = contentType; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + public String toString() { + return "Attachment #" + uuid + "(" + name + ", " + contentType + ")"; + } + + public boolean equals(Object obj) { + if (obj instanceof Attachment) { + Attachment attachment = (Attachment) obj; + if (uuid != null && attachment.getUuid() != null) + return uuid.equals(attachment.getUuid()); + + if (name != null && attachment.getName() != null) + return name.equals(attachment.getName()); + + return hashCode() == attachment.hashCode(); + } + return false; + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/build/ResourceDistribution.java b/org.argeo.slc.spring/src/org/argeo/slc/core/build/ResourceDistribution.java new file mode 100644 index 000000000..4ebbe92a4 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/build/ResourceDistribution.java @@ -0,0 +1,62 @@ +/* + * 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.core.build; + +import java.io.IOException; +import java.io.InputStream; + +import org.argeo.slc.SlcException; +import org.argeo.slc.StreamReadable; +import org.argeo.slc.build.Distribution; +import org.springframework.core.io.Resource; + +/** A software distribution archive accessible via a {@link Resource}. */ +public class ResourceDistribution implements Distribution, StreamReadable { + private Resource resource; + + public ResourceDistribution() { + } + + public ResourceDistribution(Resource location) { + this.resource = location; + } + + public String getDistributionId() { + return resource.toString(); + } + + public Resource getResource() { + return resource; + } + + public void setResource(Resource resource) { + this.resource = resource; + } + + public InputStream getInputStream() { + try { + return resource.getInputStream(); + } catch (IOException e) { + throw new SlcException("Cannot get input stream", e); + } + } + + @Override + public String toString() { + return resource.toString(); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/build/VersionDistributionId.java b/org.argeo.slc.spring/src/org/argeo/slc/core/build/VersionDistributionId.java new file mode 100644 index 000000000..c11dc00ea --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/build/VersionDistributionId.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.core.build; + +import java.util.StringTokenizer; + +/** + *

+ * An implementation of the distribution id using the standard + * Major.Minor.Release notation. And additional arbitrary string can also be + * added. + *

+ * + *

+ * Examples:
+ * 0.2.6
+ * 2.4.12.RC1 + *

+ */ +public class VersionDistributionId { + + private Integer major; + private Integer minor; + private Integer release; + private String additional; + + /** Parse the provided string in order to set the various components. */ + public void setVersionString(String str) { + StringTokenizer st = new StringTokenizer(str, "."); + if (st.hasMoreTokens()) + major = Integer.parseInt(st.nextToken()); + if (st.hasMoreTokens()) + minor = Integer.parseInt(st.nextToken()); + if (st.hasMoreTokens()) + release = Integer.parseInt(st.nextToken()); + if (st.hasMoreTokens()) + additional = st.nextToken(); + } + + public Integer getMajor() { + return major; + } + + public void setMajor(Integer major) { + this.major = major; + } + + public Integer getMinor() { + return minor; + } + + public void setMinor(Integer minor) { + this.minor = minor; + } + + public Integer getRelease() { + return release; + } + + public void setRelease(Integer release) { + this.release = release; + } + + public String getAdditional() { + return additional; + } + + public void setAdditional(String additional) { + this.additional = additional; + } + + @Override + public boolean equals(Object obj) { + // TODO Auto-generated method stub + return super.equals(obj); + } + + @Override + public String toString() { + return major + "." + minor + "." + release + + (additional != null ? "." + additional : ""); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/build/VersionedResourceDistribution.java b/org.argeo.slc.spring/src/org/argeo/slc/core/build/VersionedResourceDistribution.java new file mode 100644 index 000000000..52307ec67 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/build/VersionedResourceDistribution.java @@ -0,0 +1,62 @@ +/* + * 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.core.build; + +import org.argeo.slc.NameVersion; +import org.springframework.core.io.Resource; + +/** + * The distribution of a software package (jar, zip, RPM, etc.) which is + * versioned. The archive itself is accessible via a {@link Resource}. + */ +public class VersionedResourceDistribution extends ResourceDistribution + implements NameVersion { + private String name; + private String version; + + public VersionedResourceDistribution() { + super(); + } + + public VersionedResourceDistribution(NameVersion nameVersion, + Resource resource) { + this(nameVersion.getName(), nameVersion.getVersion(), resource); + } + + public VersionedResourceDistribution(String name, String version, + Resource resource) { + super(resource); + this.name = name; + this.version = version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/build/package.html b/org.argeo.slc.spring/src/org/argeo/slc/core/build/package.html new file mode 100644 index 000000000..5da205278 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/build/package.html @@ -0,0 +1,6 @@ + + + +SLC Build: building of software systems. + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/DefaultResourceSet.java b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/DefaultResourceSet.java new file mode 100644 index 000000000..abdcfeec3 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/DefaultResourceSet.java @@ -0,0 +1,186 @@ +/* + * 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.core.deploy; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; + +public class DefaultResourceSet implements ResourceLoaderAware, + InitializingBean, ResourceSet { + private final static Log log = LogFactory.getLog(DefaultResourceSet.class); + public final static String DEFAULT_EXCLUDES = "**/.svn/**"; + + private String base; + private String include; + private List includes = new ArrayList(); + private String exclude; + private List excludes = new ArrayList(); + private Boolean useDefaultExcludes = true; + private ResourcePatternResolver resourcePatternResolver; + private PathMatcher excludePathMatcher = new AntPathMatcher(); + + private ResourceLoader resourceLoader; + + /** List the resources, identified by their relative path. */ + public Map listResources() { + try { + Map res = new TreeMap(); + if (base == null) + return res; + String baseResUrl = getResourceLoaderToUse().getResource(base) + .getURL().toString(); + for (String includePattern : includes) + processInclude(res, includePattern, baseResUrl); + return res; + } catch (IOException e) { + throw new SlcException("Cannot list resource from " + base, e); + } + } + + protected void processInclude(Map res, String include, + String baseResUrl) throws IOException { + String pattern = base + "/" + include; + if (log.isTraceEnabled()) + log.trace("Look for resources with pattern '" + pattern + + "' in base url " + baseResUrl); + Resource[] resources = resourcePatternResolver.getResources(pattern); + resources: for (Resource resource : resources) { + String url = resource.getURL().toString(); + String relPath = url.substring(baseResUrl.length()); + + // skip dir + if (relPath.charAt(relPath.length() - 1) == '/') { + if (log.isTraceEnabled()) + log.trace("Skip directory " + relPath + "=" + resource); + continue resources; + } + + // make sure there is not starting '/' + if (relPath.charAt(0) == '/') + relPath = relPath.substring(1); + + // skip excludes + for (String exclude : excludes) + if (excludePathMatcher.match(exclude, relPath)) { + if (log.isTraceEnabled()) + log.trace("Exclude " + relPath + "=" + resource); + continue resources; + } + + // check if already exists + if (res.containsKey(relPath)) + log.warn(relPath + " already matched by " + res.get(relPath) + + ", " + resource + " will override it."); + + // store the marched resource + res.put(relPath, resource); + if (log.isTraceEnabled()) + log.trace(relPath + "=" + resource); + } + + } + + public void afterPropertiesSet() throws Exception { + if (resourcePatternResolver == null) + resourcePatternResolver = new PathMatchingResourcePatternResolver( + getResourceLoaderToUse()); + if (include != null) + addCommaSeparatedToList(include, includes); + if (exclude != null) + addCommaSeparatedToList(exclude, excludes); + + if (includes.size() == 0) + includes.add("**"); + + if (useDefaultExcludes) + addCommaSeparatedToList(DEFAULT_EXCLUDES, excludes); + } + + private void addCommaSeparatedToList(String str, List lst) { + StringTokenizer st = new StringTokenizer(str, ","); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (!lst.contains(token)) + lst.add(token); + } + } + + public void setResourceLoader(ResourceLoader resourceLoader) { + this.resourceLoader = resourceLoader; + } + + /** + * Can be overridden in order to provide the proper resource loader used to + * resolve resources. + */ + public ResourceLoader getResourceLoaderToUse() { + return resourceLoader; + } + + public void setBase(String base) { + this.base = base; + } + + public void setInclude(String include) { + this.include = include; + } + + public void setIncludes(List includes) { + this.includes = includes; + } + + public void setExclude(String exclude) { + this.exclude = exclude; + } + + public void setExcludes(List excludes) { + this.excludes = excludes; + } + + public void setUseDefaultExcludes(Boolean useDefaultExcludes) { + this.useDefaultExcludes = useDefaultExcludes; + } + + public void setExcludePathMatcher(PathMatcher excludePathMatcher) { + this.excludePathMatcher = excludePathMatcher; + } + + public void setResourcePatternResolver( + ResourcePatternResolver resourcePatternResolver) { + this.resourcePatternResolver = resourcePatternResolver; + } + + public ResourcePatternResolver getResourcePatternResolver() { + return resourcePatternResolver; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/DigestCheck.java b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/DigestCheck.java new file mode 100644 index 000000000..be8355fe3 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/DigestCheck.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.core.deploy; + +import java.io.File; +import java.io.IOException; + +import org.argeo.slc.SlcException; +import org.springframework.core.io.Resource; +import org.springframework.util.DigestUtils; + +/** Add Spring capabilities to {@link DigestUtils} */ +public class DigestCheck extends DigestUtils { + public static String digest(String algorithm, Resource resource) { + try { + File file = resource.getFile(); + return org.argeo.util.DigestUtils.digest(algorithm, file); + } catch (IOException e) { + try { + return org.argeo.util.DigestUtils.digest(algorithm, + resource.getInputStream()); + } catch (IOException e1) { + throw new SlcException("Cannot digest " + resource + + " with algorithm " + algorithm, e); + } + } + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/LocalFilesDeployment.java b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/LocalFilesDeployment.java new file mode 100644 index 000000000..79ad83597 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/LocalFilesDeployment.java @@ -0,0 +1,74 @@ +/* + * 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.core.deploy; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.argeo.slc.SlcException; +import org.springframework.core.io.Resource; + +public class LocalFilesDeployment implements Runnable { + private String targetBase = ""; + private ResourceSet resourceSet; + + public LocalFilesDeployment() { + } + + public LocalFilesDeployment(ResourceSet resourceSet) { + this.resourceSet = resourceSet; + } + + public void run() { + Map resources = resourceSet.listResources(); + for (String relPath : resources.keySet()) { + File targetFile = new File(targetBase + File.separator + relPath); + File parentDir = targetFile.getParentFile(); + if (!parentDir.exists()) + parentDir.mkdirs(); + + Resource resource = resources.get(relPath); + + InputStream in = null; + OutputStream out = null; + try { + in = resource.getInputStream(); + out = FileUtils.openOutputStream(targetFile); + IOUtils.copy(in, out); + } catch (IOException e) { + throw new SlcException("Cannot extract " + resource + " to " + + targetFile, e); + } finally { + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(out); + } + } + } + + public void setTargetBase(String targetBase) { + this.targetBase = targetBase; + } + + public void setResourceSet(ResourceSet resourceSet) { + this.resourceSet = resourceSet; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/MultiResourceSet.java b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/MultiResourceSet.java new file mode 100644 index 000000000..8da17ba42 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/MultiResourceSet.java @@ -0,0 +1,45 @@ +/* + * 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.core.deploy; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.springframework.core.io.Resource; + +public class MultiResourceSet implements ResourceSet { + private List resourceSets = new ArrayList(); + + public Map listResources() { + Map res = new HashMap(); + for (ResourceSet resourceSet : resourceSets) { + res.putAll(resourceSet.listResources()); + } + return res; + } + + /** Last listed override previous for the same relative paths. */ + public void setResourceSets(List resourceSets) { + this.resourceSets = resourceSets; + } + + public List getResourceSets() { + return resourceSets; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/ResourceSet.java b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/ResourceSet.java new file mode 100644 index 000000000..01c01abae --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/ResourceSet.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.core.deploy; + +import java.util.Map; + +import org.springframework.core.io.Resource; + +public interface ResourceSet { + /** + * List the resources, identified by their relative path. Relative paths + * must NOT start with a '/'. + */ + public Map listResources(); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/SimpleExecutables.java b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/SimpleExecutables.java new file mode 100644 index 000000000..5a5b8259f --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/SimpleExecutables.java @@ -0,0 +1,90 @@ +/* + * 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.core.deploy; + +import java.io.File; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.build.Distribution; +import org.argeo.slc.deploy.DeploymentData; +import org.argeo.slc.deploy.InstalledExecutables; +import org.argeo.slc.deploy.TargetData; + +public class SimpleExecutables implements InstalledExecutables { + private final static Log log = LogFactory.getLog(SimpleExecutables.class); + + private String baseDir; + private Map paths = new TreeMap(); + + private Distribution distribution; + + public String getExecutablePath(String key) { + String path = paths.get(key); + if (path == null) { + if (log.isDebugEnabled()) + log.debug("No executable path found for key " + key + + ", using the key as executable name."); + path = key; + } + + if (baseDir != null) + path = baseDir + File.separator + path; + return path; + } + + public String getDeployedSystemId() { + // TODO Auto-generated method stub + return null; + } + + public DeploymentData getDeploymentData() { + // TODO Auto-generated method stub + return null; + } + + public Distribution getDistribution() { + return distribution; + } + + public TargetData getTargetData() { + // TODO Auto-generated method stub + return null; + } + + public String getBaseDir() { + return baseDir; + } + + public void setBaseDir(String baseDir) { + this.baseDir = baseDir; + } + + public Map getPaths() { + return paths; + } + + public void setPaths(Map paths) { + this.paths = paths; + } + + public void setDistribution(Distribution distribution) { + this.distribution = distribution; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/VersionedDirSync.java b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/VersionedDirSync.java new file mode 100644 index 000000000..13d254366 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/VersionedDirSync.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.core.deploy; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.deploy.VersioningDriver; + +/** + * Synchronizes an URL to a local directory, taking into account versioning + * information if possible. + */ +public class VersionedDirSync implements Runnable { + private final static Log log = LogFactory.getLog(VersionedDirSync.class); + + private VersioningDriver versioningDriver; + private File dir; + private String url; + private Boolean clean = false; + + private Boolean changed = null; + + public void run() { + changed = null; + if (clean) { + try { + log.info("Clean " + dir); + FileUtils.deleteDirectory(dir); + } catch (IOException e) { + throw new SlcException("Cannot delete checkout directory " + + dir, e); + } + dir.mkdirs(); + } + log.info("Checkout " + url + " to " + dir); + changed = versioningDriver.checkout(url, dir, true); + if (log.isDebugEnabled()) + log.debug("Synchronized " + url + " to " + dir); + } + + public void setVersioningDriver(VersioningDriver versioningDriver) { + this.versioningDriver = versioningDriver; + } + + public void setDir(File dir) { + this.dir = dir; + } + + public void setUrl(String url) { + this.url = url; + } + + /** Delete before checkout */ + public void setClean(Boolean clean) { + this.clean = clean; + } + + /** Whether last call has changed the directory */ + public Boolean getChanged() { + if (changed == null) + throw new SlcException("Sync has not run"); + return changed; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/package.html b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/package.html new file mode 100644 index 000000000..f3a4c5bd6 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/deploy/package.html @@ -0,0 +1,6 @@ + + + +SLC Deploy: deployment of software systems. + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionFlowGenerator.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionFlowGenerator.java new file mode 100644 index 000000000..dc55b40f9 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionFlowGenerator.java @@ -0,0 +1,74 @@ +/* + * 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.core.execution; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; + +public abstract class AbstractExecutionFlowGenerator implements + BeanFactoryPostProcessor, PriorityOrdered { + private final Log log = LogFactory.getLog(getClass()); + + protected abstract Map createExecutionFlowDefinitions( + ConfigurableListableBeanFactory beanFactory); + + public void postProcessBeanFactory( + ConfigurableListableBeanFactory beanFactory) throws BeansException { + if (!(beanFactory instanceof BeanDefinitionRegistry)) { + throw new SlcException("Can only work on " + + BeanDefinitionRegistry.class); + } + + Map definitions = createExecutionFlowDefinitions(beanFactory); + + for (String beanName : definitions.keySet()) { + if (log.isTraceEnabled()) + log.debug("Registering execution flow " + beanName); + ((BeanDefinitionRegistry) beanFactory).registerBeanDefinition( + beanName, definitions.get(beanName)); + } + } + + protected GenericBeanDefinition createDefaultFlowDefinition( + List executables) { + GenericBeanDefinition bd = new GenericBeanDefinition(); + bd.setBeanClass(DefaultExecutionFlow.class); + + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue("executables", executables); + + bd.setPropertyValues(mpv); + return bd; + } + + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java new file mode 100644 index 000000000..1d401c6b0 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java @@ -0,0 +1,162 @@ +/* + * 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.core.execution; + +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionFlowDescriptorConverter; +import org.argeo.slc.execution.ExecutionModulesManager; +import org.argeo.slc.execution.RealizedFlow; + +/** Provides the base feature of an execution module manager. */ +public abstract class AbstractExecutionModulesManager implements + ExecutionModulesManager { + private final static Log log = LogFactory + .getLog(AbstractExecutionModulesManager.class); + + // private List filteredNotifiers = Collections + // .synchronizedList(new ArrayList()); + + protected abstract ExecutionFlow findExecutionFlow(String moduleName, + String moduleVersion, String flowName); + + protected abstract ExecutionContext findExecutionContext(String moduleName, + String moduleVersion); + + protected abstract ExecutionFlowDescriptorConverter getExecutionFlowDescriptorConverter( + String moduleName, String moduleVersion); + + public void execute(RealizedFlow realizedFlow) { + if (log.isTraceEnabled()) + log.trace("Executing " + realizedFlow); + + String moduleName = realizedFlow.getModuleName(); + String moduleVersion = realizedFlow.getModuleVersion(); + + Map variablesToAdd = getExecutionFlowDescriptorConverter( + moduleName, moduleVersion).convertValues( + realizedFlow.getFlowDescriptor()); + ExecutionContext executionContext = findExecutionContext(moduleName, + moduleVersion); + for (String key : variablesToAdd.keySet()) + executionContext.setVariable(key, variablesToAdd.get(key)); + + ExecutionFlow flow = findExecutionFlow(moduleName, moduleVersion, + realizedFlow.getFlowDescriptor().getName()); + + // + // Actually runs the flow, IN THIS THREAD + // + executionContext.beforeFlow(flow); + try { + flow.run(); + } finally { + executionContext.afterFlow(flow); + } + // + // + // + } + + // public void dispatchUpdateStatus(ExecutionProcess process, + // String oldStatus, String newStatus) { + // // filtered notifiers + // for (Iterator it = filteredNotifiers.iterator(); it + // .hasNext();) { + // FilteredNotifier filteredNotifier = it.next(); + // if (filteredNotifier.receiveFrom(process)) + // filteredNotifier.getNotifier().updateStatus(process, oldStatus, + // newStatus); + // } + // + // } + + // public void dispatchAddSteps(ExecutionProcess process, + // List steps) { + // process.addSteps(steps); + // for (Iterator it = filteredNotifiers.iterator(); it + // .hasNext();) { + // FilteredNotifier filteredNotifier = it.next(); + // if (filteredNotifier.receiveFrom(process)) + // filteredNotifier.getNotifier().addSteps(process, steps); + // } + // } + + // public void registerProcessNotifier(ExecutionProcessNotifier notifier, + // Map properties) { + // filteredNotifiers.add(new FilteredNotifier(notifier, properties)); + // } + // + // public void unregisterProcessNotifier(ExecutionProcessNotifier notifier, + // Map properties) { + // filteredNotifiers.remove(notifier); + // } + + // protected class FilteredNotifier { + // private final ExecutionProcessNotifier notifier; + // private final String processId; + // + // public FilteredNotifier(ExecutionProcessNotifier notifier, + // Map properties) { + // super(); + // this.notifier = notifier; + // if (properties == null) + // properties = new HashMap(); + // if (properties.containsKey(SLC_PROCESS_ID)) + // processId = properties.get(SLC_PROCESS_ID); + // else + // processId = null; + // } + // + // /** + // * Whether event from this process should be received by this listener. + // */ + // public Boolean receiveFrom(ExecutionProcess process) { + // if (processId != null) + // if (process.getUuid().equals(processId)) + // return true; + // else + // return false; + // return true; + // } + // + // @Override + // public int hashCode() { + // return notifier.hashCode(); + // } + // + // @Override + // public boolean equals(Object obj) { + // if (obj instanceof FilteredNotifier) { + // FilteredNotifier fn = (FilteredNotifier) obj; + // return notifier.equals(fn.notifier); + // } else if (obj instanceof ExecutionProcessNotifier) { + // ExecutionProcessNotifier epn = (ExecutionProcessNotifier) obj; + // return notifier.equals(epn); + // } else + // return false; + // } + // + // public ExecutionProcessNotifier getNotifier() { + // return notifier; + // } + // + // } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionValue.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionValue.java new file mode 100644 index 000000000..131ffec75 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractExecutionValue.java @@ -0,0 +1,23 @@ +/* + * 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.core.execution; + +import java.io.Serializable; + +/** Value to be used by an execution */ +public abstract class AbstractExecutionValue implements Serializable { + private static final long serialVersionUID = 1558444746120706961L; +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractSpecAttribute.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractSpecAttribute.java new file mode 100644 index 000000000..109c0335e --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractSpecAttribute.java @@ -0,0 +1,90 @@ +/* + * 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.core.execution; + +import java.io.Serializable; + +import org.argeo.slc.execution.ExecutionSpecAttribute; + +/** Canonical implementation of the execution spec attribute booleans. */ +public abstract class AbstractSpecAttribute implements ExecutionSpecAttribute, + Serializable { + private static final long serialVersionUID = 6494963738891709440L; + private Boolean isImmutable = false; + private Boolean isConstant = false; + private Boolean isHidden = false; + + private String description; + + /** Has to be set at instantiation */ + public Boolean getIsImmutable() { + return isImmutable; + } + + public void setIsImmutable(Boolean isImmutable) { + this.isImmutable = isImmutable; + } + + /** Cannot be overridden at runtime */ + public Boolean getIsConstant() { + return isConstant; + } + + public void setIsConstant(Boolean isConstant) { + this.isConstant = isConstant; + } + + /** Should not be shown to the end user */ + public Boolean getIsHidden() { + return isHidden; + } + + public void setIsHidden(Boolean isHidden) { + this.isHidden = isHidden; + } + + /* + * DEPRECATED + */ + /** @deprecated use {@link #getIsImmutable()} instead */ + public Boolean getIsParameter() { + return isImmutable; + } + + /** @deprecated use {@link #getIsConstant()} instead */ + public Boolean getIsFrozen() { + return isConstant; + } + + /** @deprecated use {@link #setIsImmutable(Boolean)} instead */ + public void setIsParameter(Boolean isParameter) { + this.isImmutable = isParameter; + } + + /** @deprecated use {@link #setIsConstant(Boolean)} instead */ + public void setIsFrozen(Boolean isFrozen) { + this.isConstant = isFrozen; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractSpringExecutionModule.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractSpringExecutionModule.java new file mode 100644 index 000000000..b2252f6a2 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/AbstractSpringExecutionModule.java @@ -0,0 +1,132 @@ +/* + * 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.core.execution; + +import org.argeo.slc.execution.ExecutionModule; + +@Deprecated +public abstract class AbstractSpringExecutionModule implements ExecutionModule + { +/* + protected ApplicationContext applicationContext; + + protected ExecutionContext executionContext; + + protected ExecutionFlowDescriptorConverter descriptorConverter = new DefaultDescriptorConverter(); + + public ExecutionModuleDescriptor getDescriptor() { + ExecutionModuleDescriptor md = new ExecutionModuleDescriptor(); + md.setName(getName()); + md.setVersion(getVersion()); + + Map executionFlows = listFlows(); + for (String name : executionFlows.keySet()) { + ExecutionFlow executionFlow = executionFlows.get(name); + + Assert.notNull(executionFlow.getName()); + Assert.state(name.equals(executionFlow.getName())); + + ExecutionSpec executionSpec = executionFlow.getExecutionSpec(); + Assert.notNull(executionSpec); + Assert.notNull(executionSpec.getName()); + + Map values = new TreeMap(); + for (String key : executionSpec.getAttributes().keySet()) { + ExecutionSpecAttribute attribute = executionSpec + .getAttributes().get(key); + + if (executionFlow.isSetAsParameter(key)) { + Object value = executionFlow.getParameter(key); + if (attribute instanceof PrimitiveSpecAttribute) { + PrimitiveValue primitiveValue = new PrimitiveValue(); + primitiveValue + .setType(((PrimitiveSpecAttribute) attribute) + .getType()); + primitiveValue.setValue(value); + values.put(key, primitiveValue); + } else if (attribute instanceof RefSpecAttribute) { + RefValue refValue = new RefValue(); + if (value instanceof ScopedObject) { + refValue.setLabel("RUNTIME " + + value.getClass().getName()); + } else { + refValue.setLabel("STATIC " + + value.getClass().getName()); + } + values.put(key, refValue); + } else if (attribute instanceof ResourceSpecAttribute) { + PrimitiveValue primitiveValue = new PrimitiveValue(); + primitiveValue + .setType(((ResourceSpecAttribute) attribute) + .getType()); + primitiveValue.setValue(value); + values.put(key, primitiveValue); + } else { + throw new SlcException("Unkown spec attribute type " + + attribute.getClass()); + } + } + + } + + ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name, + values, executionSpec); + if (executionFlow.getPath() != null) + efd.setPath(executionFlow.getPath()); + + // Add execution spec if necessary + if (!md.getExecutionSpecs().contains(executionSpec)) + md.getExecutionSpecs().add(executionSpec); + + // Add execution flow + md.getExecutionFlows().add(efd); + } + + return md; + } + + protected Map listFlows() { + GenericBeanFactoryAccessor accessor = new GenericBeanFactoryAccessor( + applicationContext); + Map executionFlows = accessor + .getBeansOfType(ExecutionFlow.class); + return executionFlows; + } + + public void execute(ExecutionFlowDescriptor executionFlowDescriptor) { + if (descriptorConverter != null) + executionContext.addVariables(descriptorConverter + .convertValues(executionFlowDescriptor)); + ExecutionFlow flow = (ExecutionFlow) applicationContext.getBean( + executionFlowDescriptor.getName(), ExecutionFlow.class); + flow.run(); + } + + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + + public void setDescriptorConverter( + ExecutionFlowDescriptorConverter descriptorConverter) { + this.descriptorConverter = descriptorConverter; + }*/ + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultAgent.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultAgent.java new file mode 100644 index 000000000..c692820e7 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultAgent.java @@ -0,0 +1,221 @@ +/* + * 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.core.execution; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLDecoder; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.argeo.slc.DefaultNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionModuleDescriptor; +import org.argeo.slc.execution.ExecutionModulesManager; +import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.SlcAgent; + +/** Implements the base methods of an SLC agent. */ +public class DefaultAgent implements SlcAgent { + // private final static Log log = LogFactory.getLog(DefaultAgent.class); + /** UTF-8 charset for encoding. */ + private final static String UTF8 = "UTF-8"; + + private String agentUuid = null; + private ExecutionModulesManager modulesManager; + + private ThreadGroup processesThreadGroup; + private Map runningProcesses = Collections + .synchronizedMap(new HashMap()); + + private String defaultModulePrefix = null; + + /* + * LIFECYCLE + */ + /** Initialization */ + public void init() { + agentUuid = initAgentUuid(); + processesThreadGroup = new ThreadGroup("SLC Processes of Agent #" + + agentUuid); + } + + /** Clean up (needs to be called by overriding method) */ + public void destroy() { + } + + /** + * Called during initialization in order to determines the agent UUID. To be + * overridden. By default creates a new one per instance. + */ + protected String initAgentUuid() { + return UUID.randomUUID().toString(); + } + + /* + * SLC AGENT + */ + public void process(ExecutionProcess process) { + ProcessThread processThread = createProcessThread(processesThreadGroup, + modulesManager, process); + processThread.start(); + runningProcesses.put(process.getUuid(), processThread); + + // clean up old processes + Iterator it = runningProcesses.values().iterator(); + while (it.hasNext()) { + ProcessThread pThread = it.next(); + if (!pThread.isAlive()) + it.remove(); + } + } + + public String process(List uris) { + DefaultProcess process = new DefaultProcess(); + for (URI uri : uris) { + String[] path = uri.getPath().split("/"); + if (path.length < 3) + throw new SlcException("Badly formatted URI: " + uri); + NameVersion nameVersion = new DefaultNameVersion(path[1]); + StringBuilder flow = new StringBuilder(); + for (int i = 2; i < path.length; i++) + flow.append('/').append(path[i]); + + Map values = getQueryMap(uri.getQuery()); + // Get execution module descriptor + ExecutionModuleDescriptor emd = getExecutionModuleDescriptor( + nameVersion.getName(), nameVersion.getVersion()); + process.getRealizedFlows().add( + emd.asRealizedFlow(flow.toString(), values)); + } + process(process); + return process.getUuid(); + } + + public void kill(String processUuid) { + if (runningProcesses.containsKey(processUuid)) { + runningProcesses.get(processUuid).interrupt(); + } else { + // assume is finished + } + } + + public void waitFor(String processUuid, Long millis) { + if (runningProcesses.containsKey(processUuid)) { + try { + if (millis != null) + runningProcesses.get(processUuid).join(millis); + else + runningProcesses.get(processUuid).join(); + } catch (InterruptedException e) { + // silent + } + } else { + // assume is finished + } + } + + /** Creates the thread which will coordinate the execution for this agent. */ + protected ProcessThread createProcessThread( + ThreadGroup processesThreadGroup, + ExecutionModulesManager modulesManager, ExecutionProcess process) { + ProcessThread processThread = new ProcessThread(processesThreadGroup, + modulesManager, process); + return processThread; + } + + public ExecutionModuleDescriptor getExecutionModuleDescriptor( + String moduleName, String moduleVersion) { + // Get execution module descriptor + ExecutionModuleDescriptor emd; + try { + modulesManager + .start(new DefaultNameVersion(moduleName, moduleVersion)); + emd = modulesManager.getExecutionModuleDescriptor(moduleName, + moduleVersion); + } catch (SlcException e) { + if (defaultModulePrefix != null) { + moduleName = defaultModulePrefix + "." + moduleName; + modulesManager.start(new DefaultNameVersion(moduleName, + moduleVersion)); + emd = modulesManager.getExecutionModuleDescriptor(moduleName, + moduleVersion); + } else + throw e; + } + return emd; + } + + public List listExecutionModuleDescriptors() { + return modulesManager.listExecutionModules(); + } + + public boolean ping() { + return true; + } + + /* + * UTILITIES + */ + /** + * @param query + * can be null + */ + static Map getQueryMap(String query) { + Map map = new LinkedHashMap(); + if (query == null) + return map; + String[] params = query.split("&"); + for (String param : params) { + String[] arr = param.split("="); + String name = arr[0]; + Object value = arr.length > 1 ? param.split("=")[1] : Boolean.TRUE; + try { + map.put(URLDecoder.decode(name, UTF8), + URLDecoder.decode(value.toString(), UTF8)); + } catch (UnsupportedEncodingException e) { + throw new SlcException("Cannot decode '" + param + "'", e); + } + } + return map; + } + + /* + * BEAN + */ + public void setModulesManager(ExecutionModulesManager modulesManager) { + this.modulesManager = modulesManager; + } + + public void setDefaultModulePrefix(String defaultModulePrefix) { + this.defaultModulePrefix = defaultModulePrefix; + } + + public String getAgentUuid() { + return agentUuid; + } + + @Override + public String toString() { + return "Agent #" + getAgentUuid(); + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultAgentCli.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultAgentCli.java new file mode 100644 index 000000000..e02d50f2f --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultAgentCli.java @@ -0,0 +1,238 @@ +package org.argeo.slc.core.execution; + +import java.net.URI; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +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.execution.ExecutionFlowDescriptor; +import org.argeo.slc.execution.ExecutionModuleDescriptor; +import org.argeo.slc.execution.ExecutionSpec; +import org.argeo.slc.execution.ExecutionSpecAttribute; +import org.argeo.slc.execution.SlcAgent; +import org.argeo.slc.execution.SlcAgentCli; + +/** + * Authenticates thread and executes synchronously a command line execution. + * Reference implementation of args to URIs algorithm. + */ +public class DefaultAgentCli implements SlcAgentCli { + private final static Log log = LogFactory.getLog(DefaultAgentCli.class); + + private final static String UTF8 = "UTF-8"; + private SlcAgent agent; +// private AuthenticationManager authenticationManager; + + private Long timeout = 24 * 60 * 60 * 1000l; + + public String process(String[] args) { +// if (SecurityContextHolder.getContext().getAuthentication() == null) { +// OsAuthenticationToken oat = new OsAuthenticationToken(); +// Authentication authentication = authenticationManager +// .authenticate(oat); +// SecurityContextHolder.getContext() +// .setAuthentication(authentication); +// } + + if (args.length > 0 && args[0].equals("help")) { + StringBuilder buf = new StringBuilder(); + help(args, buf); + log.info("\n" + buf); + return buf.toString(); + } else { + List uris = asURIs(args); + String processUuid = agent.process(uris); + agent.waitFor(processUuid, timeout); + return processUuid; + } + } + + protected void help(String[] rawArgs, StringBuilder buf) { + String[] args = Arrays.copyOfRange(rawArgs, 1, rawArgs.length); + if (args.length == 0) {// modules + for (ExecutionModuleDescriptor emd : agent + .listExecutionModuleDescriptors()) { + appendModule(emd, buf); + } + } else if (args.length == 1 && !args[0].contains("/")) {// single module + NameVersion nameVersion = new DefaultNameVersion(args[0]); + ExecutionModuleDescriptor emd = agent.getExecutionModuleDescriptor( + nameVersion.getName(), nameVersion.getVersion()); + appendModule(emd, buf); + + // flows + for (ExecutionFlowDescriptor efd : emd.getExecutionFlows()) { + buf.append(" ").append(efd.getName()); + if (efd.getDescription() != null + && !efd.getDescription().trim().equals("")) + buf.append(" : ").append(" ").append(efd.getDescription()); + buf.append('\n'); + } + return; + } else { + List uris = asURIs(args); + for (URI uri : uris) { + appendUriHelp(uri, buf); + } + } + } + + protected void appendUriHelp(URI uri, StringBuilder buf) { + String[] path = uri.getPath().split("/"); + NameVersion nameVersion = new DefaultNameVersion(path[1]); + ExecutionModuleDescriptor emd = agent.getExecutionModuleDescriptor( + nameVersion.getName(), nameVersion.getVersion()); + + StringBuilder flow = new StringBuilder(); + for (int i = 2; i < path.length; i++) + flow.append('/').append(path[i]); + String flowPath = flow.toString(); + ExecutionFlowDescriptor efd = findExecutionFlowDescriptor(emd, flowPath); + if (efd == null) + throw new SlcException("Flow " + uri + " not found"); + + appendModule(emd, buf); + + buf.append(" ").append(efd.getName()); + if (efd.getDescription() != null + && !efd.getDescription().trim().equals("")) + buf.append(" : ").append(" ").append(efd.getDescription()); + buf.append('\n'); + Map values = DefaultAgent.getQueryMap(uri.getQuery()); + ExecutionSpec spec = efd.getExecutionSpec(); + for (String attrKey : spec.getAttributes().keySet()) { + ExecutionSpecAttribute esa = spec.getAttributes().get(attrKey); + buf.append(" --").append(attrKey); + if (values.containsKey(attrKey)) + buf.append(" ").append(values.get(attrKey)); + if (esa.getValue() != null) + buf.append(" (").append(esa.getValue()).append(')'); + buf.append('\n'); + } + } + + private void appendModule(ExecutionModuleDescriptor emd, StringBuilder buf) { + buf.append("# ").append(emd.getName()); + if (emd.getDescription() != null + && !emd.getDescription().trim().equals("")) + buf.append(" : ").append(emd.getDescription()); + if (emd.getVersion() != null) + buf.append(" (v").append(emd.getVersion()).append(")"); + buf.append('\n'); + } + + public static List asURIs(String[] args) { + try { + List uris = new ArrayList(); + List leftOvers = new ArrayList(); + + Boolean hasArgs = false; + String currKey = null; + StringBuilder currUri = null; + Iterator argIt = Arrays.asList(args).iterator(); + while (argIt.hasNext()) { + String arg = argIt.next(); + if (!arg.startsWith("-")) { + if (currKey != null) {// value + currUri.append(URLEncoder.encode(arg, UTF8)); + currKey = null; + } else { // module + if (currUri != null) { + uris.add(new URI(currUri.toString())); + } + currUri = new StringBuilder("flow:"); + + String currModule = arg; + currUri.append('/').append(currModule); + if (!arg.contains("/")) { + // flow path not in arg go to next arg + if (!argIt.hasNext()) + throw new SlcException("No flow found"); + String currFlow = argIt.next(); + if (!currFlow.startsWith("/")) + currFlow = "/" + currFlow; + currUri.append(currFlow); + } + } + } else { + if (currUri == null) {// first args + leftOvers.add(arg); + } else { + String key; + if (arg.startsWith("--")) + key = arg.substring(2); + else if (arg.startsWith("-")) + key = arg.substring(1); + else { + throw new SlcException("Cannot intepret key: " + + arg); + } + + if (!hasArgs) { + currUri.append('?'); + hasArgs = true; + } else { + currUri.append('&'); + } + + // deal with boolean keys + if (currKey != null) {// value + currUri.append(URLEncoder.encode("true", UTF8)); + currKey = null; + } + + currKey = key; + currUri.append(URLEncoder.encode(key, UTF8)) + .append('='); + } + } + } + if (currUri != null) + uris.add(new URI(currUri.toString())); + return uris; + } catch (Exception e) { + throw new SlcException("Cannot convert " + Arrays.toString(args) + + " to flow URI", e); + } + } + + private ExecutionFlowDescriptor findExecutionFlowDescriptor( + ExecutionModuleDescriptor emd, String flowPath) { + ExecutionFlowDescriptor flowDescriptor = null; + for (ExecutionFlowDescriptor efd : emd.getExecutionFlows()) { + String name = efd.getName(); + // normalize name as flow path + if (!name.startsWith("/")) + name = "/" + name; + if (name.endsWith("/")) + name = name.substring(0, name.length() - 1); + if (name.equals(flowPath)) { + flowDescriptor = efd; + break; + } + } + return flowDescriptor; + } + + public void setAgent(SlcAgent agent) { + this.agent = agent; + } + +// public void setAuthenticationManager( +// AuthenticationManager authenticationManager) { +// this.authenticationManager = authenticationManager; +// } + + public void setTimeout(Long timeout) { + this.timeout = timeout; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionFlow.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionFlow.java new file mode 100644 index 000000000..bebde7512 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionFlow.java @@ -0,0 +1,278 @@ +/* + * 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.core.execution; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionSpec; +import org.argeo.slc.execution.ExecutionSpecAttribute; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.validation.MapBindingResult; + +/** Default implementation of an execution flow. */ +public class DefaultExecutionFlow implements ExecutionFlow, InitializingBean, + BeanNameAware { + private final static Log log = LogFactory + .getLog(DefaultExecutionFlow.class); + + private final ExecutionSpec executionSpec; + private String name = null; + private Map parameters = new HashMap(); + private List executables = new ArrayList(); + + private String path; + + private Boolean failOnError = true; + + // Only needed if stacked execution flows are used + private ExecutionContext executionContext = null; + + public DefaultExecutionFlow() { + this.executionSpec = new DefaultExecutionSpec(); + } + + public DefaultExecutionFlow(ExecutionSpec executionSpec) { + this.executionSpec = executionSpec; + } + + public DefaultExecutionFlow(ExecutionSpec executionSpec, + Map parameters) { + // be sure to have an execution spec + this.executionSpec = (executionSpec == null) ? new DefaultExecutionSpec() + : executionSpec; + + // only parameters contained in the executionSpec can be set + for (String parameter : parameters.keySet()) { + if (!executionSpec.getAttributes().containsKey(parameter)) { + throw new SlcException("Parameter " + parameter + + " is not defined in the ExecutionSpec"); + } + } + + // set the parameters + this.parameters.putAll(parameters); + + // check that all the required parameters are defined + MapBindingResult errors = new MapBindingResult(parameters, "execution#" + + getName()); + for (String key : executionSpec.getAttributes().keySet()) { + ExecutionSpecAttribute attr = executionSpec.getAttributes() + .get(key); + + if (attr.getIsImmutable() && !isSetAsParameter(key)) { + errors.rejectValue(key, "Immutable but not set"); + break; + } + + if (attr.getIsConstant() && !isSetAsParameter(key)) { + errors.rejectValue(key, "Constant but not set as parameter"); + break; + } + + if (attr.getIsHidden() && !isSetAsParameter(key)) { + errors.rejectValue(key, "Hidden but not set as parameter"); + break; + } + } + + if (errors.hasErrors()) + throw new SlcException("Could not prepare execution flow: " + + errors.toString()); + + } + + public void run() { + try { + for (Runnable executable : executables) { + if (Thread.interrupted()) { + log.error("Flow '" + getName() + "' killed before '" + + executable + "'"); + Thread.currentThread().interrupt(); + return; + // throw new ThreadDeath(); + } + this.doExecuteRunnable(executable); + } + } catch (RuntimeException e) { + if (Thread.interrupted()) { + log.error("Flow '" + getName() + + "' killed while receiving an unrelated exception", e); + Thread.currentThread().interrupt(); + return; + // throw new ThreadDeath(); + } + if (failOnError) + throw e; + else { + log.error("Execution flow failed," + + " but process did not fail" + + " because failOnError property" + + " is set to false: " + e); + if (log.isTraceEnabled()) + e.printStackTrace(); + } + } + } + + /** + * List sub-runnables that would be executed if run() method would be + * called. + */ + public Iterator runnables() { + return executables.iterator(); + } + + /** + * If there is one and only one runnable wrapped return it, throw an + * exeception otherwise. + */ + public Runnable getRunnable() { + if (executables.size() == 1) + return executables.get(0); + else + throw new SlcException("There are " + executables.size() + + " runnables in flow " + getName()); + } + + public void doExecuteRunnable(Runnable runnable) { + try { + if (executionContext != null) + if (runnable instanceof ExecutionFlow) + executionContext.beforeFlow((ExecutionFlow) runnable); + runnable.run(); + } finally { + if (executionContext != null) + if (runnable instanceof ExecutionFlow) + executionContext.afterFlow((ExecutionFlow) runnable); + } + } + + public void afterPropertiesSet() throws Exception { + if (path == null) { + if (name.charAt(0) == '/') { + path = name.substring(0, name.lastIndexOf('/')); + } + } + + if (path != null) { + for (Runnable executable : executables) { + if (executable instanceof DefaultExecutionFlow) { + // so we don't need to have DefaultExecutionFlow + // implementing StructureAware + // FIXME: probably has side effects + DefaultExecutionFlow flow = (DefaultExecutionFlow) executable; + String newPath = path + '/' + flow.getName(); + flow.setPath(newPath); + log.warn(newPath + " was forcibly set on " + flow); + } + } + } + } + + public void setBeanName(String name) { + this.name = name; + } + + public void setExecutables(List executables) { + this.executables = executables; + } + + public void setParameters(Map attributes) { + this.parameters = attributes; + } + + public String getName() { + return name; + } + + public ExecutionSpec getExecutionSpec() { + return executionSpec; + } + + public Object getParameter(String parameterName) { + // Verify that there is a spec attribute + ExecutionSpecAttribute specAttr = null; + if (executionSpec.getAttributes().containsKey(parameterName)) { + specAttr = executionSpec.getAttributes().get(parameterName); + } else { + throw new SlcException("Key " + parameterName + + " is not defined in the specifications of " + toString()); + } + + if (parameters.containsKey(parameterName)) { + Object paramValue = parameters.get(parameterName); + return paramValue; + } else { + if (specAttr.getValue() != null) { + return specAttr.getValue(); + } + } + throw new SlcException("Key " + parameterName + + " is not set as parameter in " + toString()); + } + + public Boolean isSetAsParameter(String key) { + return parameters.containsKey(key) + || (executionSpec.getAttributes().containsKey(key) && executionSpec + .getAttributes().get(key).getValue() != null); + } + + @Override + public String toString() { + return new StringBuffer("Execution flow ").append(name).toString(); + } + + @Override + public boolean equals(Object obj) { + return ((ExecutionFlow) obj).getName().equals(name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Boolean getFailOnError() { + return failOnError; + } + + public void setFailOnError(Boolean failOnError) { + this.failOnError = failOnError; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java new file mode 100644 index 000000000..beac9175a --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionFlowDescriptorConverter.java @@ -0,0 +1,359 @@ +/* + * 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.core.execution; + +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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.ExecutionSpec; +import org.argeo.slc.execution.ExecutionSpecAttribute; +import org.springframework.aop.scope.ScopedObject; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.util.StringUtils; + +/** + * Performs conversion in both direction between data exchanged with the agent + * and the data in the application context. + */ +public class DefaultExecutionFlowDescriptorConverter implements + ExecutionFlowDescriptorConverter, ApplicationContextAware { + public final static String REF_VALUE_TYPE_BEAN_NAME = "beanName"; + + /** Workaround for https://www.spartadn.com/bugzilla/show_bug.cgi?id=206 */ + private final static String REF_VALUE_INTERNAL = "[internal]"; + + private final static Log log = LogFactory + .getLog(DefaultExecutionFlowDescriptorConverter.class); + + private ApplicationContext applicationContext; + + @SuppressWarnings("unused") + public Map convertValues( + ExecutionFlowDescriptor executionFlowDescriptor) { + Map values = executionFlowDescriptor.getValues(); + Map convertedValues = new HashMap(); + ExecutionSpec executionSpec = executionFlowDescriptor + .getExecutionSpec(); + + if (executionSpec == null && log.isTraceEnabled()) + log.warn("Execution spec is null for " + executionFlowDescriptor); + + if (values != null && executionSpec != null) { + values: for (String key : values.keySet()) { + ExecutionSpecAttribute attribute = executionSpec + .getAttributes().get(key); + + if (attribute == null) + throw new FlowConfigurationException( + "No spec attribute defined for '" + key + "'"); + + if (attribute.getIsConstant()) + continue values; + + Object value = values.get(key); + if (value instanceof PrimitiveValue) { + PrimitiveValue primitiveValue = (PrimitiveValue) value; + // TODO: check class <=> type + convertedValues.put(key, primitiveValue.getValue()); + } else if (value instanceof RefValue) { + RefValue refValue = (RefValue) value; + String type = refValue.getType(); + if (REF_VALUE_TYPE_BEAN_NAME.equals(type)) { + // FIXME: UI should send all information about spec + // - targetClass + // - name + // String executionSpecName = executionSpec.getName(); + // ExecutionSpec localSpec = (ExecutionSpec) + // applicationContext + // .getBean(executionSpecName); + // RefSpecAttribute localAttr = (RefSpecAttribute) + // localSpec + // .getAttributes().get(key); + // Class targetClass = localAttr.getTargetClass(); + // + // String primitiveType = PrimitiveUtils + // .classAsType(targetClass); + String primitiveType = null; + if (primitiveType != null) { + // not active + String ref = refValue.getRef(); + Object obj = PrimitiveUtils.convert(primitiveType, + ref); + convertedValues.put(key, obj); + } else { + String ref = refValue.getRef(); + if (ref != null && !ref.equals(REF_VALUE_INTERNAL)) { + Object obj = null; + if (applicationContext.containsBean(ref)) { + obj = applicationContext.getBean(ref); + } else { + // FIXME: hack in order to pass primitive + obj = ref; + } + convertedValues.put(key, obj); + } else { + log.warn("Cannot interpret " + refValue); + } + } + } else if (PrimitiveUtils.typeAsClass(type) != null) { + String ref = refValue.getRef(); + Object obj = PrimitiveUtils.convert(type, ref); + convertedValues.put(key, obj); + } else { + throw new FlowConfigurationException( + "Ref value type not supported: " + + refValue.getType()); + } + } else { + // default is to take the value as is + convertedValues.put(key, value); + } + } + } + return convertedValues; + } + + public void addFlowsToDescriptor(ExecutionModuleDescriptor md, + Map executionFlows) { + SortedSet set = new TreeSet( + new ExecutionFlowDescriptorComparator()); + for (String name : executionFlows.keySet()) { + ExecutionFlow executionFlow = executionFlows.get(name); + + ExecutionFlowDescriptor efd = getExecutionFlowDescriptor(executionFlow); + ExecutionSpec executionSpec = efd.getExecutionSpec(); + + // Add execution spec if necessary + if (!md.getExecutionSpecs().contains(executionSpec)) + md.getExecutionSpecs().add(executionSpec); + + // Add execution flow + set.add(efd); + // md.getExecutionFlows().add(efd); + } + md.getExecutionFlows().addAll(set); + } + + public ExecutionFlowDescriptor getExecutionFlowDescriptor( + ExecutionFlow executionFlow) { + if (executionFlow.getName() == null) + throw new FlowConfigurationException("Flow name is null: " + + executionFlow); + String name = executionFlow.getName(); + + ExecutionSpec executionSpec = executionFlow.getExecutionSpec(); + if (executionSpec == null) + throw new FlowConfigurationException("Execution spec is null: " + + executionFlow); + if (executionSpec.getName() == null) + throw new FlowConfigurationException( + "Execution spec name is null: " + executionSpec); + + Map values = new TreeMap(); + for (String key : executionSpec.getAttributes().keySet()) { + ExecutionSpecAttribute attribute = executionSpec.getAttributes() + .get(key); + + if (attribute instanceof PrimitiveSpecAttribute) { + if (executionFlow.isSetAsParameter(key)) { + Object value = executionFlow.getParameter(key); + PrimitiveValue primitiveValue = new PrimitiveValue(); + primitiveValue.setType(((PrimitiveSpecAttribute) attribute) + .getType()); + primitiveValue.setValue(value); + values.put(key, primitiveValue); + } else { + // no need to add a primitive value if it is not set, + // all necessary information is in the spec + } + } else if (attribute instanceof RefSpecAttribute) { + if (attribute.getIsConstant()) { + values.put(key, new RefValue(REF_VALUE_INTERNAL)); + } else + values.put( + key, + buildRefValue((RefSpecAttribute) attribute, + executionFlow, key)); + } else { + throw new FlowConfigurationException( + "Unkown spec attribute type " + attribute.getClass()); + } + + } + + ExecutionFlowDescriptor efd = new ExecutionFlowDescriptor(name, null, + values, executionSpec); + // Takes description from spring + BeanFactory bf = getBeanFactory(); + if (bf != null) { + BeanDefinition bd = getBeanFactory().getBeanDefinition(name); + efd.setDescription(bd.getDescription()); + } + return efd; + } + + protected RefValue buildRefValue(RefSpecAttribute rsa, + ExecutionFlow executionFlow, String key) { + RefValue refValue = new RefValue(); + // FIXME: UI should be able to deal with other types + refValue.setType(REF_VALUE_TYPE_BEAN_NAME); + Class targetClass = rsa.getTargetClass(); + String primitiveType = PrimitiveUtils.classAsType(targetClass); + if (primitiveType != null) { + if (executionFlow.isSetAsParameter(key)) { + Object value = executionFlow.getParameter(key); + refValue.setRef(value.toString()); + } + refValue.setType(primitiveType); + return refValue; + } else { + + if (executionFlow.isSetAsParameter(key)) { + String ref = null; + Object value = executionFlow.getParameter(key); + if (applicationContext == null) { + log.warn("No application context declared, cannot scan ref value."); + ref = value.toString(); + } else { + + // look for a ref to the value + Map beans = getBeanFactory() + .getBeansOfType(targetClass, false, false); + // TODO: also check scoped beans + beans: for (String beanName : beans.keySet()) { + Object obj = beans.get(beanName); + if (value instanceof ScopedObject) { + // don't call methods of the target of the scope + if (obj instanceof ScopedObject) + if (value == obj) { + ref = beanName; + break beans; + } + } else { + if (obj.equals(value)) { + ref = beanName; + break beans; + } + } + } + } + if (ref == null) { + if (log.isTraceEnabled()) + log.trace("Cannot define reference for ref spec attribute " + + key + + " in " + + executionFlow + + " (" + + rsa + + ")." + + " If it is an inner bean consider put it frozen."); + ref = REF_VALUE_INTERNAL; + } else { + if (log.isTraceEnabled()) + log.trace(ref + + " is the reference for ref spec attribute " + + key + " in " + executionFlow + " (" + rsa + + ")"); + } + refValue.setRef(ref); + } + return refValue; + } + } + + /** @return can be null */ + private ConfigurableListableBeanFactory getBeanFactory() { + if (applicationContext == null) + return null; + return ((ConfigurableApplicationContext) applicationContext) + .getBeanFactory(); + } + + /** Must be use within the execution application context */ + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + private static class ExecutionFlowDescriptorComparator implements + Comparator { + @SuppressWarnings("deprecation") + public int compare(ExecutionFlowDescriptor o1, + ExecutionFlowDescriptor o2) { + // TODO: write unit tests for this + + String name1 = o1.getName(); + String name2 = o2.getName(); + + String path1 = o1.getPath(); + String path2 = o2.getPath(); + + // Check whether name include path + int lastIndex1 = name1.lastIndexOf('/'); + // log.debug(name1+", "+lastIndex1); + if (!StringUtils.hasText(path1) && lastIndex1 >= 0) { + path1 = name1.substring(0, lastIndex1); + name1 = name1.substring(lastIndex1 + 1); + } + + int lastIndex2 = name2.lastIndexOf('/'); + if (!StringUtils.hasText(path2) && lastIndex2 >= 0) { + path2 = name2.substring(0, lastIndex2); + name2 = name2.substring(lastIndex2 + 1); + } + + // Perform the actual comparison + if (StringUtils.hasText(path1) && StringUtils.hasText(path2)) { + if (path1.equals(path2)) + return name1.compareTo(name2); + else if (path1.startsWith(path2)) + return -1; + else if (path2.startsWith(path1)) + return 1; + else + return path1.compareTo(path2); + } else if (!StringUtils.hasText(path1) + && StringUtils.hasText(path2)) { + return 1; + } else if (StringUtils.hasText(path1) + && !StringUtils.hasText(path2)) { + return -1; + } else if (!StringUtils.hasText(path1) + && !StringUtils.hasText(path2)) { + return name1.compareTo(name2); + } else { + return 0; + } + } + + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionSpec.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionSpec.java new file mode 100644 index 000000000..2bce12577 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionSpec.java @@ -0,0 +1,149 @@ +/* + * 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.core.execution; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.execution.ExecutionSpec; +import org.argeo.slc.execution.ExecutionSpecAttribute; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ConfigurableApplicationContext; + +/** Spring based implementation of execution specifications. */ +public class DefaultExecutionSpec implements ExecutionSpec, BeanNameAware, + ApplicationContextAware, InitializingBean, Serializable { + private static final long serialVersionUID = 5159882223926926539L; + private final static Log log = LogFactory + .getLog(DefaultExecutionSpec.class); + private transient ApplicationContext applicationContext; + + private String description; + private Map attributes = new HashMap(); + + private String name = INTERNAL_NAME; + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + + public void setBeanName(String name) { + this.name = name; + } + + /** + * The Spring bean name (only relevant for specs declared has high-level + * beans) + */ + public String getName() { + return name; + } + + public boolean equals(Object obj) { + return ((ExecutionSpec) obj).getName().equals(name); + } + + /** + * The Spring bean description (only relevant for specs declared has + * high-level beans) + */ + public String getDescription() { + return description; + } + + private ConfigurableListableBeanFactory getBeanFactory() { + return ((ConfigurableApplicationContext) applicationContext) + .getBeanFactory(); + } + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + public void afterPropertiesSet() throws Exception { + if (description == null) { + try { + description = getBeanFactory().getBeanDefinition(name) + .getDescription(); + } catch (NoSuchBeanDefinitionException e) { + // silent + } + } + + for (String key : attributes.keySet()) { + ExecutionSpecAttribute attr = attributes.get(key); + if (attr instanceof RefSpecAttribute) { + RefSpecAttribute rsa = (RefSpecAttribute) attr; + if (rsa.getChoices() == null) { + List choices = buildRefValueChoices(rsa); + rsa.setChoices(choices); + } + if (log.isTraceEnabled()) + log.debug("Spec attr " + key + " has " + + rsa.getChoices().size() + " choices"); + } + } + } + + /** + * Generates a list of ref value choices based on the bean available in the + * application ocntext. + */ + protected List buildRefValueChoices(RefSpecAttribute rsa) { + List choices = new ArrayList(); + if (applicationContext == null) { + log.warn("No application context declared," + + " cannot scan ref value choices."); + return choices; + } + + beanNames: for (String beanName : getBeanFactory().getBeanNamesForType( + rsa.getTargetClass(), true, false)) { + + // Since Spring 3, systemProperties is implicitly defined but has no + // bean definition + if (beanName.equals("systemProperties")) + continue beanNames; + + BeanDefinition bd = getBeanFactory().getBeanDefinition(beanName); + RefValueChoice choice = new RefValueChoice(); + choice.setName(beanName); + choice.setDescription(bd.getDescription()); + if (log.isTraceEnabled()) + log.debug("Found choice " + beanName + " for " + rsa); + + choices.add(choice); + + } + return choices; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionStack.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionStack.java new file mode 100644 index 000000000..d1d06c698 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultExecutionStack.java @@ -0,0 +1,144 @@ +/* + * 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.core.execution; + +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import java.util.UUID; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionSpecAttribute; +import org.argeo.slc.execution.ExecutionStack; + +/** Canonical implementation of an execution stack. */ +public class DefaultExecutionStack implements ExecutionStack { + + private final static Log log = LogFactory + .getLog(DefaultExecutionStack.class); + + private final Stack stack = new Stack(); + + public synchronized void enterFlow(ExecutionFlow executionFlow) { + ExecutionFlowRuntime runtime = new ExecutionFlowRuntime(executionFlow); + stack.push(runtime); + + Map specAttrs = executionFlow + .getExecutionSpec().getAttributes(); + for (String key : specAttrs.keySet()) { + if (executionFlow.isSetAsParameter(key)) { + runtime.getLocalVariables().put(key, + executionFlow.getParameter(key)); + } + } + } + + public synchronized String getCurrentStackLevelUuid() { + return stack.peek().getUuid(); + } + + public synchronized Integer getStackSize() { + return stack.size(); + } + + /** + * Looks for a set variable in the stack, starting at the upper flows + * + * @return the variable or null if not found + */ + public synchronized Object findLocalVariable(String key) { + Object obj = null; + for (int i = 0; i < stack.size(); i++) { + if (stack.get(i).getLocalVariables().containsKey(key)) { + obj = stack.get(i).getLocalVariables().get(key); + break; + } + } + return obj; + } + + public synchronized void leaveFlow(ExecutionFlow executionFlow) { + ExecutionFlowRuntime leftEf = stack.pop(); + + if (!leftEf.getExecutionFlow().getName() + .equals(executionFlow.getName())) + throw new SlcException("Asked to leave " + executionFlow + + " but last is " + leftEf); + + leftEf.getScopedObjects().clear(); + leftEf.getLocalVariables().clear(); + } + + public synchronized void addScopedObject(String name, Object obj) { + ExecutionFlowRuntime runtime = stack.peek(); + // TODO: check that the object is not set yet ? + if (log.isDebugEnabled()) { + Object existing = findScopedObject(name); + if (existing != null) + log.warn("Scoped object " + name + " of type " + obj.getClass() + + " already registered in " + runtime); + } + runtime.getScopedObjects().put(name, obj); + } + + /** @return null if not found */ + public synchronized Object findScopedObject(String name) { + Object obj = null; + for (int i = stack.size() - 1; i >= 0; i--) { + if (stack.get(i).getScopedObjects().containsKey(name)) { + obj = stack.get(i).getScopedObjects().get(name); + break; + } + } + return obj; + } + + protected static class ExecutionFlowRuntime { + private final ExecutionFlow executionFlow; + private final Map scopedObjects = new HashMap(); + private final Map localVariables = new HashMap(); + private final String uuid = UUID.randomUUID().toString(); + + public ExecutionFlowRuntime(ExecutionFlow executionFlow) { + this.executionFlow = executionFlow; + } + + public ExecutionFlow getExecutionFlow() { + return executionFlow; + } + + public Map getScopedObjects() { + return scopedObjects; + } + + public String getUuid() { + return uuid; + } + + public Map getLocalVariables() { + return localVariables; + } + + @Override + public String toString() { + return "Stack Level #" + uuid; + } + + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultProcess.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultProcess.java new file mode 100644 index 000000000..30211800f --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/DefaultProcess.java @@ -0,0 +1,55 @@ +package org.argeo.slc.core.execution; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.ExecutionStep; +import org.argeo.slc.execution.RealizedFlow; + +/** Canonical implementation of an {@link ExecutionProcess} as a bean. */ +public class DefaultProcess implements ExecutionProcess { + private String uuid = UUID.randomUUID().toString(); + private String status = ExecutionProcess.NEW; + + private List steps = new ArrayList(); + private List realizedFlows = new ArrayList(); + + public String getUuid() { + return uuid; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public void addSteps(List steps) { + steps.addAll(steps); + } + + public List getRealizedFlows() { + return realizedFlows; + } + + public List getSteps() { + return steps; + } + + public void setSteps(List steps) { + this.steps = steps; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public void setRealizedFlows(List realizedFlows) { + this.realizedFlows = realizedFlows; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionAspect.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionAspect.java new file mode 100644 index 000000000..b50b78f51 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionAspect.java @@ -0,0 +1,113 @@ +/* + * 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.core.execution; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionStack; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; + +@Aspect +/** Aspect intercepting calls on execution flows and contexts. */ +public class ExecutionAspect { + private final static Log log = LogFactory.getLog(ExecutionAspect.class); + + private ExecutionStack executionStack; + private ExecutionContext executionContext; + + @Around("flowExecution()") + public void aroundFlow(ProceedingJoinPoint pjp) throws Throwable { + // IMPORTANT: Make sure that the execution context is called before the + // execution stack + executionContext.getUuid(); + + ExecutionFlow executionFlow = (ExecutionFlow) pjp.getTarget(); + executionStack.enterFlow(executionFlow); + executionContext.setVariable(ExecutionContext.VAR_FLOW_ID, + executionStack.getCurrentStackLevelUuid()); + executionContext.setVariable(ExecutionContext.VAR_FLOW_NAME, + executionFlow.getName()); + + logStackEvent("=> ", executionFlow); + try { + // Actually execute the flow + pjp.proceed(); + } finally { + logStackEvent("<= ", executionFlow); + executionStack.leaveFlow(executionFlow); + } + } + + @Around("getVariable()") + public Object aroundGetVariable(ProceedingJoinPoint pjp) throws Throwable { + Object obj = pjp.proceed(); + // if the variable was not found, look in the stack starting at the + // upper flows + if (obj == null) { + String key = pjp.getArgs()[0].toString(); + obj = executionStack.findLocalVariable(key); + } + return obj; + } + + @Pointcut("execution(void org.argeo.slc.execution.ExecutionFlow.run())") + public void flowExecution() { + } + + @Pointcut("execution(* org.argeo.slc.execution.ExecutionContext.getVariable(..))") + public void getVariable() { + } + + public void setExecutionStack(ExecutionStack executionStack) { + this.executionStack = executionStack; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + + protected void logStackEvent(String symbol, ExecutionFlow executionFlow) { + Integer stackSize = executionStack.getStackSize(); + if (log.isTraceEnabled()) + log.debug(depthSpaces(stackSize) + symbol + executionFlow + " #" + + executionStack.getCurrentStackLevelUuid() + ", depth=" + + stackSize); + if (log.isDebugEnabled()) + log.debug(depthSpaces(stackSize) + symbol + executionFlow); + } + + protected void logRunnableExecution(ExecutionFlow executionFlow, + Runnable runnable) { + Integer stackSize = executionStack.getStackSize(); + if (log.isDebugEnabled()) + log.debug(depthSpaces(stackSize + 1) + + runnable.getClass().getSimpleName() + " in " + + executionFlow); + } + + private String depthSpaces(int depth) { + StringBuffer buf = new StringBuffer(depth * 2); + for (int i = 0; i < depth; i++) + buf.append(" "); + return buf.toString(); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java new file mode 100644 index 000000000..84c932ee2 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionParameterPostProcessor.java @@ -0,0 +1,307 @@ +/* + * 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.core.execution; + +import java.beans.PropertyDescriptor; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.support.ManagedSet; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * Spring post processor which ensures that execution parameters are properly + * set. It is used at two levels: first during instantiation for instantiation + * parameters which allow to implement templates, then at runtime in order to + * interpret @{} placeholders when object of scope execution are instantiated. + */ +public class ExecutionParameterPostProcessor extends + InstantiationAwareBeanPostProcessorAdapter { + + private final static Log log = LogFactory + .getLog(ExecutionParameterPostProcessor.class); + + private ExecutionContext executionContext; + private InstantiationManager instantiationManager; + + private String placeholderPrefix = "@{"; + private String placeholderSuffix = "}"; + private String nullValue; + + @Override + public PropertyValues postProcessPropertyValues(PropertyValues pvs, + PropertyDescriptor[] pds, Object bean, String beanName) + throws BeansException { + + // TODO: resolve at execution only if scope is execution + // TODO: deal with placeholders in RuntimeBeanReference and + // RuntimeBeanNameReference + + MutablePropertyValues newPvs = new MutablePropertyValues(); + + boolean changesOccured = false; + + for (PropertyValue pv : pvs.getPropertyValues()) { + Object convertedValue = resolveValue(beanName, bean, pv.getValue()); + newPvs.addPropertyValue(new PropertyValue(pv, convertedValue)); + if (convertedValue != pv.getValue()) { + changesOccured = true; + } + } + + return changesOccured ? newPvs : pvs; + } + + @Override + public boolean postProcessAfterInstantiation(Object bean, String beanName) + throws BeansException { + if (bean instanceof ExecutionFlow) + instantiationManager.flowInitializationStarted( + (ExecutionFlow) bean, beanName); + return true; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof ExecutionFlow) + instantiationManager.flowInitializationFinished( + (ExecutionFlow) bean, beanName); + return bean; + } + + protected String resolvePlaceholder(Object bean, String placeholder) { + if (instantiationManager.isInFlowInitialization()) + return instantiationManager.getInitializingFlowParameter( + placeholder).toString(); + + else {// execution + // next call fail if no execution context available + Object obj = executionContext.getVariable(placeholder); + if (obj != null) { + return obj.toString(); + } + } + + return null; + } + + public Object resolveValue(String beanName, Object bean, Object value) { + if (value instanceof TypedStringValue) { + TypedStringValue tsv = (TypedStringValue) value; + String originalValue = tsv.getValue(); + + String convertedValue = resolveString(beanName, bean, originalValue); + if (convertedValue == null) + return null; + return convertedValue.equals(originalValue) ? value + : new TypedStringValue(convertedValue); + } else if (value instanceof String) { + String originalValue = value.toString(); + String convertedValue = resolveString(beanName, bean, originalValue); + if (convertedValue == null) + return null; + return convertedValue.equals(originalValue) ? value + : convertedValue; + } else if (value instanceof ManagedMap) { + Map mapVal = (Map) value; + + Map newContent = new ManagedMap(); + boolean entriesModified = false; + for (Iterator it = mapVal.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + Object key = entry.getKey(); + int keyHash = (key != null ? key.hashCode() : 0); + Object newKey = resolveValue(beanName, bean, key); + int newKeyHash = (newKey != null ? newKey.hashCode() : 0); + Object val = entry.getValue(); + Object newVal = resolveValue(beanName, bean, val); + newContent.put(newKey, newVal); + entriesModified = entriesModified + || (newVal != val || newKey != key || newKeyHash != keyHash); + } + + return entriesModified ? newContent : value; + } else if (value instanceof ManagedList) { + List listVal = (List) value; + List newContent = new ManagedList(); + boolean valueModified = false; + + for (int i = 0; i < listVal.size(); i++) { + Object elem = listVal.get(i); + Object newVal = resolveValue(beanName, bean, elem); + newContent.add(newVal); + if (!ObjectUtils.nullSafeEquals(newVal, elem)) { + valueModified = true; + } + } + return valueModified ? newContent : value; + } else if (value instanceof ManagedSet) { + Set setVal = (Set) value; + Set newContent = new ManagedSet(); + boolean entriesModified = false; + for (Iterator it = setVal.iterator(); it.hasNext();) { + Object elem = it.next(); + int elemHash = (elem != null ? elem.hashCode() : 0); + Object newVal = resolveValue(beanName, bean, elem); + int newValHash = (newVal != null ? newVal.hashCode() : 0); + newContent.add(newVal); + entriesModified = entriesModified + || (newVal != elem || newValHash != elemHash); + } + return entriesModified ? newContent : value; + } else { + // log.debug(beanName + ": " + value.getClass() + " : " + value); + return value; + } + + } + + private String resolveString(String beanName, Object bean, String strVal) { + // in case is passed + if (strVal == null) + return null; + + String value = parseStringValue(bean, strVal, new HashSet()); + + if (value == null) + throw new SlcException("Could not resolve placeholder '" + strVal + + "' in bean '" + beanName + "'"); + + return (value.equals(nullValue) ? null : value); + } + + public void setPlaceholderPrefix(String placeholderPrefix) { + this.placeholderPrefix = placeholderPrefix; + } + + public void setPlaceholderSuffix(String placeholderSuffix) { + this.placeholderSuffix = placeholderSuffix; + } + + public void setNullValue(String nullValue) { + this.nullValue = nullValue; + } + + public void setInstantiationManager( + InstantiationManager instantiationManager) { + this.instantiationManager = instantiationManager; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + + // + // Following methods hacked from the internals of + // PropertyPlaceholderConfigurer + // + + protected String parseStringValue(Object bean, String strVal, + Set visitedPlaceholders) + throws BeanDefinitionStoreException { + + // in case is passed + if (strVal == null) + return null; + + StringBuffer buf = new StringBuffer(strVal); + + int startIndex = strVal.indexOf(placeholderPrefix); + while (startIndex != -1) { + int endIndex = findPlaceholderEndIndex(buf, startIndex); + if (endIndex != -1) { + String placeholder = buf.substring(startIndex + + placeholderPrefix.length(), endIndex); + if (!visitedPlaceholders.add(placeholder)) { + throw new BeanDefinitionStoreException( + "Circular placeholder reference '" + placeholder + + "' in property definitions"); + } + // Recursive invocation, parsing placeholders contained in + // the placeholder key. + placeholder = parseStringValue(bean, placeholder, + visitedPlaceholders); + // Now obtain the value for the fully resolved key... + String propVal = resolvePlaceholder(bean, placeholder); + if (propVal != null) { + // Recursive invocation, parsing placeholders contained + // in the + // previously resolved placeholder value. + propVal = parseStringValue(bean, propVal, + visitedPlaceholders); + buf.replace(startIndex, + endIndex + placeholderSuffix.length(), propVal); + if (log.isTraceEnabled()) { + log.trace("Resolved placeholder '" + placeholder + "'"); + } + startIndex = buf.indexOf(placeholderPrefix, startIndex + + propVal.length()); + } else { + throw new BeanDefinitionStoreException( + "Could not resolve placeholder '" + placeholder + + "'"); + } + visitedPlaceholders.remove(placeholder); + } else { + startIndex = -1; + } + } + + return buf.toString(); + } + + private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { + int index = startIndex + placeholderPrefix.length(); + int withinNestedPlaceholder = 0; + while (index < buf.length()) { + if (StringUtils.substringMatch(buf, index, placeholderSuffix)) { + if (withinNestedPlaceholder > 0) { + withinNestedPlaceholder--; + index = index + placeholderSuffix.length(); + } else { + return index; + } + } else if (StringUtils + .substringMatch(buf, index, placeholderPrefix)) { + withinNestedPlaceholder++; + index = index + placeholderPrefix.length(); + } else { + index++; + } + } + return -1; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionResources.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionResources.java new file mode 100644 index 000000000..759a12542 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionResources.java @@ -0,0 +1,48 @@ +/* + * 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.core.execution; + +import java.io.File; + +import org.springframework.core.io.Resource; + +/** Provides write access to resources during execution */ +public interface ExecutionResources { + /** The base directory where this execution can write */ + public File getWritableBaseDir(); + + /** Allocates a local file in the writable area and return it as a resource. */ + public Resource getWritableResource(String relativePath); + + /** + * Allocates a local file in the writable area and return it as a fully + * qualified OS path. + */ + public String getWritableOsPath(String relativePath); + + /** + * Allocates a local file in the writable area and return it as a + * {@link File}. + */ + public File getWritableOsFile(String relativePath); + + /** + * Returns the resource as a file path. If the resource is not writable it + * is copied as a file in the writable area and the path to this local file + * is returned. + */ + public String getAsOsPath(Resource resource, Boolean overwrite); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionResourcesFactoryBean.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionResourcesFactoryBean.java new file mode 100644 index 000000000..0b887da5a --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionResourcesFactoryBean.java @@ -0,0 +1,49 @@ +/* + * 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.core.execution; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; + +/** Workaround when execution placedholders needs to be passed. */ +public class ExecutionResourcesFactoryBean implements FactoryBean { + private ExecutionResources executionResources; + private String relativePath; + + public Resource getObject() throws Exception { + Assert.notNull(executionResources, "executionResources is null"); + Assert.notNull(relativePath, "relativePath is null"); + return executionResources.getWritableResource(relativePath); + } + + public Class getObjectType() { + return Resource.class; + } + + public boolean isSingleton() { + return true; + } + + public void setExecutionResources(ExecutionResources executionResources) { + this.executionResources = executionResources; + } + + public void setRelativePath(String relativePath) { + this.relativePath = relativePath; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionScope.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionScope.java new file mode 100644 index 000000000..4ac0de200 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionScope.java @@ -0,0 +1,151 @@ +/* + * 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.core.execution; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.UnsupportedException; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionSpec; +import org.argeo.slc.execution.ExecutionStack; +import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.Scope; + +/** + * When Spring beans are instantiated with this scope, the same instance is + * reused across an execution. + */ +public class ExecutionScope implements Scope { + private final static Log log = LogFactory.getLog(ExecutionScope.class); + + private final ThreadLocal executionStack = new ThreadLocal(); + public final ThreadLocal executionStackBeanName = new ThreadLocal(); + + private final ThreadLocal executionContext = new ThreadLocal(); + private final ThreadLocal executionContextBeanName = new ThreadLocal(); + + public Object get(String name, ObjectFactory objectFactory) { + if (log.isTraceEnabled()) + log.debug("Get execution scoped bean " + name); + + // shortcuts + if (executionStackBeanName.get() != null + && name.equals(executionStackBeanName.get())) { + return executionStack.get(); + } + + if (executionContextBeanName.get() != null + && name.equals(executionContextBeanName.get())) { + return executionContext.get(); + } + + // execution context must be defined first + if (executionContext.get() == null) { + Object obj = objectFactory.getObject(); + if (obj instanceof ExecutionContext) { + return dealWithSpecialScopedObject(name, executionContext, + executionContextBeanName, (ExecutionContext) obj); + } else { + // TODO: use execution context wrapper + throw new SlcException("No execution context has been defined."); + } + } + + // for other scoped objects, an executions stack must be available + if (executionStack.get() == null) { + Object obj = objectFactory.getObject(); + if (obj instanceof ExecutionStack) { + return dealWithSpecialScopedObject(name, executionStack, + executionStackBeanName, (ExecutionStack) obj); + } else { + throw new SlcException("No execution stack has been defined."); + } + } + + // see if the execution stack already knows the object + Object obj = executionStack.get().findScopedObject(name); + if (obj == null) { + obj = objectFactory.getObject(); + if (obj instanceof ExecutionContext) + throw new SlcException( + "Only one execution context can be defined per thread"); + if (obj instanceof ExecutionStack) + throw new SlcException( + "Only one execution stack can be defined per thread"); + + checkForbiddenClasses(obj); + + executionStack.get().addScopedObject(name, obj); + } + return obj; + + } + + protected T dealWithSpecialScopedObject(String name, + ThreadLocal threadLocal, + ThreadLocal threadLocalBeanName, T newObj) { + + T obj = threadLocal.get(); + if (obj == null) { + obj = newObj; + threadLocal.set(obj); + threadLocalBeanName.set(name); + if (log.isTraceEnabled()) { + log.debug(obj.getClass() + " instantiated. (beanName=" + name + + ")"); + } + return obj; + } else { + throw new SlcException("Only one scoped " + obj.getClass() + + " can be defined per thread"); + } + + } + + protected void checkForbiddenClasses(Object obj) { + Class clss = obj.getClass(); + if (ExecutionFlow.class.isAssignableFrom(clss) + || ExecutionSpec.class.isAssignableFrom(clss)) { + throw new UnsupportedException("Execution scoped object", clss); + } + } + + public String getConversationId() { + // TODO: is it the most relevant? + return executionContext.get().getUuid(); + } + + public void registerDestructionCallback(String name, Runnable callback) { + if (Thread.currentThread() instanceof ExecutionThread) { + ExecutionThread executionThread = (ExecutionThread) Thread + .currentThread(); + executionThread.registerDestructionCallback(name, callback); + } + } + + public Object remove(String name) { + if (log.isDebugEnabled()) + log.debug("Remove object " + name); + throw new UnsupportedOperationException(); + } + + public Object resolveContextualObject(String key) { + return executionContext.get().getVariable(key); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionThread.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionThread.java new file mode 100644 index 000000000..31e952d4a --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ExecutionThread.java @@ -0,0 +1,131 @@ +/* + * 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.core.execution; + +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.List; + +import javax.security.auth.Subject; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionFlowDescriptor; +import org.argeo.slc.execution.ExecutionModulesManager; +import org.argeo.slc.execution.ExecutionStep; +import org.argeo.slc.execution.RealizedFlow; + +/** Thread of a single execution */ +public class ExecutionThread extends Thread { + public final static String SYSPROP_EXECUTION_AUTO_UPGRADE = "slc.execution.autoupgrade"; + private final static Log log = LogFactory.getLog(ExecutionThread.class); + + private ExecutionModulesManager executionModulesManager; + private final RealizedFlow realizedFlow; + private final AccessControlContext accessControlContext; + + private List destructionCallbacks = new ArrayList(); + + public ExecutionThread(ProcessThreadGroup processThreadGroup, ExecutionModulesManager executionModulesManager, + RealizedFlow realizedFlow) { + super(processThreadGroup, "Flow " + realizedFlow.getFlowDescriptor().getName()); + this.realizedFlow = realizedFlow; + this.executionModulesManager = executionModulesManager; + accessControlContext = AccessController.getContext(); + } + + public void run() { + // authenticate thread + // Authentication authentication = getProcessThreadGroup() + // .getAuthentication(); + // if (authentication == null) + // throw new SlcException("Can only execute authenticated threads"); + // SecurityContextHolder.getContext().setAuthentication(authentication); + + // Retrieve execution flow descriptor + ExecutionFlowDescriptor executionFlowDescriptor = realizedFlow.getFlowDescriptor(); + String flowName = executionFlowDescriptor.getName(); + + getProcessThreadGroup().dispatchAddStep( + new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.PHASE_START, "Flow " + flowName)); + + try { + Subject subject = Subject.getSubject(accessControlContext); + try { + Subject.doAs(subject, new PrivilegedExceptionAction() { + + @Override + public Void run() throws Exception { + String autoUpgrade = System.getProperty(SYSPROP_EXECUTION_AUTO_UPGRADE); + if (autoUpgrade != null && autoUpgrade.equals("true")) + executionModulesManager.upgrade(realizedFlow.getModuleNameVersion()); + executionModulesManager.start(realizedFlow.getModuleNameVersion()); + // + // START FLOW + // + executionModulesManager.execute(realizedFlow); + // END FLOW + return null; + } + + }); + } catch (PrivilegedActionException privilegedActionException) { + throw (Exception) privilegedActionException.getCause(); + } + } catch (FlowConfigurationException e) { + String msg = "Configuration problem with flow " + flowName + ":\n" + e.getMessage(); + log.error(msg); + getProcessThreadGroup().dispatchAddStep( + new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.ERROR, msg + " " + e.getMessage())); + } catch (Exception e) { + // TODO: re-throw exception ? + String msg = "Execution of flow " + flowName + " failed."; + log.error(msg, e); + getProcessThreadGroup().dispatchAddStep( + new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.ERROR, msg + " " + e.getMessage())); + } finally { + getProcessThreadGroup().dispatchAddStep( + new ExecutionStep(realizedFlow.getModuleName(), ExecutionStep.PHASE_END, "Flow " + flowName)); + processDestructionCallbacks(); + } + } + + private synchronized void processDestructionCallbacks() { + for (int i = destructionCallbacks.size() - 1; i >= 0; i--) { + try { + destructionCallbacks.get(i).run(); + } catch (Exception e) { + log.warn("Could not process destruction callback " + i + " in thread " + getName(), e); + } + } + } + + /** + * Gather object destruction callback to be called in reverse order at the + * end of the thread + */ + synchronized void registerDestructionCallback(String name, Runnable callback) { + destructionCallbacks.add(callback); + } + + protected ProcessThreadGroup getProcessThreadGroup() { + return (ProcessThreadGroup) getThreadGroup(); + } +} \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/FileExecutionResources.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/FileExecutionResources.java new file mode 100644 index 000000000..d225cd193 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/FileExecutionResources.java @@ -0,0 +1,224 @@ +/* + * 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.core.execution; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionContext; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; + +/** Implements write access to resources based on standard Java {@link File} */ +public class FileExecutionResources implements ExecutionResources { + private final static Log log = LogFactory + .getLog(FileExecutionResources.class); + protected final static String DEFAULT_EXECUTION_RESOURCES_DIRNAME = "executionResources"; + public final static String DEFAULT_EXECUTION_RESOURCES_TMP_PATH = System + .getProperty("java.io.tmpdir") + + File.separator + + System.getProperty("user.name") + + File.separator + + "slc" + + File.separator + DEFAULT_EXECUTION_RESOURCES_DIRNAME; + + private File baseDir; + private ExecutionContext executionContext; + private String prefixDatePattern = "yyMMdd_HHmmss_SSS"; + private SimpleDateFormat sdf = null; + + private Boolean withExecutionSubdirectory = true; + + public FileExecutionResources() { + // Default base directory + String osgiInstanceArea = System.getProperty("osgi.instance.area"); + String osgiInstanceAreaDefault = System + .getProperty("osgi.instance.area.default"); + + if (osgiInstanceArea != null) { + // within OSGi with -data specified + osgiInstanceArea = removeFilePrefix(osgiInstanceArea); + baseDir = new File(osgiInstanceArea + File.separator + + DEFAULT_EXECUTION_RESOURCES_DIRNAME); + } else if (osgiInstanceAreaDefault != null) { + // within OSGi without -data specified + osgiInstanceAreaDefault = removeFilePrefix(osgiInstanceAreaDefault); + baseDir = new File(osgiInstanceAreaDefault + File.separator + + DEFAULT_EXECUTION_RESOURCES_DIRNAME); + } else {// outside OSGi + baseDir = new File(DEFAULT_EXECUTION_RESOURCES_TMP_PATH); + } + } + + protected SimpleDateFormat sdf() { + // Lazy init in case prefix has been externally set + if (sdf == null) + sdf = new SimpleDateFormat(prefixDatePattern); + return sdf; + } + + public Resource getWritableResource(String relativePath) { + File file = getFile(relativePath); + File parentDir = file.getParentFile(); + + if (!parentDir.exists()) { + // Creates if necessary + if (log.isTraceEnabled()) + log.trace("Creating parent directory " + parentDir); + parentDir.mkdirs(); + } + Resource resource = new FileSystemResource(file); + + if (log.isTraceEnabled()) + log.trace("Returns writable resource " + resource); + return resource; + } + + public String getWritableOsPath(String relativePath) { + try { + return getFile(relativePath).getCanonicalPath(); + } catch (IOException e) { + throw new SlcException("Cannot find canonical path", e); + } + } + + public File getWritableOsFile(String relativePath) { + return getFile(relativePath); + } + + public String getAsOsPath(Resource resource, Boolean overwrite) { + File file = fileFromResource(resource); + if (file != null) + try { + if (log.isTraceEnabled()) + log.debug("Directly interpret " + resource + " as OS file " + + file); + return file.getCanonicalPath(); + } catch (IOException e1) { + // silent + } + + if (log.isTraceEnabled()) + log.trace("Resource " + resource + + " is not available on the file system. Retrieving it..."); + + InputStream in = null; + OutputStream out = null; + try { + String path = resource.getURL().getPath(); + file = getFile(path); + if (file.exists() && !overwrite) + return file.getCanonicalPath(); + + file.getParentFile().mkdirs(); + in = resource.getInputStream(); + out = new FileOutputStream(file); + IOUtils.copy(in, out); + if (log.isDebugEnabled()) + log.debug("Retrieved " + resource + " to OS file " + file); + return file.getCanonicalPath(); + } catch (IOException e) { + throw new SlcException("Could not make resource " + resource + + " an OS file.", e); + } finally { + IOUtils.closeQuietly(in); + IOUtils.closeQuietly(out); + } + } + + /** + * Extract the underlying file from the resource. + * + * @return the file or null if no files support this resource. + */ + protected File fileFromResource(Resource resource) { + try { + return resource.getFile(); + } catch (IOException e) { + return null; + } + + } + + protected File getFile(String relativePath) { + File writableBaseDir = getWritableBaseDir(); + return new File(writableBaseDir.getPath() + File.separator + + relativePath.replace('/', File.separatorChar)); + } + + public File getWritableBaseDir() { + if (withExecutionSubdirectory) { + Date executionContextCreationDate = (Date) executionContext + .getVariable(ExecutionContext.VAR_EXECUTION_CONTEXT_CREATION_DATE); + Assert.notNull(executionContext, "execution context is null"); + String path = baseDir.getPath() + File.separator + + sdf().format(executionContextCreationDate); + // TODO write execution id somewhere? like in a txt file + return new File(path); + } else { + return baseDir; + } + } + + protected String removeFilePrefix(String url) { + if (url.startsWith("file:")) + return url.substring("file:".length()); + else if (url.startsWith("reference:file:")) + return url.substring("reference:file:".length()); + else + return url; + } + + public void setBaseDir(File baseDir) { + this.baseDir = baseDir; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + + public void setPrefixDatePattern(String prefixDatePattern) { + this.prefixDatePattern = prefixDatePattern; + } + + public File getBaseDir() { + return baseDir; + } + + public ExecutionContext getExecutionContext() { + return executionContext; + } + + public String getPrefixDatePattern() { + return prefixDatePattern; + } + + /** Default is true. */ + public void setWithExecutionSubdirectory(Boolean withExecutionSubdirectory) { + this.withExecutionSubdirectory = withExecutionSubdirectory; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/FlowConfigurationException.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/FlowConfigurationException.java new file mode 100644 index 000000000..aeda5aca5 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/FlowConfigurationException.java @@ -0,0 +1,12 @@ +package org.argeo.slc.core.execution; + +import org.argeo.slc.SlcException; + +/** The stack trace of such exceptions does not need to be displayed */ +public class FlowConfigurationException extends SlcException { + private static final long serialVersionUID = 8456260596346797321L; + + public FlowConfigurationException(String message) { + super(message); + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/InstantiationManager.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/InstantiationManager.java new file mode 100644 index 000000000..60e93ec15 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/InstantiationManager.java @@ -0,0 +1,120 @@ +/* + * 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.core.execution; + +import java.util.Stack; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionSpecAttribute; + +/** Manage parameters that need to be set during the instantiation of a flow */ +public class InstantiationManager { + + private final static Log log = LogFactory + .getLog(InstantiationManager.class); + + private ThreadLocal> flowStack = new ThreadLocal>(); + + public Object createRef(String name) { + + if ((flowStack.get() == null) || flowStack.get().empty()) { + throw new SlcException("No flow is currently initializing." + + " Declare ParameterRef as inner beans or prototypes."); + } + + return getInitializingFlowParameter(name); + } + + public void flowInitializationStarted(ExecutionFlow flow, String flowName) { + // set the flow name if it is DefaultExecutionFlow + if (flow instanceof DefaultExecutionFlow) { + ((DefaultExecutionFlow) flow).setBeanName(flowName); + } + + if (log.isTraceEnabled()) + log.trace("Start initialization of " + flow.hashCode() + " (" + + flow + " - " + flow.getClass() + ")"); + + // log.info("# flowInitializationStarted " + flowName); + // create a stack for this thread if there is none + if (flowStack.get() == null) { + flowStack.set(new Stack()); + } + flowStack.get().push(flow); + } + + public void flowInitializationFinished(ExecutionFlow flow, String flowName) { + if (log.isTraceEnabled()) + log.trace("Finish initialization of " + flow.hashCode() + " (" + + flow + " - " + flow.getClass() + ")"); + + if (flowStack.get() != null) { + ExecutionFlow registeredFlow = flowStack.get().pop(); + if (registeredFlow != null) { + if (!flow.getName().equals(registeredFlow.getName())) + throw new SlcException("Current flow is " + flow); + // log.info("# flowInitializationFinished " + flowName); + // initializingFlow.set(null); + } + } else { + // happens for flows imported as services + log.warn("flowInitializationFinished - Flow Stack is null"); + } + } + + protected ExecutionFlow findInitializingFlowWithParameter(String key) { + if ((flowStack.get() == null) || flowStack.get().empty()) + throw new SlcException("No initializing flow available."); + + // first look in the outer flow (that may override parameters) + for (int i = 0; i < flowStack.get().size(); i++) { + if (flowStack.get().elementAt(i).isSetAsParameter(key)) { + return flowStack.get().elementAt(i); + } + } + throw new SlcException("Key " + key + " is not set as parameter in " + + flowStack.get().firstElement().toString() + " (stack size=" + + flowStack.get().size() + ")"); + + } + + public Object getInitializingFlowParameter(String key) { + return findInitializingFlowWithParameter(key).getParameter(key); + } + + public Class getInitializingFlowParameterClass(String key) { + ExecutionSpecAttribute attr = findInitializingFlowWithParameter(key) + .getExecutionSpec().getAttributes().get(key); + if (attr instanceof RefSpecAttribute) + return ((RefSpecAttribute) attr).getTargetClass(); + else if (attr instanceof PrimitiveSpecAttribute) { + String type = ((PrimitiveSpecAttribute) attr).getType(); + Class clss = PrimitiveUtils.typeAsClass(type); + if (clss == null) + throw new SlcException("Cannot convert type " + type + + " to class."); + return clss; + } else + return null; + } + + public Boolean isInFlowInitialization() { + return (flowStack.get() != null) && !flowStack.get().empty(); + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/MapExecutionContext.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/MapExecutionContext.java new file mode 100644 index 000000000..324f97305 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/MapExecutionContext.java @@ -0,0 +1,138 @@ +/* + * 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.core.execution; + +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionStack; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +public class MapExecutionContext implements ExecutionContext, + ApplicationContextAware { + private final Map variables = Collections + .synchronizedMap(new HashMap()); + + private final String uuid; + + private ApplicationContext applicationContext; + private ExecutionStack executionStack; + + public MapExecutionContext() { + uuid = UUID.randomUUID().toString(); + variables.put(VAR_EXECUTION_CONTEXT_ID, uuid); + variables.put(VAR_EXECUTION_CONTEXT_CREATION_DATE, new Date()); + } + + public void setVariable(String key, Object value) { + // check if we do not refer to a bean + int lastInd = key.lastIndexOf('.'); + if (applicationContext != null && lastInd > 0) { + String beanName = key.substring(0, lastInd); + String propertyName = key.substring(lastInd + 1); + if (applicationContext.containsBean(beanName)) { + BeanWrapper beanWrapper = new BeanWrapperImpl( + applicationContext.getBean(beanName)); + if (!beanWrapper.isWritableProperty(propertyName)) + throw new SlcException("No writable property " + + propertyName + " in bean " + beanName); + beanWrapper.setPropertyValue(propertyName, value); + } + } + + variables.put(key, value); + } + + public Object getVariable(String key) { + // check if we do not refer to a bean + int lastInd = key.lastIndexOf('.'); + if (applicationContext != null && lastInd > 0) { + String beanName = key.substring(0, lastInd); + String propertyName = key.substring(lastInd + 1); + if (applicationContext.containsBean(beanName)) { + BeanWrapper beanWrapper = new BeanWrapperImpl( + applicationContext.getBean(beanName)); + if (!beanWrapper.isReadableProperty(propertyName)) + throw new SlcException("No readable property " + + propertyName + " in bean " + beanName); + Object obj = beanWrapper.getPropertyValue(propertyName); + return obj; + } + } + + Object value = variables.get(key); + // try system property in last resort + if (value == null) + value = System.getProperty(key); + + // if the variable was not found, look in the stack starting at the + // upper flows + if (value == null) { + value = executionStack.findLocalVariable(key); + } + return value; + } + + public String getUuid() { + return uuid; + } + + @Override + public void beforeFlow(ExecutionFlow executionFlow) { + // getUuid(); + executionStack.enterFlow(executionFlow); + setVariable(ExecutionContext.VAR_FLOW_ID, + executionStack.getCurrentStackLevelUuid()); + setVariable(ExecutionContext.VAR_FLOW_NAME, executionFlow.getName()); + } + + @Override + public void afterFlow(ExecutionFlow executionFlow) { + executionStack.leaveFlow(executionFlow); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ExecutionContext) + return uuid.equals(((ExecutionContext) obj).getUuid()); + return false; + } + + @Override + public String toString() { + return getClass().getSimpleName() + "#" + uuid; + } + + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + public void setExecutionStack(ExecutionStack executionStack) { + this.executionStack = executionStack; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/OsFileFactoryBean.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/OsFileFactoryBean.java new file mode 100644 index 000000000..e524970cf --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/OsFileFactoryBean.java @@ -0,0 +1,64 @@ +/* + * 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.core.execution; + +import java.io.File; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; + +/** Retrieve an OS File from the given resource. */ +public class OsFileFactoryBean implements FactoryBean { + private ExecutionResources executionResources; + private Resource resource; + private Boolean overwrite = false; + + /** Return an existing file on the file system. */ + public String getObject() throws Exception { + Assert.notNull(executionResources, "executionResources is null"); + Assert.notNull(resource, "resource is null"); + return executionResources.getAsOsPath(resource, overwrite); + } + + /** Return {@link Object} because CGLIB is unable to proxy {@link File}. */ + public Class getObjectType() { + return CharSequence.class; + } + + public boolean isSingleton() { + return false; + } + + /** The execution resources object. */ + public void setExecutionResources(ExecutionResources executionResources) { + this.executionResources = executionResources; + } + + /** The resource to access. */ + public void setResource(Resource resource) { + this.resource = resource; + } + + /** + * Whether to overwrite the resource if it already exists. Default is + * false. + */ + public void setOverwrite(Boolean overwrite) { + this.overwrite = overwrite; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ParameterRef.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ParameterRef.java new file mode 100644 index 000000000..45dd0964f --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ParameterRef.java @@ -0,0 +1,67 @@ +/* + * 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.core.execution; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.FactoryBean; + +public class ParameterRef implements FactoryBean { + private final static Log log = LogFactory.getLog(ParameterRef.class); + + private InstantiationManager instantiationManager; + private String name; + + /** Cached object. */ + private Object object; + + public ParameterRef() { + } + + public ParameterRef(String name) { + this.name = name; + } + + public Object getObject() throws Exception { + if (log.isTraceEnabled()) + log.debug("Parameter ref called for " + name); + + if (object == null) + object = instantiationManager.getInitializingFlowParameter(name); + return object; + } + + public Class getObjectType() { + if (object == null) + return instantiationManager.getInitializingFlowParameterClass(name); + else + return object.getClass(); + } + + public boolean isSingleton() { + return true; + } + + public void setInstantiationManager( + InstantiationManager instantiationManager) { + this.instantiationManager = instantiationManager; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveAccessor.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveAccessor.java new file mode 100644 index 000000000..18d1b9894 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveAccessor.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.core.execution; + +/** Abstraction of access to primitive values */ +public interface PrimitiveAccessor { + public final static String TYPE_STRING = "string"; + /** + * As of Argeo 1, passwords are NOT stored encrypted, just hidden in the UI, + * but stored in plain text in JCR. Use keyring instead. + */ + public final static String TYPE_PASSWORD = "password"; + public final static String TYPE_INTEGER = "integer"; + public final static String TYPE_LONG = "long"; + public final static String TYPE_FLOAT = "float"; + public final static String TYPE_DOUBLE = "double"; + public final static String TYPE_BOOLEAN = "boolean"; + + public String getType(); + + public Object getValue(); + + public void setValue(Object value); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveSpecAttribute.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveSpecAttribute.java new file mode 100644 index 000000000..fe8412c81 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveSpecAttribute.java @@ -0,0 +1,65 @@ +/* + * 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.core.execution; + +import org.argeo.slc.SlcException; + +/** + * A spec attribute wrapping a primitive value. + * + * @see PrimitiveAccessor + */ +public class PrimitiveSpecAttribute extends AbstractSpecAttribute implements + PrimitiveAccessor { + private static final long serialVersionUID = -566676381839825483L; + private String type = "string"; + private Object value = null; + + public PrimitiveSpecAttribute() { + } + + public PrimitiveSpecAttribute(String type, Object value) { + this.type = type; + this.value = value; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + // check whether type is recognized. + if (PrimitiveUtils.typeAsClass(type) == null) + throw new SlcException("Unrecognized type " + type); + this.type = type; + + } + + @Override + public String toString() { + return "Primitive spec attribute [" + type + "]" + + (value != null ? "=" + value : ""); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveUtils.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveUtils.java new file mode 100644 index 000000000..4268b8b03 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveUtils.java @@ -0,0 +1,110 @@ +/* + * 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.core.execution; + +/** Converts to and from primitive types. */ +public class PrimitiveUtils { + /** + * @deprecated Use {@link PrimitiveAccessor#TYPE_STRING} instead + */ + public final static String TYPE_STRING = PrimitiveAccessor.TYPE_STRING; + /** + * @deprecated Use {@link PrimitiveAccessor#TYPE_INTEGER} instead + */ + public final static String TYPE_INTEGER = PrimitiveAccessor.TYPE_INTEGER; + /** + * @deprecated Use {@link PrimitiveAccessor#TYPE_LONG} instead + */ + public final static String TYPE_LONG = PrimitiveAccessor.TYPE_LONG; + /** + * @deprecated Use {@link PrimitiveAccessor#TYPE_FLOAT} instead + */ + public final static String TYPE_FLOAT = PrimitiveAccessor.TYPE_FLOAT; + /** + * @deprecated Use {@link PrimitiveAccessor#TYPE_DOUBLE} instead + */ + public final static String TYPE_DOUBLE = PrimitiveAccessor.TYPE_DOUBLE; + /** + * @deprecated Use {@link PrimitiveAccessor#TYPE_BOOLEAN} instead + */ + public final static String TYPE_BOOLEAN = PrimitiveAccessor.TYPE_BOOLEAN; + + private PrimitiveUtils() { + + } + + /** @return the class or null if the provided type is not a primitive */ + public static Class typeAsClass(String type) { + if (PrimitiveAccessor.TYPE_STRING.equals(type)) + return String.class; + else if (PrimitiveAccessor.TYPE_PASSWORD.equals(type)) + return char[].class; + else if (PrimitiveAccessor.TYPE_INTEGER.equals(type)) + return Integer.class; + else if (PrimitiveAccessor.TYPE_LONG.equals(type)) + return Long.class; + else if (PrimitiveAccessor.TYPE_FLOAT.equals(type)) + return Float.class; + else if (PrimitiveAccessor.TYPE_DOUBLE.equals(type)) + return Double.class; + else if (PrimitiveAccessor.TYPE_BOOLEAN.equals(type)) + return Boolean.class; + else + return null; + } + + /** @return the type or null if the provided class is not a primitive */ + public static String classAsType(Class clss) { + if (String.class.isAssignableFrom(clss)) + return PrimitiveAccessor.TYPE_STRING; + else if (char[].class.isAssignableFrom(clss)) + return PrimitiveAccessor.TYPE_PASSWORD; + else if (Integer.class.isAssignableFrom(clss)) + return PrimitiveAccessor.TYPE_INTEGER; + else if (Long.class.isAssignableFrom(clss)) + return PrimitiveAccessor.TYPE_LONG; + else if (Float.class.isAssignableFrom(clss)) + return PrimitiveAccessor.TYPE_FLOAT; + else if (Double.class.isAssignableFrom(clss)) + return PrimitiveAccessor.TYPE_DOUBLE; + else if (Boolean.class.isAssignableFrom(clss)) + return PrimitiveAccessor.TYPE_BOOLEAN; + else + return null; + } + + /** Parse string as an object. Passwords are returned as String.*/ + public static Object convert(String type, String str) { + if (PrimitiveAccessor.TYPE_STRING.equals(type)) { + return str; + } else if (PrimitiveAccessor.TYPE_PASSWORD.equals(type)) { + return str; + } else if (PrimitiveAccessor.TYPE_INTEGER.equals(type)) { + return (Integer.parseInt(str)); + } else if (PrimitiveAccessor.TYPE_LONG.equals(type)) { + return (Long.parseLong(str)); + } else if (PrimitiveAccessor.TYPE_FLOAT.equals(type)) { + return (Float.parseFloat(str)); + } else if (PrimitiveAccessor.TYPE_DOUBLE.equals(type)) { + return (Double.parseDouble(str)); + } else if (PrimitiveAccessor.TYPE_BOOLEAN.equals(type)) { + return (Boolean.parseBoolean(str)); + } else { + return str; + } + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveValue.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveValue.java new file mode 100644 index 000000000..3dedb9c22 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/PrimitiveValue.java @@ -0,0 +1,52 @@ +/* + * 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.core.execution; + +/** Primitive value to be used by an execution. */ +public class PrimitiveValue extends AbstractExecutionValue implements + PrimitiveAccessor { + private static final long serialVersionUID = 533414290998374166L; + + private String type; + + private Object value; + + public PrimitiveValue() { + } + + public PrimitiveValue(String type, Object value) { + super(); + this.type = type; + this.value = value; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ProcessThread.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ProcessThread.java new file mode 100644 index 000000000..926789677 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ProcessThread.java @@ -0,0 +1,230 @@ +/* + * 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.core.execution; + +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.security.auth.Subject; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.execution.ExecutionModulesManager; +import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.ExecutionStep; +import org.argeo.slc.execution.RealizedFlow; + +/** + * Main thread coordinating an {@link ExecutionProcess}, launching parallel or + * sequential {@link ExecutionThread}s. + */ +public class ProcessThread extends Thread { + private final static Log log = LogFactory.getLog(ProcessThread.class); + + private final ExecutionModulesManager executionModulesManager; + private final ExecutionProcess process; + private final ProcessThreadGroup processThreadGroup; + + private Set executionThreads = Collections.synchronizedSet(new HashSet()); + + // private Boolean hadAnError = false; + private Boolean killed = false; + + private final AccessControlContext accessControlContext; + + public ProcessThread(ThreadGroup processesThreadGroup, ExecutionModulesManager executionModulesManager, + ExecutionProcess process) { + super(processesThreadGroup, "SLC Process #" + process.getUuid()); + this.executionModulesManager = executionModulesManager; + this.process = process; + processThreadGroup = new ProcessThreadGroup(process); + accessControlContext = AccessController.getContext(); + } + + public final void run() { + // authenticate thread + // Authentication authentication = getProcessThreadGroup() + // .getAuthentication(); + // if (authentication == null) + // throw new SlcException("Can only execute authenticated threads"); + // SecurityContextHolder.getContext().setAuthentication(authentication); + + log.info("\n##\n## SLC Process #" + process.getUuid() + " STARTED\n##\n"); + + // Start logging + new LoggingThread().start(); + + process.setStatus(ExecutionProcess.RUNNING); + try { + Subject subject = Subject.getSubject(accessControlContext); + try { + Subject.doAs(subject, new PrivilegedExceptionAction() { + + @Override + public Void run() throws Exception { + process(); + return null; + } + + }); + } catch (PrivilegedActionException privilegedActionException) { + Throwable cause = privilegedActionException.getCause(); + if (cause instanceof InterruptedException) + throw (InterruptedException) cause; + else + throw new SlcException("Cannot process", cause); + } + // process(); + } catch (InterruptedException e) { + die(); + return; + } catch (Exception e) { + String msg = "Process " + getProcess().getUuid() + " failed unexpectedly."; + log.error(msg, e); + getProcessThreadGroup() + .dispatchAddStep(new ExecutionStep("Process", ExecutionStep.ERROR, msg + " " + e.getMessage())); + } + + // waits for all execution threads to complete (in case they were + // started asynchronously) + for (ExecutionThread executionThread : executionThreads) { + if (executionThread.isAlive()) { + try { + executionThread.join(); + } catch (InterruptedException e) { + die(); + return; + } + } + } + + computeFinalStatus(); + } + + /** Make sure this is called BEFORE all the threads are interrupted. */ + private void computeFinalStatus() { + // String oldStatus = process.getStatus(); + // TODO: error management at flow level? + if (killed) + process.setStatus(ExecutionProcess.KILLED); + else if (processThreadGroup.hadAnError()) + process.setStatus(ExecutionProcess.ERROR); + else + process.setStatus(ExecutionProcess.COMPLETED); + // executionModulesManager.dispatchUpdateStatus(process, oldStatus, + // process.getStatus()); + log.info("\n## SLC Process #" + process.getUuid() + " " + process.getStatus() + "\n"); + } + + /** Called when being killed */ + private synchronized void die() { + killed = true; + computeFinalStatus(); + for (ExecutionThread executionThread : executionThreads) { + try { + executionThread.interrupt(); + } catch (Exception e) { + log.error("Cannot interrupt " + executionThread); + } + } + processThreadGroup.interrupt(); + } + + /** + * Implementation specific execution. To be overridden in order to deal with + * custom process types. Default expects an {@link SlcExecution}. + */ + protected void process() throws InterruptedException { + List flowsToProcess = new ArrayList(); + flowsToProcess.addAll(process.getRealizedFlows()); + while (flowsToProcess.size() > 0) { + RealizedFlow realizedFlow = flowsToProcess.remove(0); + execute(realizedFlow, true); + } + } + + /** @return the (distinct) thread used for this execution */ + protected final void execute(RealizedFlow realizedFlow, Boolean synchronous) throws InterruptedException { + if (killed) + return; + + ExecutionThread thread = new ExecutionThread(processThreadGroup, executionModulesManager, realizedFlow); + executionThreads.add(thread); + thread.start(); + + if (synchronous) + thread.join(); + + return; + } + + // public void notifyError() { + // hadAnError = true; + // } + // + // public synchronized void flowCompleted() { + // // notifyAll(); + // } + + public ExecutionProcess getProcess() { + return process; + } + + public ProcessThreadGroup getProcessThreadGroup() { + return processThreadGroup; + } + + public ExecutionModulesManager getExecutionModulesManager() { + return executionModulesManager; + } + + private class LoggingThread extends Thread { + + public LoggingThread() { + super("SLC Process Logger #" + process.getUuid()); + } + + public void run() { + boolean run = true; + while (run) { + List newSteps = new ArrayList(); + processThreadGroup.getSteps().drainTo(newSteps); + if (newSteps.size() > 0) { + // System.out.println(steps.size() + " steps"); + process.addSteps(newSteps); + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + + if (!ProcessThread.this.isAlive() && processThreadGroup.getSteps().size() == 0) + run = false; + } + } + + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ProcessThreadGroup.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ProcessThreadGroup.java new file mode 100644 index 000000000..17dbff83b --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/ProcessThreadGroup.java @@ -0,0 +1,68 @@ +/* + * 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.core.execution; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.ExecutionStep; + +/** The thread group attached to a given {@link SlcExecution}. */ +public class ProcessThreadGroup extends ThreadGroup { +// private final Authentication authentication; + private final static Integer STEPS_BUFFER_CAPACITY = 5000; + + private BlockingQueue steps = new ArrayBlockingQueue( + STEPS_BUFFER_CAPACITY); + + private Boolean hadAnError = false; + + public ProcessThreadGroup(ExecutionProcess executionProcess) { + super("SLC Process #" + executionProcess.getUuid() + " thread group"); +// this.authentication = SecurityContextHolder.getContext() +// .getAuthentication(); + } + +// public Authentication getAuthentication() { +// return authentication; +// } + + public void dispatchAddStep(ExecutionStep step) { + // ExecutionProcess slcProcess = processThread.getProcess(); + // List steps = new ArrayList(); + // steps.add(step); + // TODO clarify why we don't dispatch steps, must be a reason + // dispatchAddSteps(steps); + // slcProcess.addSteps(steps); + if (step.getType().equals(ExecutionStep.ERROR)) + hadAnError = true; + this.steps.add(step); + } + + // public void dispatchAddSteps(List steps) { + // ExecutionProcess slcProcess = processThread.getProcess(); + // executionModulesManager.dispatchAddSteps(slcProcess, steps); + // } + + public BlockingQueue getSteps() { + return steps; + } + + public Boolean hadAnError() { + return hadAnError; + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefSpecAttribute.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefSpecAttribute.java new file mode 100644 index 000000000..8e4f617c8 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefSpecAttribute.java @@ -0,0 +1,77 @@ +/* + * 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.core.execution; + +import java.util.List; + +/** A spec attribute whose value is a reference to a full fledged object. */ +public class RefSpecAttribute extends AbstractSpecAttribute implements + Cloneable { + private static final long serialVersionUID = -3427797452955753574L; + private transient Class targetClass = String.class; + /** Read only. */ + private String targetClassName; + private transient Object value = null; + + /** List to be chosen from */ + private List choices = null; + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + /** Default is {@link String} */ + public Class getTargetClass() { + return targetClass; + } + + public void setTargetClass(Class targetClass) { + this.targetClass = targetClass; + this.targetClassName = targetClass.getName(); + } + + public String getTargetClassName() { + return targetClassName; + } + + /** @return can be null */ + public List getChoices() { + return choices; + } + + public void setChoices(List choices) { + this.choices = choices; + } + + @Override + protected Object clone() throws CloneNotSupportedException { + RefSpecAttribute rsa = new RefSpecAttribute(); + rsa.setTargetClass(targetClass); + rsa.setChoices(choices); + return rsa; + } + + @Override + public String toString() { + return "Ref spec attribute [" + targetClass + "]" + + (value != null ? "=" + value : ""); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefValue.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefValue.java new file mode 100644 index 000000000..0a24bc4b4 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefValue.java @@ -0,0 +1,53 @@ +/* + * 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.core.execution; + +/** Reference value to be used by an execution */ +public class RefValue extends AbstractExecutionValue { + private static final long serialVersionUID = -8951231456757181687L; + private String ref; + private String type; + + public RefValue() { + } + + public RefValue(String ref) { + super(); + this.ref = ref; + } + + public String getRef() { + return ref; + } + + public void setRef(String ref) { + this.ref = ref; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String toString() { + return "Ref Value [" + type + "=" + ref + "]"; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefValueChoice.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefValueChoice.java new file mode 100644 index 000000000..5e1f9c2ab --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/RefValueChoice.java @@ -0,0 +1,50 @@ +/* + * 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.core.execution; + +import java.io.Serializable; + +/** A choice of ref value to be shown to the end user. */ +public class RefValueChoice implements Serializable { + private static final long serialVersionUID = -1133645722307507774L; + private String name; + private String description; + + public RefValueChoice() { + } + + public RefValueChoice(String name, String description) { + this.name = name; + this.description = description; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/SedFilteredResource.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/SedFilteredResource.java new file mode 100644 index 000000000..c793f4963 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/SedFilteredResource.java @@ -0,0 +1,144 @@ +/* + * 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.core.execution; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.commons.io.IOUtils; +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; + +/** Experimental and suboptimal */ +public class SedFilteredResource implements FactoryBean, + InitializingBean { + private Resource source; + + private List filters = new ArrayList(); + private Map patterns = new HashMap(); + + private String charset = "UTF-8"; + private Charset cs; + private CharsetDecoder decoder; + + // private CharsetEncoder encoder; + + public Resource getObject() throws Exception { + if (filters.size() == 0) + return source; + + // int capacity = 100 * 1024;// 100 KB + ByteBuffer bb; + if (source instanceof ByteArrayResource) { + bb = ByteBuffer.wrap(((ByteArrayResource) source).getByteArray()); + } else { + FileInputStream fis = null; + try { + File file = source.getFile(); + fis = new FileInputStream(file); + FileChannel fc = fis.getChannel(); + + // Get the file's size and then map it into memory + int sz = (int) fc.size(); + bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, sz); + } catch (IOException e) { + // ReadableByteChannel channel = Channels.newChannel(source + // .getInputStream()); + // bb = ByteBuffer.allocateDirect(capacity); + // int read = 0; + // do { + // read = channel.read(bb); + // } while (read > 0); + // FIXME : use nio to parse the stream as it goes + bb = ByteBuffer.wrap(IOUtils.toByteArray(source + .getInputStream())); + } finally { + IOUtils.closeQuietly(fis); + } + } + CharBuffer cb = decoder.decode(bb); + for (Pattern pattern : patterns.keySet()) { + Matcher matcher = pattern.matcher(cb); + String output = matcher.replaceAll(patterns.get(pattern)); + cb = CharBuffer.wrap(output); + } + // ByteBuffer bbout = encoder.encode(cb); + // ByteArrayOutputStream out = new ByteArrayOutputStream(capacity); + // WritableByteChannel wchannel = Channels.newChannel(out); + // wchannel.write(bbout); + ByteArrayResource res = new ByteArrayResource(cb.toString().getBytes()); + return res; + } + + public Class getObjectType() { + return Resource.class; + } + + public boolean isSingleton() { + return true; + } + + public void afterPropertiesSet() throws Exception { + cs = Charset.forName(charset); + decoder = cs.newDecoder(); + // encoder = cs.newEncoder(); + + for (String sedStr : filters) { + sedStr = sedStr.trim(); + if (sedStr.length() < 4) + throw new SlcException(sedStr + " not properly formatted."); + if (sedStr.charAt(0) != 's') + throw new SlcException(sedStr + " not properly formatted."); + Character sep = sedStr.charAt(1); + List tokens = new ArrayList(4); + StringTokenizer st = new StringTokenizer(sedStr, sep.toString()); + while (st.hasMoreTokens()) + tokens.add(st.nextToken()); + if (tokens.size() != 3 && tokens.size() != 4) + throw new SlcException(sedStr + " not properly formatted."); + patterns.put(Pattern.compile(tokens.get(1)), tokens.get(2)); + } + } + + public void setSource(Resource source) { + this.source = source; + } + + public void setFilters(List filters) { + this.filters = filters; + } + + public void setCharset(String charset) { + this.charset = charset; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/defaults.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/defaults.xml new file mode 100644 index 000000000..d84ba10eb --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/defaults.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/doc/ConsoleContextDescriber.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/doc/ConsoleContextDescriber.java new file mode 100644 index 000000000..6504a3de3 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/doc/ConsoleContextDescriber.java @@ -0,0 +1,49 @@ +/* + * 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.core.execution.doc; + +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +public class ConsoleContextDescriber implements ContextDescriber { + public void describeContext(BeanDefinitionRegistry registry) { + String[] beanNames = registry.getBeanDefinitionNames(); + for (String beanName : beanNames) { + log("\n## BEAN: " + beanName); + describeBean(registry.getBeanDefinition(beanName)); + } + } + + public void describeBean(BeanDefinition beanDefinition) { + log("BeanDefinition class: "+beanDefinition.getClass()); + log("# ATTRIBUTES"); + for(String attr:beanDefinition.attributeNames()){ + log(attr+"="+beanDefinition.getAttribute(attr)); + } + log("# PROPERTIES"); + MutablePropertyValues pValues = beanDefinition.getPropertyValues(); + for (PropertyValue pv : pValues.getPropertyValues()) { + log(pv.getName() + "= (" + pv.getValue().getClass() + ") " + + pv.getValue()); + } + } + + protected void log(Object obj){ + System.out.println(obj); + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/doc/ContextDescriber.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/doc/ContextDescriber.java new file mode 100644 index 000000000..713019b37 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/doc/ContextDescriber.java @@ -0,0 +1,24 @@ +/* + * 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.core.execution.doc; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +public interface ContextDescriber { + public void describeContext(BeanDefinitionRegistry registry); + public void describeBean(BeanDefinition bd); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/CompositeRunnableFactory.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/CompositeRunnableFactory.java new file mode 100644 index 000000000..f1e80d390 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/CompositeRunnableFactory.java @@ -0,0 +1,77 @@ +/* + * 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.core.execution.generator; + +import java.util.Map; + +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +/** + * Composite RunnableFactory, redirecting the Runnable + * creation to on of the configured RunnableFactory depending + * on an entry of the data of the RunnableDataNode. + */ +public class CompositeRunnableFactory implements RunnableFactory { + + /** + * Key used to access factory ID in the data of the RunnableDataNode + */ + private String factoryKey; + + /** + * Maps a factory ID to an ExecutionFlowFactory + */ + private Map factories; + + public void createAndRegisterRunnable(RunnableDataNode node, + BeanDefinitionRegistry beanDefinitionRegistry) { + findFactory(node).createAndRegisterRunnable(node, beanDefinitionRegistry); + } + + /** + * Finds the RunnableFactory to use for a RunnableDataNode + * @param node + * @return the RunnableFactory to use for the RunnableDataNode + */ + private RunnableFactory findFactory(RunnableDataNode node) { + // get the factory ID from the data of the RunnableDescriptor + Map data = node.getData(); + if (!data.containsKey(factoryKey)) { + throw new SlcException("No data value for key '" + factoryKey + "'"); + } + String factoryId = data.get(factoryKey).toString(); + + // see if we have a factory for the factory ID + if ((factories != null) && factories.containsKey(factoryId)) { + return factories.get(factoryId); + } + // if not, look for a bean of name equals to the factory ID + else { + throw new SlcException("Not implemented"); + } + } + + public void setFactoryKey(String factoryKey) { + this.factoryKey = factoryKey; + } + + public void setFactories(Map factories) { + this.factories = factories; + } + + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/DefaultRunnableDataNode.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/DefaultRunnableDataNode.java new file mode 100644 index 000000000..daed350b2 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/DefaultRunnableDataNode.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.core.execution.generator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Default implementation of RunnableDataNode + * + */ +public class DefaultRunnableDataNode implements RunnableDataNode { + + private List children = new ArrayList(); + + private RunnableDataNode parent; + + /** + * Data of the RunnableDataNode. Does not contain + * parent data. + */ + private Map properData = new HashMap(); + + private String path; + + private String beanName; + + public boolean isLeaf() { + return children.size() == 0; + } + + public List getChildren() { + return children; + } + + public void addChild(RunnableDataNode child) { + child.setParent(this); + children.add(child); + } + + public Map getData() { + Map data = new HashMap(); + if(parent != null) { + Map parentData = parent.getData(); + if(parentData != null) { + data.putAll(parentData); + } + } + // entries defined in parentData can be overridden + // in properData + if(properData != null) { + data.putAll(properData); + } + return data; + } + + public Map getProperData() { + return properData; + } + + public void setProperData(Map properData) { + this.properData = properData; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getBeanName() { + return beanName; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public void setParent(RunnableDataNode parent) { + this.parent = parent; + } + + public RunnableDataNode getParent() { + return parent; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/ExecutionFlowGenerator.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/ExecutionFlowGenerator.java new file mode 100644 index 000000000..d9400e42e --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/ExecutionFlowGenerator.java @@ -0,0 +1,181 @@ +/* + * 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.core.execution.generator; + +import java.util.HashMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.springframework.aop.scope.ScopedProxyUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.core.Ordered; + +/** + * Generates ExecutionFlows and Runnables as + * beans in the Spring Application Context. + * Called by the Application Context as a BeanFactoryPostProcessor. + * Two kinds of beans are generated: + * RunnableCallFlow, calling a list of Runnables from the + * Application Context after configuring the ExecutionContext, + * and outputs of a RunnableFactory. + */ +public class ExecutionFlowGenerator implements BeanFactoryPostProcessor, + Ordered { + + private final Log log = LogFactory.getLog(getClass()); + + /** + * Source providing a list of RunnableCallFlowDescriptor + * used to create RunnableCallFlow and a list of + * RunnableDataNode used to create any kind of flow via a factory + */ + protected ExecutionFlowGeneratorSource source; + + /** + * Factory used to create Runnables in the Application context from + * the RunnableDataNode provided from the source. + */ + protected RunnableFactory runnableFactory; + + /** + * Bean name of the ExecutionContext. + * Used to provide the created RunnableCallFlow beans + * with a RuntimeBeanReference to + * the ExecutionContext + */ + private String executionContextBeanName = "executionContext"; + + /** + * Bean name of the context values Map. + * A bean of class HashMap is created with this name, and a + * RuntimeBeanReference is provided to the created + * RunnableCallFlow beans. + */ + private String contextValuesBeanName = "executionFlowGenerator.contextValues"; + + /** + * Prefix added to the bean names defined in each + * RunnableCallFlowDescriptor + */ + private String flowBeanNamesPrefix = ""; + + private int order = Ordered.HIGHEST_PRECEDENCE; + + public void postProcessBeanFactory( + ConfigurableListableBeanFactory beanFactory) throws BeansException { + + // assert that the beanFactory is a BeanDefinitionRegistry + if (!(beanFactory instanceof BeanDefinitionRegistry)) { + throw new SlcException("Can only work on " + + BeanDefinitionRegistry.class); + } + + // add bean for the Context Values Map + createAndRegisterContextValuesBean((BeanDefinitionRegistry) beanFactory); + + // add beans for each RunnableDataNode + for(RunnableDataNode node : source.getRunnableDataNodes()) { + runnableFactory.createAndRegisterRunnable(node, (BeanDefinitionRegistry) beanFactory); + } + + // add beans for each RunnableCallFlowDescriptor of the source to the application context + for (RunnableCallFlowDescriptor descriptor : source + .getRunnableCallFlowDescriptors()) { + createAndRegisterFlowFor(descriptor, (BeanDefinitionRegistry) beanFactory); + } + } + + /** + * Creates a RunnableCallFlow bean + * for a RunnableCallFlowDescriptor and registers + * it in the BeanDefinitionRegistry + * @param flowDescriptor + * @param registry + */ + private void createAndRegisterFlowFor(RunnableCallFlowDescriptor flowDescriptor, BeanDefinitionRegistry registry) { + // create the flow bean + GenericBeanDefinition flowBean = new GenericBeanDefinition(); + flowBean.setBeanClass(RunnableCallFlow.class); + + String beanName = flowBeanNamesPrefix + flowDescriptor.getBeanName(); + + MutablePropertyValues mpv = new MutablePropertyValues(); + mpv.addPropertyValue("runnableCalls", flowDescriptor.getRunnableCalls()); + mpv.addPropertyValue("sharedContextValuesMap", new RuntimeBeanReference(contextValuesBeanName)); + + mpv.addPropertyValue("name", beanName); + mpv.addPropertyValue("path", flowDescriptor.getPath()); + + mpv.addPropertyValue("executionContext", new RuntimeBeanReference(executionContextBeanName)); + + flowBean.setPropertyValues(mpv); + + // register it + if(log.isDebugEnabled()) { + log.debug("Registering bean definition for RunnableCallFlow " + beanName); + } + registry.registerBeanDefinition(beanName, flowBean); + } + + /** + * Creates the Context Values bean and register it in the + * BeanDefinitionRegistry + * @param registry + */ + private void createAndRegisterContextValuesBean(BeanDefinitionRegistry registry) { + GenericBeanDefinition contextValuesBean = new GenericBeanDefinition(); + contextValuesBean.setBeanClass(HashMap.class); + + BeanDefinitionHolder bdh = ScopedProxyUtils.createScopedProxy(new BeanDefinitionHolder(contextValuesBean, contextValuesBeanName), registry, true); + registry.registerBeanDefinition(contextValuesBeanName, bdh.getBeanDefinition()); + } + + public int getOrder() { + return order; + } + + public void setOrder(int order) { + this.order = order; + } + + public void setSource(ExecutionFlowGeneratorSource source) { + this.source = source; + } + + public void setRunnableFactory(RunnableFactory runnableFactory) { + this.runnableFactory = runnableFactory; + } + + public void setExecutionContextBeanName(String executionContextBeanName) { + this.executionContextBeanName = executionContextBeanName; + } + + public void setContextValuesBeanName(String contextValuesBeanName) { + this.contextValuesBeanName = contextValuesBeanName; + } + + public void setFlowBeanNamesPrefix(String flowBeanNamesPrefix) { + this.flowBeanNamesPrefix = flowBeanNamesPrefix; + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/ExecutionFlowGeneratorSource.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/ExecutionFlowGeneratorSource.java new file mode 100644 index 000000000..8d699c660 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/ExecutionFlowGeneratorSource.java @@ -0,0 +1,39 @@ +/* + * 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.core.execution.generator; + +import java.util.List; + +/** + * Provides 2 types of information required by an ExecutionFlowGenerator: + * a list of RunnableCallFlowDescriptor used to create RunnableCallFlow + * and a list of RunnableDataNode used to create any kind of flow via a factory. + */ +public interface ExecutionFlowGeneratorSource { + + /** + * @return a list of RunnableCallFlowDescriptor used + * by a ExecutionFlowGenerator to create RunnableCallFlow + */ + public List getRunnableCallFlowDescriptors(); + + /** + * @return a list of RunnableDataNode used + * by a ExecutionFlowGenerator to create any kind of flow via a factory + */ + public List getRunnableDataNodes(); + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCall.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCall.java new file mode 100644 index 000000000..c3fd5f2d8 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCall.java @@ -0,0 +1,70 @@ +/* + * 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.core.execution.generator; + +import java.util.Map; + +/** + * Storage class for information required to call a flow + * of the Spring execution context: + * bean name of the flow, + * variables to add to the Execution Context before the call + * and variables (context values) to add to a Map + * potentially referenced by the called flow + */ +public class RunnableCall { + + /** + * Bean name of the flow to call + */ + private String beanName; + + /** + * Variables to add to the execution context before the call + */ + private Map executionVariables; + + /** + * Variables to add to the Map potentially referenced by + * the called flow + */ + private Map contextValues; + + public String getBeanName() { + return beanName; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public Map getExecutionVariables() { + return executionVariables; + } + + public void setExecutionVariables(Map executionVariables) { + this.executionVariables = executionVariables; + } + + public Map getContextValues() { + return contextValues; + } + + public void setContextValues(Map contextValues) { + this.contextValues = contextValues; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCallFlow.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCallFlow.java new file mode 100644 index 000000000..695606c21 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCallFlow.java @@ -0,0 +1,243 @@ +/* + * 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.core.execution.generator; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.DefaultExecutionSpec; +import org.argeo.slc.execution.ExecutionContext; +import org.argeo.slc.execution.ExecutionFlow; +import org.argeo.slc.execution.ExecutionSpec; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Execution Flow calling a list of Runnable (identified by their + * bean name in the Spring Application Context) after configuring the Execution + * context and a Map potentially shared by the called Runnable + * + */ +public class RunnableCallFlow implements ExecutionFlow, ApplicationContextAware { + + private final static Log log = LogFactory.getLog(RunnableCallFlow.class); + + /** + * Key in the execution context for the index of the call (e.g. 0 for the + * first runnable called, ...) + */ + public final static String VAR_CALL_INDEX = "slcVar.runnableCallFlow.callIndex"; + + /** + * Name of the flow. Also bean name + */ + private String name; + + /** + * Path of the flow + */ + private String path; + + /** + * Whether an exception in a Runnable shall stop the execution + * of the flow + */ + private Boolean failOnError = true; + + /** + * List of Runnable to call, with bean name, execution + * variables and context values + */ + private List runnableCalls; + + /** + * Map potentially referenced by called flows. Updated with the context + * values of a Runnable before calling it. + */ + private Map sharedContextValuesMap; + + /** + * ExecutionSpec of the flow. Does not contain any attribute. + */ + private ExecutionSpec executionSpec = new DefaultExecutionSpec(); + + /** + * Reference to the ExecutionContext + */ + private ExecutionContext executionContext; + + /** + * Reference to the Spring ApplicationContext. Set via + * setApplicationContext, the class implementing + * ApplicationContextAware + */ + private ApplicationContext applicationContext; + + /** + * Runs a Runnable after configuring the Execution Context and + * sharedContextValuesMap + * + * @param runnable + * the Runnable to call + * @param executionVariables + * the variables to add to the ExecutionContext + * @param contextValues + * the variables to add to sharedContextValuesMap + * @param callIndex + * index of the call (0 for the first called + * Runnable) set as variable of the + * ExecutionContext + */ + private void run(Runnable runnable, Map executionVariables, + Map contextValues, int callIndex) { + // add all variables to the Execution Context + for (Map.Entry entry : executionVariables.entrySet()) { + executionContext.setVariable(entry.getKey(), entry.getValue()); + } + + // add call Index Variable + executionContext.setVariable(VAR_CALL_INDEX, callIndex); + + // clear sharedContextValues and add all values of contextValues + if (sharedContextValuesMap != null) { + sharedContextValuesMap.clear(); + sharedContextValuesMap.putAll(contextValues); + } + + // then run the runnable + doExecuteRunnable(runnable); + } + + public void doExecuteRunnable(Runnable runnable) { + runnable.run(); + } + + /** + * Executes the flow. For each RunnableCall, the corresponding + * flow is retrieved from the Spring Application Context, the + * ExecutionContext and sharedContextValuesMap are + * configured and the Runnable is called. + */ + public void run() { + if (applicationContext == null) { + throw new SlcException("No ApplicationContext defined"); + } + + try { + for (int callIndex = 0; callIndex < runnableCalls.size(); ++callIndex) { + RunnableCall runnableCall = runnableCalls.get(callIndex); + Object bean = applicationContext.getBean( + runnableCall.getBeanName(), Runnable.class); + if (log.isDebugEnabled()) + log.debug("Running flow '" + runnableCall.getBeanName() + + "'"); + run((Runnable) bean, runnableCall.getExecutionVariables(), + runnableCall.getContextValues(), callIndex); + } + } catch (RuntimeException e) { + if (failOnError) + throw e; + else { + log.error("Execution flow failed," + + " but process did not fail" + + " because failOnError property" + + " is set to false: " + e); + if (log.isTraceEnabled()) + e.printStackTrace(); + } + } + } + + public Iterator runnables() { + List runnables = new ArrayList(); + for (int callIndex = 0; callIndex < runnableCalls.size(); ++callIndex) { + RunnableCall runnableCall = runnableCalls.get(callIndex); + Object bean = applicationContext.getBean( + runnableCall.getBeanName(), Runnable.class); + runnables.add((Runnable) bean); + } + return runnables.iterator(); + } + + public Runnable getRunnable() { + if (runnableCalls.size() == 1) + return runnables().next(); + else + throw new SlcException("There are " + runnableCalls.size() + + " runnables in flow " + getName()); + } + + @Override + public String toString() { + return new StringBuffer("RunnableCallFlow ").append(name).toString(); + } + + public ExecutionSpec getExecutionSpec() { + return executionSpec; + } + + public String getName() { + return name; + } + + public Object getParameter(String key) { + throw new SlcException("RunnableCallFlow have no parameters"); + } + + public String getPath() { + return path; + } + + public Boolean isSetAsParameter(String key) { + // The ExecutionSpec having no attribute, + // always return false + return false; + } + + public void setName(String name) { + this.name = name; + } + + public void setPath(String path) { + this.path = path; + } + + public void setExecutionContext(ExecutionContext executionContext) { + this.executionContext = executionContext; + } + + public void setRunnableCalls(List runnableCalls) { + this.runnableCalls = runnableCalls; + } + + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + public void setSharedContextValuesMap(Map contextValues) { + this.sharedContextValuesMap = contextValues; + } + + public void setFailOnError(Boolean failOnError) { + this.failOnError = failOnError; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCallFlowDescriptor.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCallFlowDescriptor.java new file mode 100644 index 000000000..e0bbbdda9 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableCallFlowDescriptor.java @@ -0,0 +1,70 @@ +/* + * 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.core.execution.generator; + +import java.util.ArrayList; +import java.util.List; + +/** + * Storage Class for information required to + * instantiate a RunnableCallFlow: + * bean name of the flow, + * path of the flow + * and list of RunnableCall. + * + */ +public class RunnableCallFlowDescriptor { + + /** + * Bean name of the flow to instantiate + */ + private String beanName; + + /** + * Path of the flow to instantiate + */ + private String path; + + /** + * List of RunnableCall + */ + private List runnableCalls = new ArrayList(); + + public String getBeanName() { + return beanName; + } + + public void setBeanName(String beanName) { + this.beanName = beanName; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public List getRunnableCalls() { + return runnableCalls; + } + + public void setRunnableCalls(List runnableCalls) { + this.runnableCalls = runnableCalls; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableDataNode.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableDataNode.java new file mode 100644 index 000000000..51843dcd0 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableDataNode.java @@ -0,0 +1,74 @@ +/* + * 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.core.execution.generator; + +import java.util.List; +import java.util.Map; + +/** + * Stores information relative to a Runnable. + * Allows to structure the information as a tree, each node + * storing data as a Map. + */ +public interface RunnableDataNode { + + /** + * @return a Map containing the data associated with this node. + * Data associated with parent nodes are expected + * to be contained in the returned Map + */ + public Map getData(); + + /** + * @return the name of the bean to create. + * Can be null if no bean shall be created for the + * RunnableDataNode (e.g. is is a sub-node) + */ + public String getBeanName(); + + /** + * @return the path of the flow bean to create. + * Can be null if the bean to created is not an + * ExecutionFlow or if no bean shall be created for the + * RunnableDataNode (e.g. is is a sub-node) + */ + public String getPath(); + + /** + * @return whether the RunnableDataNode has + * children or not. + * Expected to be equivalent to getChildren().empty() + */ + public boolean isLeaf(); + + /** + * @return the list of RunnableDataNode children. + * Can be empty. Shall not be null. + */ + public List getChildren(); + + /** + * @return the RunnableDataNode parent. + * Can be null if no parent is defined (top node). + */ + public RunnableDataNode getParent(); + + /** + * Sets the RunnableDataNode parent + * @param parent + */ + public void setParent(RunnableDataNode parent); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableFactory.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableFactory.java new file mode 100644 index 000000000..2b3702889 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/generator/RunnableFactory.java @@ -0,0 +1,29 @@ +/* + * 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.core.execution.generator; + +import org.springframework.beans.factory.support.BeanDefinitionRegistry; + +/** + * Interprets a RunnableDataNode by creating corresponding + * beans and registering them in a BeanDefinitionRegistry + * + */ +public interface RunnableFactory { + + public void createAndRegisterRunnable(RunnableDataNode node, + BeanDefinitionRegistry beanDefinitionRegistry); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/runtime.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/runtime.xml new file mode 100644 index 000000000..33542ee20 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/runtime.xml @@ -0,0 +1,59 @@ + + + + + + + Bare minimal runtime configuration. In general you will + want to use simple.xml instead. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/simple.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/simple.xml new file mode 100644 index 000000000..ff243baf6 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/simple.xml @@ -0,0 +1,49 @@ + + + + + + + Default Capabilities + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/specs.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/specs.xml new file mode 100644 index 000000000..7cc960475 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/specs.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/spring.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/spring.xml new file mode 100644 index 000000000..de1c06b1e --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/spring.xml @@ -0,0 +1,51 @@ + + + + + + + + Simple runtime enriched with defaults and templates used + to simplify XML files. These templates have been deprecated by the + custom XML namespace and will be removed in SLC 2.x. Use the XML + namespace instead. + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/CloseTestResult.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/CloseTestResult.java new file mode 100644 index 000000000..43b296106 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/CloseTestResult.java @@ -0,0 +1,31 @@ +/* + * 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.core.execution.tasks; + +import org.argeo.slc.test.TestResult; + +public class CloseTestResult implements Runnable { + private TestResult testResult; + + public void run() { + testResult.close(); + } + + public void setTestResult(TestResult testResult) { + this.testResult = testResult; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/Echo.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/Echo.java new file mode 100644 index 000000000..d47149b86 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/Echo.java @@ -0,0 +1,62 @@ +/* + * 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.core.execution.tasks; + +import java.io.File; +import java.io.IOException; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.springframework.core.io.Resource; + +public class Echo implements Runnable { + private final static Log defaultLog = LogFactory.getLog(Echo.class); + private Resource writeTo = null; + + private Log log; + private Object message; + + public void run() { + log().info(message); + + if (writeTo != null) { + try { + File file = writeTo.getFile(); + if (log().isDebugEnabled()) + log().debug("Write to " + file); + if (message != null) + FileUtils.writeStringToFile(file, message.toString()); + } catch (IOException e) { + throw new SlcException("Could not write to " + writeTo, e); + } + } + } + + private Log log() { + return log != null ? log : defaultLog; + } + + public void setMessage(Object message) { + this.message = message; + } + + public void setWriteTo(Resource writeTo) { + this.writeTo = writeTo; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/If.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/If.java new file mode 100644 index 000000000..0d22e437d --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/If.java @@ -0,0 +1,64 @@ +/* + * 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.core.execution.tasks; + +import org.argeo.slc.SlcException; + +/** Conditional execution */ +public class If implements Runnable { + private Boolean is; + private Boolean not; + private Runnable then; + private Runnable els; + + public void run() { + if (is == null && not == null) + throw new SlcException("No condition set"); + if (is != null && not != null) + throw new SlcException("Both is and not cannot be set"); + + boolean bool = (is != null ? is : !not); + if (bool) { + if (then != null) + then.run(); + } else { + if (els != null) + els.run(); + } + + } + + public void setIs(Boolean bool) { + this.is = bool; + } + + public void setThen(Runnable then) { + this.then = then; + } + + public void setEls(Runnable els) { + this.els = els; + } + + public Boolean getNot() { + return not; + } + + public void setNot(Boolean not) { + this.not = not; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/JvmProcess.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/JvmProcess.java new file mode 100644 index 000000000..01f11012f --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/JvmProcess.java @@ -0,0 +1,253 @@ +/* + * 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.core.execution.tasks; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.commons.io.IOUtils; +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; + +/** A Java Virtual Machine process. */ +public class JvmProcess extends SystemCall implements InitializingBean { + private Properties systemProperties = new Properties(); + private List classpath = new ArrayList(); + private List pBootClasspath = new ArrayList(); + private Resource jvm = null; + private String mainClass; + private String mainJar; + private List jvmArgs = new ArrayList(); + private List args = new ArrayList(); + + private String systemPropertiesFileProperty = null; + private String systemPropertiesFileDir = null; + private String systemPropertiesFileName = null; + + public void afterPropertiesSet() throws Exception { + List command = new ArrayList(); + if (jvm != null) + command.add(asFile(jvm).getPath()); + else + command.add("java"); + + if (pBootClasspath.size() > 0) { + StringBuffer buf = new StringBuffer("-Xbootclasspath/p:"); + Boolean first = true; + for (Resource res : pBootClasspath) { + if (first) + first = false; + else + buf.append(File.pathSeparatorChar); + + buf.append(asFile(res)); + } + command.add(buf.toString()); + } + + for (String jvmArg : jvmArgs) { + command.add(jvmArg); + } + + if (classpath.size() > 0) { + command.add("-cp"); + StringBuffer buf = new StringBuffer(""); + for (Resource res : classpath) { + if (buf.length() != 0) + buf.append(File.pathSeparatorChar); + buf.append(asFile(res)); + } + command.add(buf.toString()); + } + + if (systemPropertiesFileProperty == null) { + // pass system properties as argument + for (Map.Entry entry : systemProperties.entrySet()) { + command.add("-D" + entry.getKey() + "=" + entry.getValue()); + } + } else { + // write system properties in a file to work around OS limitations + // with command line (e.g. Win XP) + String dir = systemPropertiesFileDir; + if (dir == null) + dir = getExecDirToUse(); + String fileName = systemPropertiesFileName; + if (fileName == null) + fileName = systemPropertiesFileProperty + ".properties"; + + // Write file + FileOutputStream fos = null; + File file = new File(dir + File.separator + fileName); + try { + + if (!file.getParentFile().exists()) + file.getParentFile().mkdirs(); + fos = new FileOutputStream(file); + systemProperties.store(fos, "Automatically generated by " + + getClass()); + command.add("-D" + systemPropertiesFileProperty + "=" + + file.getCanonicalPath()); + } catch (IOException e) { + throw new SlcException("Cannot write to system properties to " + + file, e); + } finally { + IOUtils.closeQuietly(fos); + } + } + + // Program + if (mainClass != null) { + command.add(mainClass); + } else if (mainJar != null) { + command.add("-jar"); + command.add(mainJar); + } else { + throw new SlcException("No main class or jar defined"); + } + + for (String arg : args) { + command.add(arg); + } + + setCommand(command); + } + + protected File asFile(Resource res) { + try { + return res.getFile(); + } catch (FileNotFoundException e) { + return copyToTempFile(res); + } catch (IOException e) { + throw new SlcException("Cannot convert resource to file", e); + } + + } + + protected File copyToTempFile(Resource res) { + File tempFile; + FileOutputStream fos; + try { + tempFile = File.createTempFile("slcJvmProcess-", res.getFilename()); + tempFile.deleteOnExit(); + fos = new FileOutputStream(tempFile); + IOUtils.copy(res.getInputStream(), fos); + } catch (IOException e) { + throw new SlcException("Cannot copy " + res + " to temp file.", e); + } + IOUtils.closeQuietly(fos); + return tempFile; + } + + /** Append the argument (for chaining) */ + @Override + public SystemCall arg(String arg) { + args.add(arg); + return this; + } + + /** Append the argument (for chaining) */ + @Override + public SystemCall arg(String arg, String value) { + args.add(arg); + args.add(value); + return this; + } + + public Properties getSystemProperties() { + return systemProperties; + } + + public void setSystemProperties(Properties systemProperties) { + this.systemProperties = systemProperties; + } + + public List getClasspath() { + return classpath; + } + + public void setClasspath(List classpath) { + this.classpath = classpath; + } + + public List getPBootClasspath() { + return pBootClasspath; + } + + public void setPBootClasspath(List bootClasspath) { + pBootClasspath = bootClasspath; + } + + public Resource getJvm() { + return jvm; + } + + public void setJvm(Resource jvm) { + this.jvm = jvm; + } + + public String getMainClass() { + return mainClass; + } + + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + public String getMainJar() { + return mainJar; + } + + public void setMainJar(String mainJar) { + this.mainJar = mainJar; + } + + public List getJvmArgs() { + return jvmArgs; + } + + public void setJvmArgs(List jvmArgs) { + this.jvmArgs = jvmArgs; + } + + public List getArgs() { + return args; + } + + public void setArgs(List args) { + this.args = args; + } + + public void setSystemPropertiesFileProperty( + String systemPropertiesFilePropertyName) { + this.systemPropertiesFileProperty = systemPropertiesFilePropertyName; + } + + public void setSystemPropertiesFileDir(String systemPropertiesFileDir) { + this.systemPropertiesFileDir = systemPropertiesFileDir; + } + + public void setSystemPropertiesFileName(String systemPropertiesFileName) { + this.systemPropertiesFileName = systemPropertiesFileName; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/MergedLists.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/MergedLists.java new file mode 100644 index 000000000..e1740e659 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/MergedLists.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.core.execution.tasks; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.FactoryBean; + +/** Merge the provided lists in one single list, in the order provided. */ +public class MergedLists implements FactoryBean> { + private List> lists = new ArrayList>(); + + public void setLists(List> lists) { + this.lists = lists; + } + + public List getObject() throws Exception { + List merged = new ArrayList(); + for (List lst : lists) { + merged.addAll(lst); + } + return merged; + } + + public Class getObjectType() { + return List.class; + } + + public boolean isSingleton() { + return false; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/MethodCall.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/MethodCall.java new file mode 100644 index 000000000..e4fa77222 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/MethodCall.java @@ -0,0 +1,53 @@ +/* + * 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.core.execution.tasks; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; + +public class MethodCall implements Runnable { + private Object target; + private String method; + private List args = new ArrayList(); + + public void run() { + Assert.notNull(target, "target"); + Assert.notNull(method, "method"); + Method methodRef = ReflectionUtils + .findMethod(target.getClass(), method); + if (args.size() == 0) + ReflectionUtils.invokeMethod(methodRef, target); + else + ReflectionUtils.invokeMethod(methodRef, methodRef, args.toArray()); + } + + public void setTarget(Object target) { + this.target = target; + } + + public void setMethod(String method) { + this.method = method; + } + + public void setArgs(List args) { + this.args = args; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/OverrideContextAware.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/OverrideContextAware.java new file mode 100644 index 000000000..9afa8468c --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/OverrideContextAware.java @@ -0,0 +1,72 @@ +/* + * 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.core.execution.tasks; + +import org.argeo.slc.SlcException; +import org.argeo.slc.core.test.context.SimpleContextAware; +import org.argeo.slc.test.context.ContextAware; + +/** + * Overrides Values and Expected values of a target + * SimpleContextAware with the corresponding + * values and expected values of a source ContextAware + * + */ +public class OverrideContextAware implements Runnable { + + private ContextAware source; + + private SimpleContextAware target; + + /** + * Whether an exception shall be thrown if a value + * or expected value of the source is not defined + * in the target + */ + private Boolean failIfUndefinedInSource = true; + + public void run() { + // override values + if(source.getValues() != null) + for(String key : source.getValues().keySet()) { + if(failIfUndefinedInSource && !target.getValues().containsKey(key)) { + throw new SlcException("No entry in target values for key '" + key + "'"); + } + target.getValues().put(key, source.getValues().get(key)); + } + + // override expected values + if(source.getExpectedValues() != null) + for(String key : source.getExpectedValues().keySet()) { + if(failIfUndefinedInSource && !target.getExpectedValues().containsKey(key)) { + throw new SlcException("No entry in target expected values for key '" + key + "'"); + } + target.getExpectedValues().put(key, source.getExpectedValues().get(key)); + } + } + + public void setSource(ContextAware source) { + this.source = source; + } + + public void setTarget(SimpleContextAware target) { + this.target = target; + } + + public void setFailIfUndefinedInSource(Boolean failIfUndefinedInSource) { + this.failIfUndefinedInSource = failIfUndefinedInSource; + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/SystemCall.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/SystemCall.java new file mode 100644 index 000000000..27cc59d60 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/SystemCall.java @@ -0,0 +1,782 @@ +/* + * 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.core.execution.tasks; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.security.auth.callback.CallbackHandler; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.ExecuteException; +import org.apache.commons.exec.ExecuteResultHandler; +import org.apache.commons.exec.ExecuteStreamHandler; +import org.apache.commons.exec.ExecuteWatchdog; +import org.apache.commons.exec.Executor; +import org.apache.commons.exec.LogOutputStream; +import org.apache.commons.exec.PumpStreamHandler; +import org.apache.commons.exec.ShutdownHookProcessDestroyer; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.UnsupportedException; +import org.argeo.slc.core.execution.ExecutionResources; +import org.argeo.slc.core.test.SimpleResultPart; +import org.argeo.slc.test.TestResult; +import org.argeo.slc.test.TestStatus; +import org.springframework.core.io.Resource; + +/** Execute an OS specific system call. */ +public class SystemCall implements Runnable { + public final static String LOG_STDOUT = "System.out"; + + private final Log log = LogFactory.getLog(getClass()); + + private String execDir; + + private String cmd = null; + private List command = null; + + private Executor executor = new DefaultExecutor(); + private Boolean synchronous = true; + + private String stdErrLogLevel = "ERROR"; + private String stdOutLogLevel = "INFO"; + + private Resource stdOutFile = null; + private Resource stdErrFile = null; + + private Resource stdInFile = null; + /** + * If no {@link #stdInFile} provided, writing to this stream will write to + * the stdin of the process. + */ + private OutputStream stdInSink = null; + + private Boolean redirectStdOut = false; + + private List outputListeners = Collections + .synchronizedList(new ArrayList()); + + private Map> osCommands = new HashMap>(); + private Map osCmds = new HashMap(); + private Map environmentVariables = new HashMap(); + + private Boolean logCommand = false; + private Boolean redirectStreams = true; + private Boolean exceptionOnFailed = true; + private Boolean mergeEnvironmentVariables = true; + +// private Authentication authentication; + + private String osConsole = null; + private String generateScript = null; + + /** 24 hours */ + private Long watchdogTimeout = 24 * 60 * 60 * 1000l; + + private TestResult testResult; + + private ExecutionResources executionResources; + + /** Sudo the command, as root if empty or as user if not. */ + private String sudo = null; + // TODO make it more secure and robust, test only once + private final String sudoPrompt = UUID.randomUUID().toString(); + private String askPassProgram = "/usr/libexec/openssh/ssh-askpass"; + @SuppressWarnings("unused") + private boolean firstLine = true; + @SuppressWarnings("unused") + private CallbackHandler callbackHandler; + /** Chroot to the this path (must not be empty) */ + private String chroot = null; + + // Current + /** Current watchdog, null if process is completed */ + ExecuteWatchdog currentWatchdog = null; + + /** Empty constructor */ + public SystemCall() { + + } + + /** + * Constructor based on the provided command list. + * + * @param command + * the command list + */ + public SystemCall(List command) { + this.command = command; + } + + /** + * Constructor based on the provided command. + * + * @param cmd + * the command. If the provided string contains no space a + * command list is initialized with the argument as first + * component (useful for chained construction) + */ + public SystemCall(String cmd) { + if (cmd.indexOf(' ') < 0) { + command = new ArrayList(); + command.add(cmd); + } else { + this.cmd = cmd; + } + } + + /** Executes the system call. */ + public void run() { +// authentication = SecurityContextHolder.getContext().getAuthentication(); + + // Manage streams + Writer stdOutWriter = null; + OutputStream stdOutputStream = null; + Writer stdErrWriter = null; + InputStream stdInStream = null; + if (stdOutFile != null) + if (redirectStdOut) + stdOutputStream = createOutputStream(stdOutFile); + else + stdOutWriter = createWriter(stdOutFile, true); + + if (stdErrFile != null) { + stdErrWriter = createWriter(stdErrFile, true); + } else { + if (stdOutFile != null && !redirectStdOut) + stdErrWriter = createWriter(stdOutFile, true); + } + + try { + if (stdInFile != null) + stdInStream = stdInFile.getInputStream(); + else { + stdInStream = new PipedInputStream(); + stdInSink = new PipedOutputStream( + (PipedInputStream) stdInStream); + } + } catch (IOException e2) { + throw new SlcException("Cannot open a stream for " + stdInFile, e2); + } + + if (log.isTraceEnabled()) { + log.debug("os.name=" + System.getProperty("os.name")); + log.debug("os.arch=" + System.getProperty("os.arch")); + log.debug("os.version=" + System.getProperty("os.version")); + } + + // Execution directory + File dir = new File(getExecDirToUse()); + // if (!dir.exists()) + // dir.mkdirs(); + + // Watchdog to check for lost processes + Executor executorToUse; + if (executor != null) + executorToUse = executor; + else + executorToUse = new DefaultExecutor(); + executorToUse.setWatchdog(createWatchdog()); + + if (redirectStreams) { + // Redirect standard streams + executorToUse.setStreamHandler(createExecuteStreamHandler( + stdOutWriter, stdOutputStream, stdErrWriter, stdInStream)); + } else { + // Dummy stream handler (otherwise pump is used) + executorToUse.setStreamHandler(new DummyexecuteStreamHandler()); + } + + executorToUse.setProcessDestroyer(new ShutdownHookProcessDestroyer()); + executorToUse.setWorkingDirectory(dir); + + // Command line to use + final CommandLine commandLine = createCommandLine(); + if (logCommand) + log.info("Execute command:\n" + commandLine + + "\n in working directory: \n" + dir + "\n"); + + // Env variables + Map environmentVariablesToUse = null; + environmentVariablesToUse = new HashMap(); + if (mergeEnvironmentVariables) + environmentVariablesToUse.putAll(System.getenv()); + if (environmentVariables.size() > 0) + environmentVariablesToUse.putAll(environmentVariables); + + // Execute + ExecuteResultHandler executeResultHandler = createExecuteResultHandler(commandLine); + + // + // THE EXECUTION PROPER + // + try { + if (synchronous) + try { + int exitValue = executorToUse.execute(commandLine, + environmentVariablesToUse); + executeResultHandler.onProcessComplete(exitValue); + } catch (ExecuteException e1) { + if (e1.getExitValue() == Executor.INVALID_EXITVALUE) { + Thread.currentThread().interrupt(); + return; + } + // Sleep 1s in order to make sure error logs are flushed + Thread.sleep(1000); + executeResultHandler.onProcessFailed(e1); + } + else + executorToUse.execute(commandLine, environmentVariablesToUse, + executeResultHandler); + } catch (SlcException e) { + throw e; + } catch (Exception e) { + throw new SlcException("Could not execute command " + commandLine, + e); + } finally { + IOUtils.closeQuietly(stdOutWriter); + IOUtils.closeQuietly(stdErrWriter); + IOUtils.closeQuietly(stdInStream); + IOUtils.closeQuietly(stdInSink); + } + + } + + public synchronized String function() { + final StringBuffer buf = new StringBuffer(""); + SystemCallOutputListener tempOutputListener = new SystemCallOutputListener() { + private Long lineCount = 0l; + + public void newLine(SystemCall systemCall, String line, + Boolean isError) { + if (!isError) { + if (lineCount != 0l) + buf.append('\n'); + buf.append(line); + lineCount++; + } + } + }; + addOutputListener(tempOutputListener); + run(); + removeOutputListener(tempOutputListener); + return buf.toString(); + } + + public String asCommand() { + return createCommandLine().toString(); + } + + @Override + public String toString() { + return asCommand(); + } + + /** + * Build a command line based on the properties. Can be overridden by + * specific command wrappers. + */ + protected CommandLine createCommandLine() { + // Check if an OS specific command overrides + String osName = System.getProperty("os.name"); + List commandToUse = null; + if (osCommands.containsKey(osName)) + commandToUse = osCommands.get(osName); + else + commandToUse = command; + String cmdToUse = null; + if (osCmds.containsKey(osName)) + cmdToUse = osCmds.get(osName); + else + cmdToUse = cmd; + + CommandLine commandLine = null; + + // Which command definition to use + if (commandToUse == null && cmdToUse == null) + throw new SlcException("Please specify a command."); + else if (commandToUse != null && cmdToUse != null) + throw new SlcException( + "Specify the command either as a line or as a list."); + else if (cmdToUse != null) { + if (chroot != null && !chroot.trim().equals("")) + cmdToUse = "chroot \"" + chroot + "\" " + cmdToUse; + if (sudo != null) { + environmentVariables.put("SUDO_ASKPASS", askPassProgram); + if (!sudo.trim().equals("")) + cmdToUse = "sudo -p " + sudoPrompt + " -u " + sudo + " " + + cmdToUse; + else + cmdToUse = "sudo -p " + sudoPrompt + " " + cmdToUse; + } + + // GENERATE COMMAND LINE + commandLine = CommandLine.parse(cmdToUse); + } else if (commandToUse != null) { + if (commandToUse.size() == 0) + throw new SlcException("Command line is empty."); + + if (chroot != null && sudo != null) { + commandToUse.add(0, "chroot"); + commandToUse.add(1, chroot); + } + + if (sudo != null) { + environmentVariables.put("SUDO_ASKPASS", askPassProgram); + commandToUse.add(0, "sudo"); + commandToUse.add(1, "-p"); + commandToUse.add(2, sudoPrompt); + if (!sudo.trim().equals("")) { + commandToUse.add(3, "-u"); + commandToUse.add(4, sudo); + } + } + + // GENERATE COMMAND LINE + commandLine = new CommandLine(commandToUse.get(0).toString()); + + for (int i = 1; i < commandToUse.size(); i++) { + if (log.isTraceEnabled()) + log.debug(commandToUse.get(i)); + commandLine.addArgument(commandToUse.get(i).toString()); + } + } else { + // all cases covered previously + throw new UnsupportedException(); + } + + if (generateScript != null) { + File scriptFile = new File(getExecDirToUse() + File.separator + + generateScript); + try { + FileUtils.writeStringToFile(scriptFile, + (osConsole != null ? osConsole + " " : "") + + commandLine.toString()); + } catch (IOException e) { + throw new SlcException("Could not generate script " + + scriptFile, e); + } + commandLine = new CommandLine(scriptFile); + } else { + if (osConsole != null) + commandLine = CommandLine.parse(osConsole + " " + + commandLine.toString()); + } + + return commandLine; + } + + /** + * Creates a {@link PumpStreamHandler} which redirects streams to the custom + * logging mechanism. + */ + protected ExecuteStreamHandler createExecuteStreamHandler( + final Writer stdOutWriter, final OutputStream stdOutputStream, + final Writer stdErrWriter, final InputStream stdInStream) { + + // Log writers + OutputStream stdout = stdOutputStream != null ? stdOutputStream + : new LogOutputStream() { + protected void processLine(String line, int level) { + // if (firstLine) { + // if (sudo != null && callbackHandler != null + // && line.startsWith(sudoPrompt)) { + // try { + // PasswordCallback pc = new PasswordCallback( + // "sudo password", false); + // Callback[] cbs = { pc }; + // callbackHandler.handle(cbs); + // char[] pwd = pc.getPassword(); + // char[] arr = Arrays.copyOf(pwd, + // pwd.length + 1); + // arr[arr.length - 1] = '\n'; + // IOUtils.write(arr, stdInSink); + // stdInSink.flush(); + // } catch (Exception e) { + // throw new SlcException( + // "Cannot retrieve sudo password", e); + // } + // } + // firstLine = false; + // } + + if (line != null && !line.trim().equals("")) + logStdOut(line); + + if (stdOutWriter != null) + appendLineToFile(stdOutWriter, line); + } + }; + + OutputStream stderr = new LogOutputStream() { + protected void processLine(String line, int level) { + if (line != null && !line.trim().equals("")) + logStdErr(line); + if (stdErrWriter != null) + appendLineToFile(stdErrWriter, line); + } + }; + + PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(stdout, + stderr, stdInStream) { + + @Override + public void stop() throws IOException { + // prevents the method to block when joining stdin + if (stdInSink != null) + IOUtils.closeQuietly(stdInSink); + + super.stop(); + } + }; + return pumpStreamHandler; + } + + /** Creates the default {@link ExecuteResultHandler}. */ + protected ExecuteResultHandler createExecuteResultHandler( + final CommandLine commandLine) { + return new ExecuteResultHandler() { + + public void onProcessComplete(int exitValue) { + String msg = "System call '" + commandLine + + "' properly completed."; + if (log.isTraceEnabled()) + log.trace(msg); + if (testResult != null) { + forwardPath(testResult); + testResult.addResultPart(new SimpleResultPart( + TestStatus.PASSED, msg)); + } + releaseWatchdog(); + } + + public void onProcessFailed(ExecuteException e) { + + String msg = "System call '" + commandLine + "' failed."; + if (testResult != null) { + forwardPath(testResult); + testResult.addResultPart(new SimpleResultPart( + TestStatus.ERROR, msg, e)); + } else { + if (exceptionOnFailed) + throw new SlcException(msg, e); + else + log.error(msg, e); + } + releaseWatchdog(); + } + }; + } + + @Deprecated + protected void forwardPath(TestResult testResult) { + // TODO: allocate a TreeSPath + } + + /** + * Shortcut method getting the execDir to use + */ + protected String getExecDirToUse() { + try { + if (execDir != null) { + return execDir; + } + return System.getProperty("user.dir"); + } catch (Exception e) { + throw new SlcException("Cannot find exec dir", e); + } + } + + protected void logStdOut(String line) { + for (SystemCallOutputListener outputListener : outputListeners) + outputListener.newLine(this, line, false); + log(stdOutLogLevel, line); + } + + protected void logStdErr(String line) { + for (SystemCallOutputListener outputListener : outputListeners) + outputListener.newLine(this, line, true); + log(stdErrLogLevel, line); + } + + /** Log from the underlying streams. */ + protected void log(String logLevel, String line) { + // TODO optimize +// if (SecurityContextHolder.getContext().getAuthentication() == null) { +// SecurityContextHolder.getContext() +// .setAuthentication(authentication); +// } + + if ("ERROR".equals(logLevel)) + log.error(line); + else if ("WARN".equals(logLevel)) + log.warn(line); + else if ("INFO".equals(logLevel)) + log.info(line); + else if ("DEBUG".equals(logLevel)) + log.debug(line); + else if ("TRACE".equals(logLevel)) + log.trace(line); + else if (LOG_STDOUT.equals(logLevel)) + System.out.println(line); + else if ("System.err".equals(logLevel)) + System.err.println(line); + else + throw new SlcException("Unknown log level " + logLevel); + } + + /** Append line to a log file. */ + protected void appendLineToFile(Writer writer, String line) { + try { + writer.append(line).append('\n'); + } catch (IOException e) { + log.error("Cannot write to log file", e); + } + } + + /** Creates the writer for the output/err files. */ + protected Writer createWriter(Resource target, Boolean append) { + FileWriter writer = null; + try { + + final File file; + if (executionResources != null) + file = new File(executionResources.getAsOsPath(target, true)); + else + file = target.getFile(); + writer = new FileWriter(file, append); + } catch (IOException e) { + log.error("Cannot get file for " + target, e); + IOUtils.closeQuietly(writer); + } + return writer; + } + + /** Creates an outputstream for the output/err files. */ + protected OutputStream createOutputStream(Resource target) { + FileOutputStream out = null; + try { + + final File file; + if (executionResources != null) + file = new File(executionResources.getAsOsPath(target, true)); + else + file = target.getFile(); + out = new FileOutputStream(file, false); + } catch (IOException e) { + log.error("Cannot get file for " + target, e); + IOUtils.closeQuietly(out); + } + return out; + } + + /** Append the argument (for chaining) */ + public SystemCall arg(String arg) { + if (command == null) + command = new ArrayList(); + command.add(arg); + return this; + } + + /** Append the argument (for chaining) */ + public SystemCall arg(String arg, String value) { + if (command == null) + command = new ArrayList(); + command.add(arg); + command.add(value); + return this; + } + + // CONTROL + public synchronized Boolean isRunning() { + return currentWatchdog != null; + } + + private synchronized ExecuteWatchdog createWatchdog() { +// if (currentWatchdog != null) +// throw new SlcException("A process is already being monitored"); + currentWatchdog = new ExecuteWatchdog(watchdogTimeout); + return currentWatchdog; + } + + private synchronized void releaseWatchdog() { + currentWatchdog = null; + } + + public synchronized void kill() { + if (currentWatchdog != null) + currentWatchdog.destroyProcess(); + } + + /** */ + public void setCmd(String command) { + this.cmd = command; + } + + public void setCommand(List command) { + this.command = command; + } + + public void setExecDir(String execdir) { + this.execDir = execdir; + } + + public void setStdErrLogLevel(String stdErrLogLevel) { + this.stdErrLogLevel = stdErrLogLevel; + } + + public void setStdOutLogLevel(String stdOutLogLevel) { + this.stdOutLogLevel = stdOutLogLevel; + } + + public void setSynchronous(Boolean synchronous) { + this.synchronous = synchronous; + } + + public void setOsCommands(Map> osCommands) { + this.osCommands = osCommands; + } + + public void setOsCmds(Map osCmds) { + this.osCmds = osCmds; + } + + public void setEnvironmentVariables(Map environmentVariables) { + this.environmentVariables = environmentVariables; + } + + public Map getEnvironmentVariables() { + return environmentVariables; + } + + public void setWatchdogTimeout(Long watchdogTimeout) { + this.watchdogTimeout = watchdogTimeout; + } + + public void setStdOutFile(Resource stdOutFile) { + this.stdOutFile = stdOutFile; + } + + public void setStdErrFile(Resource stdErrFile) { + this.stdErrFile = stdErrFile; + } + + public void setStdInFile(Resource stdInFile) { + this.stdInFile = stdInFile; + } + + public void setTestResult(TestResult testResult) { + this.testResult = testResult; + } + + public void setLogCommand(Boolean logCommand) { + this.logCommand = logCommand; + } + + public void setRedirectStreams(Boolean redirectStreams) { + this.redirectStreams = redirectStreams; + } + + public void setExceptionOnFailed(Boolean exceptionOnFailed) { + this.exceptionOnFailed = exceptionOnFailed; + } + + public void setMergeEnvironmentVariables(Boolean mergeEnvironmentVariables) { + this.mergeEnvironmentVariables = mergeEnvironmentVariables; + } + + public void setOsConsole(String osConsole) { + this.osConsole = osConsole; + } + + public void setGenerateScript(String generateScript) { + this.generateScript = generateScript; + } + + public void setExecutionResources(ExecutionResources executionResources) { + this.executionResources = executionResources; + } + + public void setRedirectStdOut(Boolean redirectStdOut) { + this.redirectStdOut = redirectStdOut; + } + + public void addOutputListener(SystemCallOutputListener outputListener) { + outputListeners.add(outputListener); + } + + public void removeOutputListener(SystemCallOutputListener outputListener) { + outputListeners.remove(outputListener); + } + + public void setOutputListeners( + List outputListeners) { + this.outputListeners = outputListeners; + } + + public void setExecutor(Executor executor) { + this.executor = executor; + } + + public void setSudo(String sudo) { + this.sudo = sudo; + } + + public void setCallbackHandler(CallbackHandler callbackHandler) { + this.callbackHandler = callbackHandler; + } + + public void setChroot(String chroot) { + this.chroot = chroot; + } + + private class DummyexecuteStreamHandler implements ExecuteStreamHandler { + + public void setProcessErrorStream(InputStream is) throws IOException { + } + + public void setProcessInputStream(OutputStream os) throws IOException { + } + + public void setProcessOutputStream(InputStream is) throws IOException { + } + + public void start() throws IOException { + } + + public void stop() { + } + + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/SystemCallOutputListener.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/SystemCallOutputListener.java new file mode 100644 index 000000000..b28f1ade2 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/SystemCallOutputListener.java @@ -0,0 +1,20 @@ +/* + * 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.core.execution.tasks; + +public interface SystemCallOutputListener { + public void newLine(SystemCall systemCall, String line, Boolean isError); +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/UploadAttachments.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/UploadAttachments.java new file mode 100644 index 000000000..13cc51918 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/UploadAttachments.java @@ -0,0 +1,85 @@ +/* + * 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.core.execution.tasks; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import org.argeo.slc.SlcException; +import org.argeo.slc.core.attachment.Attachment; +import org.argeo.slc.core.attachment.AttachmentUploader; +import org.argeo.slc.core.attachment.AttachmentsEnabled; +import org.springframework.core.io.Resource; + +public class UploadAttachments implements Runnable { + private AttachmentUploader attachmentUploader; + private Attachment attachment = null; + private Resource resource = null; + private Map attachments = new HashMap(); + private List attachTo = new ArrayList(); + private Boolean newUuidPerExecution = true; + + public void run() { + if (attachment != null) { + if (resource == null) + throw new SlcException("A resource must be specified."); + uploadAndAdd(attachment, resource); + } + + for (Attachment attachmentT : attachments.keySet()) { + Resource resourceT = attachments.get(attachmentT); + uploadAndAdd(attachmentT, resourceT); + } + + } + + protected void uploadAndAdd(Attachment attachment, Resource resource) { + if (newUuidPerExecution) + attachment.setUuid(UUID.randomUUID().toString()); + attachmentUploader.upload(attachment, resource); + for (AttachmentsEnabled attachmentsEnabled : attachTo) { + attachmentsEnabled.addAttachment(attachment); + } + } + + public void setAttachmentUploader(AttachmentUploader attachmentUploader) { + this.attachmentUploader = attachmentUploader; + } + + public void setAttachments(Map attachments) { + this.attachments = attachments; + } + + public void setAttachTo(List attachTo) { + this.attachTo = attachTo; + } + + public void setAttachment(Attachment attachment) { + this.attachment = attachment; + } + + public void setResource(Resource resource) { + this.resource = resource; + } + + public void setNewUuidPerExecution(Boolean newUuidPerExecution) { + this.newUuidPerExecution = newUuidPerExecution; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/core.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/core.xml new file mode 100644 index 000000000..df35944ee --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/tasks/core.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/templates.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/templates.xml new file mode 100644 index 000000000..28b742af7 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/templates.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/utils.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/utils.xml new file mode 100644 index 000000000..527e701f6 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/utils.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/AsFlowDecorator.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/AsFlowDecorator.java new file mode 100644 index 000000000..dceec1c5a --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/AsFlowDecorator.java @@ -0,0 +1,71 @@ +/* + * 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.core.execution.xml; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.DefaultExecutionFlow; +import org.argeo.slc.execution.ExecutionFlow; +import org.springframework.beans.BeanMetadataElement; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.xml.BeanDefinitionDecorator; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Attr; +import org.w3c.dom.Node; + +/** Publishes a {@link Runnable} as an {@link ExecutionFlow} */ +public class AsFlowDecorator implements BeanDefinitionDecorator { + private Log log = LogFactory.getLog(AsFlowDecorator.class); + + public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder bean, + ParserContext ctx) { + String attrValue = ((Attr) node).getValue(); + if (attrValue.charAt(attrValue.length() - 1) == '/') + throw new SlcException(attrValue + " cannot end with a path"); + final String flowBeanName = attrValue; + + if (log.isTraceEnabled()) + log.trace("flowBeanName=" + flowBeanName); + + if (ctx.getRegistry().containsBeanDefinition(flowBeanName)) + throw new SlcException("A bean named " + flowBeanName + + " is already defined."); + BeanDefinitionBuilder flow = BeanDefinitionBuilder + .rootBeanDefinition(DefaultExecutionFlow.class); + ManagedList executables = new ManagedList( + 1); + + String beanName = bean.getBeanName(); + if (beanName == null) + executables.add(bean.getBeanDefinition()); + else + executables.add(new RuntimeBeanReference(beanName)); + + // if (path != null) + // flow.addPropertyValue("path", path); + flow.addPropertyValue("executables", executables); + + if (beanName != null) + ctx.getRegistry().registerBeanDefinition(flowBeanName, + flow.getBeanDefinition()); + return bean; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/ExecutionScopeDecorator.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/ExecutionScopeDecorator.java new file mode 100644 index 000000000..dfca9d512 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/ExecutionScopeDecorator.java @@ -0,0 +1,52 @@ +/* + * 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.core.execution.xml; + +import org.springframework.aop.scope.ScopedProxyUtils; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.xml.BeanDefinitionDecorator; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Inspired by org.springframework.aop.config.ScopedProxyBeanDefinitionDecorator + */ +public class ExecutionScopeDecorator implements BeanDefinitionDecorator { + private static final String PROXY_TARGET_CLASS = "proxy-target-class"; + + public BeanDefinitionHolder decorate(Node node, + BeanDefinitionHolder definition, ParserContext parserContext) { + + definition.getBeanDefinition().setScope("execution"); + + // Default: CGLib not used + boolean proxyTargetClass = false; + if (node instanceof Element) { + Element ele = (Element) node; + if (ele.hasAttribute(PROXY_TARGET_CLASS)) { + proxyTargetClass = Boolean.valueOf(ele.getAttribute(PROXY_TARGET_CLASS)).booleanValue(); + } + } + + // Register the original bean definition as it will be referenced by the scoped proxy and is relevant for tooling (validation, navigation). + String targetBeanName = ScopedProxyUtils.getTargetBeanName(definition.getBeanName()); + parserContext.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(definition.getBeanDefinition(), targetBeanName)); + + return ScopedProxyUtils.createScopedProxy(definition, parserContext.getRegistry(), proxyTargetClass); + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/FlowBeanDefinitionParser.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/FlowBeanDefinitionParser.java new file mode 100644 index 000000000..7d2ab49a1 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/FlowBeanDefinitionParser.java @@ -0,0 +1,182 @@ +/* + * 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.core.execution.xml; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.DefaultExecutionFlow; +import org.argeo.slc.execution.ExecutionFlow; +import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** Interprets the tag */ +public class FlowBeanDefinitionParser extends + AbstractSingleBeanDefinitionParser { + private Log log = LogFactory.getLog(FlowBeanDefinitionParser.class); + + /** Whether the user has already be warned on path attribute usage. */ + private Boolean warnedAboutPathAttribute = false; + + @Override + protected void doParse(Element element, ParserContext parserContext, + BeanDefinitionBuilder builder) { + String path = element.getAttribute("path"); + if (StringUtils.hasText(path)) { + builder.addPropertyValue("path", path); + + // warns user only once + if (!warnedAboutPathAttribute) + log.warn("The path=\"\" attribute is deprecated" + + " and will be removed in a later release." + + " Use ."); + warnedAboutPathAttribute = true; + } + + String spec = element.getAttribute("spec"); + if (StringUtils.hasText(spec)) + builder.getBeanDefinition().getConstructorArgumentValues() + .addGenericArgumentValue(new RuntimeBeanReference(spec)); + + String abstrac = element.getAttribute("abstract"); + if (StringUtils.hasText(abstrac)) + builder.setAbstract(Boolean.parseBoolean(abstrac)); + + String parent = element.getAttribute("parent"); + if (StringUtils.hasText(parent)) + builder.setParentName(parent); + + builder.getBeanDefinition().setDescription( + DomUtils.getChildElementValueByTagName(element, "description")); + + List argsElems = new ArrayList(); + List execElems = new ArrayList(); + List specElems = new ArrayList(); + NodeList nodeList = element.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + Node node = nodeList.item(i); + if (node instanceof Element) { + if (DomUtils.nodeNameEquals(node, "arg")) + argsElems.add((Element) node); + else if (DomUtils.nodeNameEquals(node, "spec")) + specElems.add((Element) node); + else if (!DomUtils.nodeNameEquals(node, "description")) + execElems.add((Element) node); + } + } + + // Arguments + if (argsElems.size() != 0) { + ManagedMap args = new ManagedMap( + argsElems.size()); + for (Element argElem : argsElems) { + Object value = NamespaceUtils.parseValue(argElem, + parserContext, builder.getBeanDefinition(), null); + if (value != null) + args.put(argElem.getAttribute("name"), value); + else + throw new SlcException("No value defined."); + } + builder.getBeanDefinition().getConstructorArgumentValues() + .addGenericArgumentValue(args); + } + + // Execution specs + if (StringUtils.hasText(spec) && specElems.size() != 0) + throw new SlcException("A flow cannot have multiple specs"); + if (specElems.size() == 1) { + Object specObj = NamespaceUtils.parseBeanOrReference( + specElems.get(0), parserContext, + builder.getBeanDefinition()); + builder.getBeanDefinition().getConstructorArgumentValues() + .addGenericArgumentValue(specObj); + } else if (specElems.size() > 1) + throw new SlcException("A flow cannot have multiple specs"); + + // Executables + if (execElems.size() != 0) { + ManagedList executables = new ManagedList( + execElems.size()); + for (Element child : execElems) { + // child validity check is performed in xsd + executables.add(NamespaceUtils.parseBeanOrReference(child, + parserContext, builder.getBeanDefinition())); + } + if (executables.size() > 0) + builder.addPropertyValue("executables", executables); + } + } + + @SuppressWarnings("unchecked") + @Override + protected Class getBeanClass(Element element) { + String clss = element.getAttribute("class"); + if (StringUtils.hasText(clss)) + // TODO: check that it actually works + try { + return (Class) getClass() + .getClassLoader().loadClass(clss); + } catch (ClassNotFoundException e) { + try { + return (Class) Thread + .currentThread().getContextClassLoader() + .loadClass(clss); + } catch (ClassNotFoundException e1) { + throw new SlcException("Cannot load class " + clss, e); + } + } + else + return DefaultExecutionFlow.class; + } + + // parse nested bean definition + // private Object parseBeanReference(Element element, + // ParserContext parserContext, BeanDefinitionBuilder builder) { + // return parserContext.getDelegate().parsePropertySubElement(element, + // builder.getBeanDefinition()); + // } + + @Override + protected String resolveId(Element element, + AbstractBeanDefinition definition, ParserContext parserContext) + throws BeanDefinitionStoreException { + String name = element.getAttribute("name"); + if (StringUtils.hasText(name)) { + return name; + } else { + return super.resolveId(element, definition, parserContext); + } + } + + protected boolean shouldGenerateIdAsFallback() { + return true; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/FlowNamespaceHandler.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/FlowNamespaceHandler.java new file mode 100644 index 000000000..2deba8bb2 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/FlowNamespaceHandler.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.core.execution.xml; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +public class FlowNamespaceHandler extends NamespaceHandlerSupport { + + public void init() { + registerBeanDefinitionParser("flow", new FlowBeanDefinitionParser()); + registerBeanDefinitionParser("spec", new SpecBeanDefinitionParser()); + registerBeanDefinitionDecoratorForAttribute("as-flow", + new AsFlowDecorator()); + registerBeanDefinitionParser("param", new ParamDecorator()); + + // The objective was to replace + // - attribute scope="execution" + // - and element "aop:scoped-proxy" + // by a single attribute, using an attribute decorator + // this does not work correctly with other attribute decorators (e.g. + // p namespace) since this decorator needs to be called after all + // properties have been set on target bean. + // It works properly with element decorators (called after all attribute + // decorators + registerBeanDefinitionDecorator("variable", new ExecutionScopeDecorator()); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/NamespaceUtils.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/NamespaceUtils.java new file mode 100644 index 000000000..ccf94f131 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/NamespaceUtils.java @@ -0,0 +1,107 @@ +/* + * 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.core.execution.xml; + +import org.argeo.slc.SlcException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Utilities to simplify common tasks when interpreting a custom namespace and + * converting it into bean definitions. + */ +public class NamespaceUtils { + // private final static Log log = LogFactory.getLog(NamespaceUtils.class); + + /** + * Returns the value defined either: directly by the the 'value' attribute, + * as reference by the 'ref' attribute or as a nested bean. + */ + public static Object parseValue(Element element, + ParserContext parserContext, + BeanDefinition containingBeanDefintion, String valueTagName) { + Object value = null; + if (element.hasAttribute("value")) { + value = element.getAttribute("value"); + } + + if (element.hasAttribute("ref")) { + if (value != null) + throw new SlcException("Multiple value definition for " + + element); + value = new RuntimeBeanReference(element.getAttribute("ref")); + } + + Element uniqueSubElem = null; + if (valueTagName != null) { + Element valueElem = DomUtils.getChildElementByTagName(element, + valueTagName); + if (valueElem != null) { + uniqueSubElem = findUniqueSubElement(valueElem); + if (uniqueSubElem == null) + throw new SlcException("No subelement found under " + + valueElem); + } + } else {// no intermediary tag + uniqueSubElem = findUniqueSubElement(element); + } + + if (uniqueSubElem != null) { + if (value != null) + throw new SlcException("Multiple value definition for " + + element); + value = parseBeanOrReference(uniqueSubElem, parserContext, + containingBeanDefintion); + } + return value; + } + + public static Element findUniqueSubElement(Element element) { + NodeList childNodes = element.getChildNodes(); + + Element uniqueSubElem = null; + for (int i = 0; i < childNodes.getLength(); i++) { + Node node = childNodes.item(i); + if (node != null && node instanceof Element) { + if (uniqueSubElem == null) + uniqueSubElem = (Element) node; + else + throw new SlcException( + "There are more than one sub element under " + + element); + } + } + return uniqueSubElem; + } + + public static Object parseBeanOrReference(Element element, + ParserContext parserContext, BeanDefinition beanDefinition) { + // return parserContext.getDelegate().parsePropertySubElement(element, + // beanDefinition); + + BeanDefinitionParserDelegate deleg = parserContext.getDelegate(); + // if ("bean".equals(element.getNodeName())) + // return deleg.parseBeanDefinitionElement(element, beanDefinition); + // else + return deleg.parsePropertySubElement(element, beanDefinition); + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/ParamDecorator.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/ParamDecorator.java new file mode 100644 index 000000000..16839c042 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/ParamDecorator.java @@ -0,0 +1,61 @@ +/* + * 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.core.execution.xml; + +import org.argeo.slc.core.execution.ParameterRef; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.w3c.dom.Element; + +public class ParamDecorator extends AbstractSingleBeanDefinitionParser { + + // public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder + // bean, + // ParserContext ctx) { + // String paramName = ((Element) node).getAttribute("name"); + // String propertyName = ((Element) node.getParentNode()) + // .getAttribute("name"); + // BeanDefinitionBuilder parameterRef = BeanDefinitionBuilder + // .genericBeanDefinition(ParameterRef.class); + // parameterRef.addPropertyReference("instantiationManager", + // "instantiationManager"); + // parameterRef.addConstructorArgValue(paramName); + // bean.getBeanDefinition().getPropertyValues().addPropertyValue( + // propertyName, parameterRef.getBeanDefinition()); + // return bean; + // } + + @Override + protected void doParse(Element element, ParserContext parserContext, + BeanDefinitionBuilder builder) { + String paramName = element.getAttribute("name"); + + String instantationManagerRef = element + .getAttribute("instantiationManager"); + if (!StringUtils.hasText(instantationManagerRef)) + instantationManagerRef = "instantiationManager"; + builder.addPropertyReference("instantiationManager", + instantationManagerRef); + builder.addConstructorArgValue(paramName); + } + + @Override + protected Class getBeanClass(Element element) { + return ParameterRef.class; + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/SpecBeanDefinitionParser.java b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/SpecBeanDefinitionParser.java new file mode 100644 index 000000000..761e26dd1 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/SpecBeanDefinitionParser.java @@ -0,0 +1,146 @@ +/* + * 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.core.execution.xml; + +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.core.execution.DefaultExecutionSpec; +import org.argeo.slc.core.execution.PrimitiveSpecAttribute; +import org.argeo.slc.core.execution.RefSpecAttribute; +import org.argeo.slc.core.execution.RefValueChoice; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.ManagedMap; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +/** Interprets the tag */ +public class SpecBeanDefinitionParser extends + AbstractSingleBeanDefinitionParser { + private Log log = LogFactory.getLog(SpecBeanDefinitionParser.class); + + @Override + protected void doParse(Element element, ParserContext parserContext, + BeanDefinitionBuilder builder) { + builder.getBeanDefinition().setDescription( + DomUtils.getChildElementValueByTagName(element, "description")); + + ManagedMap attributes = new ManagedMap(); + + // Primitives + for (Element child : (List) DomUtils + .getChildElementsByTagName(element, "primitive")) { + BeanDefinitionBuilder childBuilder = BeanDefinitionBuilder + .genericBeanDefinition(PrimitiveSpecAttribute.class); + addCommonProperties(child, parserContext, childBuilder); + + String type = child.getAttribute("type"); + if (StringUtils.hasText(type)) + childBuilder.addPropertyValue("type", type); + + putInAttributes(attributes, child, + childBuilder.getBeanDefinition(), "primitive"); + } + + // Refs + for (Element refAttrElem : (List) DomUtils + .getChildElementsByTagName(element, "ref")) { + BeanDefinitionBuilder refAttrBuilder = BeanDefinitionBuilder + .genericBeanDefinition(RefSpecAttribute.class); + addCommonProperties(refAttrElem, parserContext, refAttrBuilder); + + String targetClassName = refAttrElem.getAttribute("targetClass"); + if (StringUtils.hasText(targetClassName)) + refAttrBuilder.addPropertyValue("targetClass", targetClassName); + + // Choices + Element choicesElem = DomUtils.getChildElementByTagName( + refAttrElem, "choices"); + if (choicesElem != null) { + List choices = DomUtils.getChildElementsByTagName( + choicesElem, "choice"); + ManagedList choiceBeans = new ManagedList( + choices.size()); + for (Element choiceElem : choices) { + BeanDefinitionBuilder choiceBuilder = BeanDefinitionBuilder + .genericBeanDefinition(RefValueChoice.class); + choiceBuilder.addPropertyValue("name", + choiceElem.getAttribute("name")); + String desc = choiceElem.getAttribute("description"); + if (StringUtils.hasText(desc)) + choiceBuilder.addPropertyValue("description", desc); + + choiceBeans.add(choiceBuilder.getBeanDefinition()); + } + refAttrBuilder.addPropertyValue("choices", choiceBeans); + } + + putInAttributes(attributes, refAttrElem, + refAttrBuilder.getBeanDefinition(), "ref"); + } + + builder.addPropertyValue("attributes", attributes); + } + + protected void addCommonProperties(Element element, + ParserContext parserContext, BeanDefinitionBuilder specAttr) { + addBooleanProperty("isImmutable", specAttr, element); + addBooleanProperty("isConstant", specAttr, element); + addBooleanProperty("isHidden", specAttr, element); + addBooleanProperty("isParameter", specAttr, element); + addBooleanProperty("isFrozen", specAttr, element); + + Object value = NamespaceUtils.parseValue(element, parserContext, + specAttr.getBeanDefinition(), "value"); + if (value != null) + specAttr.addPropertyValue("value", value); + + } + + protected void putInAttributes( + ManagedMap attributes, Element child, + BeanDefinition beanDefinition, String nature) { + String name = child.getAttribute("name"); + attributes.put(name, beanDefinition); + if (log.isTraceEnabled()) + log.debug("Added " + nature + " attribute " + name); + + } + + private void addBooleanProperty(String name, + BeanDefinitionBuilder specAttr, Element element) { + String bool = element.getAttribute(name); + if (StringUtils.hasText(bool)) + specAttr.addPropertyValue(name, Boolean.parseBoolean(bool)); + + } + + @Override + protected Class getBeanClass(Element element) { + return DefaultExecutionSpec.class; + } + + protected boolean shouldGenerateIdAsFallback() { + return false; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd new file mode 100644 index 000000000..8b31a60bf --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/slc-flow-0.12.xsd @@ -0,0 +1,384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd new file mode 100644 index 000000000..a70798f2d --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/execution/xml/slc-flow-1.2.xsd @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/BasicTestData.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/BasicTestData.java new file mode 100644 index 000000000..39a97f290 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/BasicTestData.java @@ -0,0 +1,40 @@ +/* + * 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.core.test; + +import org.argeo.slc.test.TestData; + +public class BasicTestData implements TestData { + private Object expected; + private Object reached; + + public Object getExpected() { + return expected; + } + + public void setExpected(Object expected) { + this.expected = expected; + } + + public Object getReached() { + return reached; + } + + public void setReached(Object reached) { + this.reached = reached; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/BasicTestDefinition.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/BasicTestDefinition.java new file mode 100644 index 000000000..6b92135e8 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/BasicTestDefinition.java @@ -0,0 +1,61 @@ +/* + * 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.core.test; + +import org.argeo.slc.SlcException; +import org.argeo.slc.core.test.context.ContextUtils; +import org.argeo.slc.test.IncompatibleTestDataException; +import org.argeo.slc.test.TestData; +import org.argeo.slc.test.TestDefinition; +import org.argeo.slc.test.TestResult; +import org.argeo.slc.test.TestRun; +import org.argeo.slc.test.TestStatus; +import org.argeo.slc.test.context.ContextAware; + +/** Understands basic test data and context aware test data. */ +public class BasicTestDefinition implements TestDefinition { + + public void execute(TestRun testRun) { + if (testRun. getTestData() instanceof BasicTestData) { + BasicTestData testData = testRun.getTestData(); + TestResult result = testRun.getTestResult(); + + if (result == null) + throw new SlcException("No test result defined."); + + try { + if (testData.getExpected().equals(testData.getReached())) { + result.addResultPart(new SimpleResultPart( + TestStatus.PASSED, "Reached and expected equals")); + } else { + result.addResultPart(new SimpleResultPart( + TestStatus.FAILED, "Expected " + + testData.getExpected() + " but reached " + + testData.getReached())); + } + } catch (Exception e) { + result.addResultPart(new SimpleResultPart(TestStatus.ERROR, + "Could not compare", e)); + } + } else if (testRun. getTestData() instanceof ContextAware) { + TestData testData = testRun.getTestData(); + ContextUtils.compareReachedExpected((ContextAware) testData, + testRun.getTestResult()); + } else { + throw new IncompatibleTestDataException(testRun); + } + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleResultPart.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleResultPart.java new file mode 100644 index 000000000..8ad81af1c --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleResultPart.java @@ -0,0 +1,150 @@ +/* + * 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.core.test; + +import java.io.Serializable; + +import org.argeo.slc.test.TestResultPart; +import org.argeo.slc.test.TestRun; +import org.argeo.slc.test.TestRunAware; +import org.argeo.slc.test.TestStatus; + +/** + *

+ * Basic implementation of a result part, implementing the standard three status + * approach for test results. + *

+ * + * @see TestStatus + */ +public class SimpleResultPart implements TestResultPart, TestStatus, + TestRunAware, Serializable { + private static final long serialVersionUID = 6669675957685071901L; + + private Long tid; + + private String testRunUuid; + + /** The status. Default to ERROR since it should always be explicitely set. */ + private Integer status = ERROR; + private String message; + private String exceptionMessage; + + public SimpleResultPart() { + } + + public SimpleResultPart(Integer status, String message) { + this(status, message, null); + } + + public SimpleResultPart(Integer status, String message, Exception exception) { + this.status = status; + this.message = message; + setException(exception); + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public Integer getStatus() { + return status; + } + + public String getExceptionMessage() { + return exceptionMessage; + } + + public void setException(Exception exception) { + if (exception == null) + return; + + StringBuffer buf = new StringBuffer(""); + buf.append(exception.toString()); + buf.append('\n'); + for (StackTraceElement elem : exception.getStackTrace()) { + buf.append('\t').append(elem.toString()).append('\n'); + } + + if (exception.getCause() != null) + addRootCause(buf, exception.getCause()); + + this.exceptionMessage = buf.toString(); + } + + protected void addRootCause(StringBuffer buf, Throwable cause) { + if (cause == null) + return; + + buf.append("Caused by: " + cause.getMessage()); + for (StackTraceElement elem : cause.getStackTrace()) { + buf.append('\t').append(elem.toString()).append('\n'); + } + + if (cause.getCause() != null) { + addRootCause(buf, cause.getCause()); + } + } + + @Override + public String toString() { + StringBuffer buf = new StringBuffer(""); + buf.append(SlcTestUtils.statusToString(status)); + if (status == PASSED || status == FAILED) { + buf.append(' '); + } else if (status == ERROR) { + buf.append(" "); + } + buf.append(message); + return buf.toString(); + } + + /** @deprecated */ + Long getTid() { + return tid; + } + + /** @deprecated */ + void setTid(Long tid) { + this.tid = tid; + } + + public String getTestRunUuid() { + return testRunUuid; + } + + /** For ORM */ + public void setTestRunUuid(String testRunUuid) { + this.testRunUuid = testRunUuid; + } + + public void notifyTestRun(TestRun testRun) { + testRunUuid = testRun.getUuid(); + } + + public void setExceptionMessage(String exceptionMessage) { + this.exceptionMessage = exceptionMessage; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleTestResult.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleTestResult.java new file mode 100644 index 000000000..93306a5b4 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleTestResult.java @@ -0,0 +1,103 @@ +/* + * 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.core.test; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.test.TestResult; +import org.argeo.slc.test.TestResultPart; +import org.argeo.slc.test.TestRun; + +/** + * Basic implementation of a test result containing only a list of result parts. + */ +public class SimpleTestResult implements TestResult { + private static Log log = LogFactory.getLog(SimpleTestResult.class); + + private String uuid; + private String currentTestRunUuid; + + private Boolean throwError = true; + + private Date closeDate; + private List parts = new Vector(); + + private Map attributes = new TreeMap(); + + public void addResultPart(TestResultPart part) { + if (throwError && part.getStatus() == ERROR) { + throw new SlcException( + "There was an error in the underlying test: " + + part.getExceptionMessage()); + } + parts.add(part); + if (log.isDebugEnabled()) + log.debug(part); + } + + public void close() { + parts.clear(); + closeDate = new Date(); + } + + public List getParts() { + return parts; + } + + public Date getCloseDate() { + return closeDate; + } + + public void setThrowError(Boolean throwError) { + this.throwError = throwError; + } + + public void notifyTestRun(TestRun testRun) { + currentTestRunUuid = testRun.getUuid(); + } + + public String getUuid() { + if (uuid == null) { + uuid = UUID.randomUUID().toString(); + } + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getCurrentTestRunUuid() { + return currentTestRunUuid; + } + + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleTestRun.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleTestRun.java new file mode 100644 index 000000000..4f6a12f81 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SimpleTestRun.java @@ -0,0 +1,110 @@ +/* + * 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.core.test; + +import java.util.UUID; + +import org.argeo.slc.deploy.DeployedSystem; +import org.argeo.slc.test.ExecutableTestRun; +import org.argeo.slc.test.TestData; +import org.argeo.slc.test.TestDefinition; +import org.argeo.slc.test.TestResult; +import org.argeo.slc.test.WritableTestRun; + +/** + * A basic bean implementation of a WritableTestRun, holding + * references to the various parts of a test run. + */ +public class SimpleTestRun implements WritableTestRun, ExecutableTestRun { + private String uuid; + + // private String slcExecutionUuid; + // private String slcExecutionStepUuid; + + private DeployedSystem deployedSystem; + private TestData testData; + private TestDefinition testDefinition; + private TestResult testResult; + + /** Executes the underlying test definition. */ + public void run() { + uuid = UUID.randomUUID().toString(); + if (testResult != null) + testResult.notifyTestRun(this); + + testDefinition.execute(this); + } + + @SuppressWarnings("unchecked") + public T getDeployedSystem() { + return (T) deployedSystem; + } + + public void setDeployedSystem(DeployedSystem deployedSystem) { + this.deployedSystem = deployedSystem; + } + + @SuppressWarnings("unchecked") + public T getTestData() { + return (T) testData; + } + + public void setTestData(TestData testData) { + this.testData = testData; + } + + @SuppressWarnings("unchecked") + public T getTestDefinition() { + return (T) testDefinition; + } + + public void setTestDefinition(TestDefinition testDefinition) { + this.testDefinition = testDefinition; + } + + @SuppressWarnings("unchecked") + public T getTestResult() { + return (T) testResult; + } + + public void setTestResult(TestResult testResult) { + this.testResult = testResult; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + // public String getSlcExecutionUuid() { + // return slcExecutionUuid; + // } + // + // public void setSlcExecutionUuid(String slcExecutionUuid) { + // this.slcExecutionUuid = slcExecutionUuid; + // } + // + // public String getSlcExecutionStepUuid() { + // return slcExecutionStepUuid; + // } + // + // public void setSlcExecutionStepUuid(String slcExecutionStepUuid) { + // this.slcExecutionStepUuid = slcExecutionStepUuid; + // } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/SlcTestUtils.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SlcTestUtils.java new file mode 100644 index 000000000..c926a691d --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/SlcTestUtils.java @@ -0,0 +1,50 @@ +/* + * 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.core.test; + +import org.argeo.slc.SlcException; +import org.argeo.slc.test.TestStatus; + +public abstract class SlcTestUtils { + public static String statusToString(Integer status) { + if (status.equals(TestStatus.PASSED)) { + return TestStatus.STATUSSTR_PASSED; + } else if (status.equals(TestStatus.FAILED)) { + return TestStatus.STATUSSTR_FAILED; + } else if (status.equals(TestStatus.ERROR)) { + return TestStatus.STATUSSTR_ERROR; + } else { + throw new SlcException("Unrecognized status " + status); + } + } + + public static Integer stringToStatus(String statusStr) { + if (statusStr.equals(TestStatus.STATUSSTR_PASSED)) { + return TestStatus.PASSED; + } else if (statusStr.equals(TestStatus.STATUSSTR_FAILED)) { + return TestStatus.FAILED; + } else if (statusStr.equals(TestStatus.STATUSSTR_ERROR)) { + return TestStatus.ERROR; + } else { + throw new SlcException("Unrecognized status string " + statusStr); + } + } + + private SlcTestUtils() { + + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/TestDataUtils.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/TestDataUtils.java new file mode 100644 index 000000000..b32da3801 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/TestDataUtils.java @@ -0,0 +1,63 @@ +/* + * 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.core.test; + +import org.argeo.slc.UnsupportedException; +import org.argeo.slc.test.TestData; +import org.argeo.slc.test.TestDataProvider; + +/** Utilities for dealing with test datas. */ +public class TestDataUtils { + /** Extracts the test data from the given provider. */ + public static T getFromProvider(Object obj, + Class clss, String key) { + if (obj instanceof TestDataProvider) { + TestDataProvider testDataProvider = (TestDataProvider) obj; + return testDataProvider.getTestData(clss, key); + } else { + throw new UnsupportedException("test data provider", obj); + } + } + + /** + * Extracts the test data from the given provider using null + * as key. + */ + public static T getFromProvider(Object obj, + Class clss) { + return getFromProvider(obj, clss, null); + } + + /** + * Returns it self after making the proper checks. Used for test data being + * their own data providers. + */ + @SuppressWarnings("unchecked") + public static T getItSelf(Class clss, + TestData testDataObject) { + if (clss.isAssignableFrom(testDataObject.getClass())) { + return (T) testDataObject; + } else { + throw new UnsupportedException("test data", testDataObject); + } + + } + + /** Makes sure this is an utility class. */ + private TestDataUtils() { + + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/ContextUtils.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/ContextUtils.java new file mode 100644 index 000000000..f62fb5ca3 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/ContextUtils.java @@ -0,0 +1,140 @@ +/* + * 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.core.test.context; + +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.core.test.SimpleResultPart; +import org.argeo.slc.test.TestResult; +import org.argeo.slc.test.TestStatus; +import org.argeo.slc.test.context.ContextAware; +import org.argeo.slc.test.context.ParentContextAware; + +/** Utilities for comparing and synchronising contexts. */ +public class ContextUtils { + private final static Log log = LogFactory.getLog(ContextUtils.class); + + public static void compareReachedExpected(ContextAware contextAware, + TestResult testResult) { + for (String key : contextAware.getExpectedValues().keySet()) { + + // Compare expected values with reached ones + Object expectedValue = contextAware.getExpectedValues().get(key); + + if (expectedValue.toString().equals( + contextAware.getContextSkipFlag())) { + if (log.isDebugEnabled()) + log.debug("Skipped check for key '" + key + "'"); + continue; + } + + if (contextAware.getValues().containsKey(key)) { + Object reachedValue = contextAware.getValues().get(key); + + if (expectedValue.equals(contextAware.getContextAnyFlag())) { + testResult.addResultPart(new SimpleResultPart( + TestStatus.PASSED, "Expected any value for key '" + + key + "'")); + } else if (expectedValue.equals(reachedValue)) { + testResult.addResultPart(new SimpleResultPart( + TestStatus.PASSED, "Values matched for key '" + key + + "'")); + } else { + testResult.addResultPart(new SimpleResultPart( + TestStatus.FAILED, "Mismatch for key '" + key + + "': expected '" + expectedValue + + "' but reached '" + reachedValue + "'")); + } + } else { + testResult.addResultPart(new SimpleResultPart( + TestStatus.FAILED, "No value reached for key '" + key + + "'")); + } + } + } + + /** + * Makes sure that all children and sub-children of parent share the same + * maps for values and expected values. + */ + public static void synchronize(ParentContextAware parent) { + Map expectedValuesCommon = new TreeMap( + parent.getExpectedValues()); + synchronize(parent, expectedValuesCommon); + if (log.isDebugEnabled()) + log.debug("Synchronized context " + parent); + + } + + private static void synchronize(ParentContextAware parent, + Map expectedValuesCommon) { + for (ContextAware child : parent.getChildContexts()) { + // Values + putNotContained(parent.getValues(), child.getValues()); + child.setValues(parent.getValues()); + + // Expected Values + // Expected values reference is not overridden: each child has its + // own expected values map. + overrideContained(expectedValuesCommon, child.getExpectedValues()); + + // Creates a new Map in order not to disturb other context using the + // same keys + Map expectedValuesCommonChild = new TreeMap( + expectedValuesCommon); + putNotContained(expectedValuesCommonChild, + child.getExpectedValues()); + + if (child instanceof ParentContextAware) { + // Recursive sync + synchronize((ParentContextAware) child, + expectedValuesCommonChild); + } + } + + } + + /** + * Put into common map the values from child map which are not already + * defined in common map. + */ + public static void putNotContained(Map commonMap, + Map childMap) { + for (String key : childMap.keySet()) { + if (!commonMap.containsKey(key)) { + commonMap.put(key, childMap.get(key)); + } + } + } + + /** Overrides child map values with the values already set in common map */ + public static void overrideContained(Map commonMap, + Map childMap) { + for (String key : childMap.keySet()) { + if (commonMap.containsKey(key)) { + childMap.put(key, commonMap.get(key)); + } + } + } + + /** Makes sure this cannot be instantiated. */ + private ContextUtils() { + + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/DefaultContextTestData.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/DefaultContextTestData.java new file mode 100644 index 000000000..ca0bf5ffb --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/DefaultContextTestData.java @@ -0,0 +1,29 @@ +/* + * 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.core.test.context; + +import org.argeo.slc.core.test.TestDataUtils; +import org.argeo.slc.test.TestData; +import org.argeo.slc.test.TestDataProvider; + +public class DefaultContextTestData extends SimpleContextAware implements + TestData, TestDataProvider { + + public T getTestData(Class clss, String key) { + return TestDataUtils.getItSelf(clss, this); + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/SimpleContextAware.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/SimpleContextAware.java new file mode 100644 index 000000000..f10be5659 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/SimpleContextAware.java @@ -0,0 +1,85 @@ +/* + * 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.core.test.context; + +import java.util.Map; +import java.util.TreeMap; + +import org.argeo.slc.SlcException; +import org.argeo.slc.test.context.ContextAware; +import org.argeo.slc.test.context.ParentContextAware; +import org.springframework.beans.factory.InitializingBean; + +public class SimpleContextAware implements ContextAware, InitializingBean { + private ParentContextAware parentContext; + + private Map values = new TreeMap(); + private Map expectedValues = new TreeMap(); + + private String contextSkipFlag = DEFAULT_SKIP_FLAG; + private String contextAnyFlag = DEFAULT_ANY_FLAG; + + public Map getValues() { + return values; + } + + public void setValues(Map values) { + this.values = values; + } + + public Map getExpectedValues() { + return expectedValues; + } + + public void setExpectedValues(Map expectedValues) { + this.expectedValues = expectedValues; + } + + /** Used to add this context as a child by setting a property. */ + public void setParentContext(ParentContextAware parentContextAware) { + if (parentContext != null) + throw new SlcException("Parent context already set"); + this.parentContext = parentContextAware; + this.parentContext.addChildContext(this); + } + + protected ParentContextAware getParentContext() { + return parentContext; + } + + public void afterPropertiesSet() throws Exception { + if (parentContext != null) { + ContextUtils.synchronize(parentContext); + } + } + + public String getContextSkipFlag() { + return contextSkipFlag; + } + + public void setContextSkipFlag(String contextSkipFlag) { + this.contextSkipFlag = contextSkipFlag; + } + + public String getContextAnyFlag() { + return contextAnyFlag; + } + + public void setContextAnyFlag(String contextAnyFlag) { + this.contextAnyFlag = contextAnyFlag; + } + +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/SimpleParentContextAware.java b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/SimpleParentContextAware.java new file mode 100644 index 000000000..b8abf7fde --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/SimpleParentContextAware.java @@ -0,0 +1,50 @@ +/* + * 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.core.test.context; + +import java.util.Collection; +import java.util.List; +import java.util.Vector; + +import org.argeo.slc.test.context.ContextAware; +import org.argeo.slc.test.context.ParentContextAware; +import org.springframework.beans.factory.InitializingBean; + +public class SimpleParentContextAware extends SimpleContextAware implements + ParentContextAware, InitializingBean { + private List children = new Vector(); + + public Collection getChildContexts() { + return children; + } + + public void addChildContext(ContextAware contextAware) { + children.add(contextAware); + } + + @Override + public void afterPropertiesSet() throws Exception { + if (getParentContext() != null) { + // If has a parent, sync it. + super.afterPropertiesSet(); + } else { + if (children.size() > 0) { + // No need to synchronize if no children + ContextUtils.synchronize(this); + } + } + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/package.html b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/package.html new file mode 100644 index 000000000..cd08d63f3 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/context/package.html @@ -0,0 +1,6 @@ + + + +Context variables to be passed between parts of tests. + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/package.html b/org.argeo.slc.spring/src/org/argeo/slc/core/test/package.html new file mode 100644 index 000000000..c70d2d151 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/package.html @@ -0,0 +1,6 @@ + + + +SLC Test: test of software systems. + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/core/test/spring.xml b/org.argeo.slc.spring/src/org/argeo/slc/core/test/spring.xml new file mode 100644 index 000000000..31cf67167 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/core/test/spring.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/jcr/JcrMetadataWriter.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/JcrMetadataWriter.java new file mode 100644 index 000000000..c4922d325 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/jcr/JcrMetadataWriter.java @@ -0,0 +1,80 @@ +/* + * 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; +import org.argeo.slc.SlcNames; + +/** + * 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.spring/src/org/argeo/slc/jcr/JcrTestResult.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/JcrTestResult.java new file mode 100644 index 000000000..c9ec874ea --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/jcr/JcrTestResult.java @@ -0,0 +1,291 @@ +/* + * 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.SlcNames; +import org.argeo.slc.SlcTypes; +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.spring/src/org/argeo/slc/jcr/SlcJcrConstants.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/SlcJcrConstants.java new file mode 100644 index 000000000..3190c85b9 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/jcr/SlcJcrConstants.java @@ -0,0 +1,29 @@ +/* + * 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 org.argeo.slc.SlcNames; + +/** 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.spring/src/org/argeo/slc/jcr/SlcJcrResultUtils.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/SlcJcrResultUtils.java new file mode 100644 index 000000000..6353804df --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/jcr/SlcJcrResultUtils.java @@ -0,0 +1,168 @@ +/* + * 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.node.NodeUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.SlcNames; +import org.argeo.slc.SlcTypes; + +/** + * 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 = NodeUtils.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 = NodeUtils.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.spring/src/org/argeo/slc/jcr/SlcJcrUtils.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/SlcJcrUtils.java new file mode 100644 index 000000000..137e298be --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/jcr/SlcJcrUtils.java @@ -0,0 +1,268 @@ +/* + * 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.node.NodeUtils; +import org.argeo.slc.DefaultNameVersion; +import org.argeo.slc.NameVersion; +import org.argeo.slc.SlcException; +import org.argeo.slc.SlcNames; +import org.argeo.slc.SlcTypes; +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 DefaultNameVersion(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 = NodeUtils.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.spring/src/org/argeo/slc/jcr/execution/JcrAgent.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/execution/JcrAgent.java new file mode 100644 index 000000000..89b4530ac --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/jcr/execution/JcrAgent.java @@ -0,0 +1,131 @@ +/* + * 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 javax.jcr.security.Privilege; + +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcConstants; +import org.argeo.slc.SlcException; +import org.argeo.slc.SlcNames; +import org.argeo.slc.SlcTypes; +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; + +/** 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); + JcrUtils.addPrivilege(session, SlcJcrConstants.SLC_BASE_PATH, SlcConstants.ROLE_SLC, Privilege.JCR_ALL); + 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.spring/src/org/argeo/slc/jcr/execution/JcrAttachmentUploader.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/execution/JcrAttachmentUploader.java new file mode 100644 index 000000000..105d549cd --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java new file mode 100644 index 000000000..1a2576e06 --- /dev/null +++ b/org.argeo.slc.spring/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.SlcNames; +import org.argeo.slc.SlcTypes; +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; + +/** + * 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.spring/src/org/argeo/slc/jcr/execution/JcrExecutionProcess.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/execution/JcrExecutionProcess.java new file mode 100644 index 000000000..e1ad69e3b --- /dev/null +++ b/org.argeo.slc.spring/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.SlcNames; +import org.argeo.slc.SlcTypes; +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; + +/** 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.spring/src/org/argeo/slc/jcr/execution/JcrProcessThread.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/execution/JcrProcessThread.java new file mode 100644 index 000000000..a73e1a94a --- /dev/null +++ b/org.argeo.slc.spring/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.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.SlcNames; +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; + +/** 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 SlcException("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.spring/src/org/argeo/slc/jcr/execution/JcrRealizedFlow.java b/org.argeo.slc.spring/src/org/argeo/slc/jcr/execution/JcrRealizedFlow.java new file mode 100644 index 000000000..c371b1114 --- /dev/null +++ b/org.argeo.slc.spring/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.SlcNames; +import org.argeo.slc.SlcTypes; +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; + +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.spring/src/org/argeo/slc/osgi/BundleRegister.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/BundleRegister.java new file mode 100644 index 000000000..747785fee --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/osgi/BundlesManager.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/BundlesManager.java new file mode 100644 index 000000000..9877c31e6 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/osgi/BundlesManager.java @@ -0,0 +1,443 @@ +/* + * 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.Collection; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +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.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.springframework.util.Assert; + +/** Wraps low-level access to a {@link BundleContext} */ +@SuppressWarnings("deprecation") +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 + Collection> srs = getServiceRefSynchronous( + ApplicationContext.class, filter); + ServiceReference sr = srs.iterator().next(); + 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); + 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 Collection> getServiceRefSynchronous( + Class clss, String filter) throws InvalidSyntaxException { + if (log.isTraceEnabled()) + log.debug("Filter: '" + filter + "'"); + Collection> 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, + null); + st.open(); + return st; + } + + public T getSingleService(Class clss, String filter, + Boolean synchronous) { + if (filter != null) + Assert.isTrue(OsgiFilterUtils.isValidFilter(filter), "valid filter"); + Collection> sfs; + try { + if (synchronous) + sfs = getServiceRefSynchronous(clss, filter); + else + sfs = bundleContext.getServiceReferences(clss, filter); + } catch (InvalidSyntaxException e) { + throw new SlcException("Cannot retrieve service reference for " + + filter, e); + } + + if (sfs == null || sfs.size() == 0) + return null; + else if (sfs.size() > 1) + throw new SlcException("More than one execution flow found for " + + filter); + return (T) bundleContext.getService(sfs.iterator().next()); + } + + 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.spring/src/org/argeo/slc/osgi/FileSystemBundleRegister.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/FileSystemBundleRegister.java new file mode 100644 index 000000000..03f21c530 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/osgi/FileSystemBundleRegister.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.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.io.IOUtils; +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 { + JarFile jarFile = null; + try { + 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(); + } finally { + IOUtils.closeQuietly(jarFile); + } + } + } + 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.spring/src/org/argeo/slc/osgi/MultipleServiceExporterPostProcessor.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/MultipleServiceExporterPostProcessor.java new file mode 100644 index 000000000..2d8b0311c --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/osgi/OsgiBundle.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/OsgiBundle.java new file mode 100644 index 000000000..cb11615b6 --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/osgi/OsgiExecutionModule.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/OsgiExecutionModule.java new file mode 100644 index 000000000..df7ae9bc1 --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java new file mode 100644 index 000000000..046cfb646 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/osgi/OsgiExecutionModulesManager.java @@ -0,0 +1,701 @@ +/* + * 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.eclipse.gemini.blueprint.service.importer.OsgiServiceLifecycleListener; +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; + +/** 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, 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) { + // FIXME why are properties null? + if (properties == null) + return; + 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) { + // FIXME why are properties null? + if (properties == null) + return; + 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); + } + } + + 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.spring/src/org/argeo/slc/osgi/OsgiExecutionResources.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/OsgiExecutionResources.java new file mode 100644 index 000000000..306ad07a8 --- /dev/null +++ b/org.argeo.slc.spring/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.eclipse.gemini.blueprint.context.BundleContextAware; +import org.eclipse.gemini.blueprint.io.OsgiBundleResource; +import org.osgi.framework.BundleContext; +import org.springframework.core.io.Resource; + +/** 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.spring/src/org/argeo/slc/osgi/OsgiRuntime.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/OsgiRuntime.java new file mode 100644 index 000000000..8286eccd5 --- /dev/null +++ b/org.argeo.slc.spring/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.eclipse.gemini.blueprint.context.BundleContextAware; +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; + +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.spring/src/org/argeo/slc/osgi/build/AbstractOsgiModularDistribution.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/build/AbstractOsgiModularDistribution.java new file mode 100644 index 000000000..c76659f09 --- /dev/null +++ b/org.argeo.slc.spring/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.eclipse.gemini.blueprint.context.BundleContextAware; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.springframework.beans.factory.InitializingBean; + +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.spring/src/org/argeo/slc/osgi/build/BundleModularDistribution.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/build/BundleModularDistribution.java new file mode 100644 index 000000000..db7c7e8a1 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/osgi/build/BundleModularDistribution.java @@ -0,0 +1,96 @@ +/* + * 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"; + + 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.spring/src/org/argeo/slc/osgi/build/EclipseUpdateSite.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/build/EclipseUpdateSite.java new file mode 100644 index 000000000..e38d9c024 --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/osgi/build/EclipseUpdateSiteCategory.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/build/EclipseUpdateSiteCategory.java new file mode 100644 index 000000000..c71656236 --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/osgi/build/EclipseUpdateSiteFeature.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/build/EclipseUpdateSiteFeature.java new file mode 100644 index 000000000..f28c0cb12 --- /dev/null +++ b/org.argeo.slc.spring/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.spring/src/org/argeo/slc/osgi/build/OsgiRuntimeModularDistribution.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/build/OsgiRuntimeModularDistribution.java new file mode 100644 index 000000000..5523e6efe --- /dev/null +++ b/org.argeo.slc.spring/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.eclipse.gemini.blueprint.util.OsgiBundleUtils; +import org.osgi.framework.Bundle; +import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; + +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.spring/src/org/argeo/slc/osgi/deploy/OsgiResourceSet.java b/org.argeo.slc.spring/src/org/argeo/slc/osgi/deploy/OsgiResourceSet.java new file mode 100644 index 000000000..2414788c8 --- /dev/null +++ b/org.argeo.slc.spring/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.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; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.springframework.core.io.ResourceLoader; + +/** + * 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.spring/src/org/argeo/slc/osgi/execution.xml b/org.argeo.slc.spring/src/org/argeo/slc/osgi/execution.xml new file mode 100644 index 000000000..cc0aac069 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/osgi/execution.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/org.argeo.slc.spring/src/org/argeo/slc/spring/AbstractSystemExecution.java b/org.argeo.slc.spring/src/org/argeo/slc/spring/AbstractSystemExecution.java new file mode 100644 index 000000000..7813b9a5f --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/spring/AbstractSystemExecution.java @@ -0,0 +1,64 @@ +/* + * 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.spring; + +import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.node.NodeConstants; +import org.argeo.slc.SlcException; + +/** Provides base method for executing code with system authorization. */ +abstract class AbstractSystemExecution { + private final static Log log = LogFactory.getLog(AbstractSystemExecution.class); + private final Subject subject = new Subject(); + + /** Authenticate the calling thread */ + protected void authenticateAsSystem() { + ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + try { + LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN, subject); + lc.login(); + } catch (LoginException e) { + throw new SlcException("Cannot login as system", e); + } finally { + Thread.currentThread().setContextClassLoader(origClassLoader); + } + if (log.isTraceEnabled()) + log.trace("System authenticated"); + } + + protected void deauthenticateAsSystem() { + ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + try { + LoginContext lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_DATA_ADMIN, subject); + lc.logout(); + } catch (LoginException e) { + throw new SlcException("Cannot logout as system", e); + } finally { + Thread.currentThread().setContextClassLoader(origClassLoader); + } + } + + protected Subject getSubject() { + return subject; + } +} diff --git a/org.argeo.slc.spring/src/org/argeo/slc/spring/AuthenticatedApplicationContextInitialization.java b/org.argeo.slc.spring/src/org/argeo/slc/spring/AuthenticatedApplicationContextInitialization.java new file mode 100644 index 000000000..68a9cc993 --- /dev/null +++ b/org.argeo.slc.spring/src/org/argeo/slc/spring/AuthenticatedApplicationContextInitialization.java @@ -0,0 +1,80 @@ +/* + * 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.spring; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; + +import javax.security.auth.Subject; + +import org.eclipse.gemini.blueprint.context.DependencyInitializationAwareBeanPostProcessor; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.support.AbstractBeanFactory; +import org.springframework.beans.factory.support.SecurityContextProvider; +import org.springframework.beans.factory.support.SimpleSecurityContextProvider; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * Executes with a system authentication the instantiation and initialization + * methods of the application context where it has been defined. + */ +public class AuthenticatedApplicationContextInitialization extends + AbstractSystemExecution implements + DependencyInitializationAwareBeanPostProcessor, ApplicationContextAware { + /** If non empty, restricts to these beans */ + private List beanNames = new ArrayList(); + + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + if (beanNames.size() == 0 || beanNames.contains(beanName)) + authenticateAsSystem(); + return bean; + } + + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + if (beanNames.size() == 0 || beanNames.contains(beanName)) + deauthenticateAsSystem(); + return bean; + } + + public void setBeanNames(List beanNames) { + this.beanNames = beanNames; + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + if (applicationContext.getAutowireCapableBeanFactory() instanceof AbstractBeanFactory) { + final AbstractBeanFactory beanFactory = ((AbstractBeanFactory) applicationContext + .getAutowireCapableBeanFactory()); + // retrieve subject's access control context + // and set it as the bean factory security context + Subject.doAs(getSubject(), new PrivilegedAction() { + @Override + public Void run() { + SecurityContextProvider scp = new SimpleSecurityContextProvider( + AccessController.getContext()); + beanFactory.setSecurityContextProvider(scp); + return null; + } + }); + } + } +} diff --git a/pom.xml b/pom.xml index 572202b33..6cee4d3e1 100644 --- a/pom.xml +++ b/pom.xml @@ -22,9 +22,10 @@ 2.1.86-SNAPSHOT - org.argeo.slc.api - org.argeo.slc.core + + + org.argeo.slc.spring org.argeo.slc.unit org.argeo.slc.support org.argeo.slc.repo