log4j.logger.org.argeo.slc.execution.ExecutionContext=DEBUG
log4j.logger.org.argeo.slc.execution.SimpleExecutionSpec=DEBUG
-log4j.logger.org.argeo.slc.services=DEBUG
+log4j.logger.org.argeo.slc.web.mvc=DEBUG
log4j.logger.org.hibernate=WARN
--- /dev/null
+package org.argeo.slc.it.webapp;
+
+import org.argeo.slc.Condition;
+import org.argeo.slc.core.test.tree.TreeTestResultList;
+import org.argeo.slc.runtime.SlcAgentDescriptor;
+import org.argeo.slc.server.unit.AbstractHttpClientTestCase;
+
+public class SimpleScenarioTest extends AbstractHttpClientTestCase {
+ public void testSimpleScenario() throws Exception {
+ // Get agent
+ SlcAgentDescriptor agentDescriptor = getHttpClient().waitForOneAgent();
+ assertNotNull(agentDescriptor);
+
+ // Launch SLC Execution
+ // TODO: don't hardcode tested version
+ assertAnswerOk(getHttpClient().startFlow(agentDescriptor.getUuid(),
+ "org.argeo.slc.demo.basic", "0.11.4.SNAPSHOT", "main"));
+
+ getHttpClient().callServiceSafe("listResults.service", null,
+ new Condition<TreeTestResultList>() {
+
+ public Boolean check(TreeTestResultList obj) {
+ return obj.getList().size() == 3;
+ }
+ }, null);
+ }
+}
package org.argeo.slc.server.client;
+import org.argeo.slc.msg.ExecutionAnswer;
import org.argeo.slc.runtime.SlcAgentDescriptor;
/** Abstraction of the access to HTTP services of an SLC Server. */
public interface SlcServerHttpClient extends HttpServicesClient {
/** Wait for one agent to be available. */
public SlcAgentDescriptor waitForOneAgent();
+
+ /** Wait for the http server to be ready. */
+ public void waitForServerToBeReady();
+
+ /** Start an execution flow on the given agent. */
+ public ExecutionAnswer startFlow(String agentId, String moduleName,
+ String version, String flowName);
}
package org.argeo.slc.server.client.impl;
import java.io.IOException;
-import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Iterator;
import java.util.Map;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.io.IOUtils;
import org.argeo.slc.Condition;
import org.argeo.slc.SlcException;
import org.argeo.slc.server.client.HttpServicesClient;
+import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.util.Assert;
private final static Log log = LogFactory
.getLog(AbstractHttpServicesClient.class);
private Unmarshaller unmarshaller;
+ private Marshaller marshaller;
private String baseUrl;
+ private String encoding = "UTF-8";
private Long retryPeriod = 1000l;
- @SuppressWarnings(value = { "unchecked" })
+ private Long defaultTimeout = 30 * 1000l;
+
public <T> T callService(String path, Map<String, String> parameters) {
+ return callService(path, parameters, null);
+ }
+
+ @SuppressWarnings(value = { "unchecked" })
+ public <T> T callService(String path, Map<String, String> parameters,
+ Object body) {
try {
- return (T) callServiceLowLevel(path, parameters);
+ return (T) callServiceLowLevel(path, parameters, body);
} catch (Exception e) {
throw new SlcException("Cannot call service " + path + " on "
+ baseUrl, e);
@SuppressWarnings(value = { "unchecked" })
public <T> T callServiceSafe(String path, Map<String, String> parameters,
Condition<T> condition, Long timeout) {
+ if (timeout == null)
+ timeout = defaultTimeout;
+
long begin = System.currentTimeMillis();
try {
Object obj = null;
long duration = System.currentTimeMillis() - begin;
while (duration < timeout) {
try {
- obj = callServiceLowLevel(path, parameters);
+ obj = callServiceLowLevel(path, parameters, null);
} catch (IOException e) {
if (log.isTraceEnabled())
log.trace("Exception when calling service " + path
}
protected Object callServiceLowLevel(String path,
- Map<String, String> parameters) throws IOException {
+ Map<String, String> parameters, Object body) throws IOException {
Assert.notNull(baseUrl, "base url");
- InputStream in = null;
+ HttpURLConnection connection = null;
+ Writer writer = null;
+ Reader reader = null;
try {
- URL url = new URL(baseUrl + path);
- HttpURLConnection connection = (HttpURLConnection) url
- .openConnection();
- if (parameters != null) {
- for (String key : parameters.keySet()) {
- connection.addRequestProperty(key, parameters.get(key));
- }
+ URL url = createUrl(path, parameters);
+ connection = (HttpURLConnection) url.openConnection();
+
+ if (body != null) {
+ connection.setRequestMethod("POST");
+ connection.setDoOutput(true);
+ connection.setDoInput(true);
+ connection.setUseCaches(false);
+ connection.setAllowUserInteraction(false);
+ connection.setRequestProperty("Content-type",
+ "text/xml; charset=" + encoding);
}
+ // Establish the connection
connection.connect();
- in = connection.getInputStream();
- StreamSource source = new StreamSource(in);
+ if (body != null) {
+ writer = new OutputStreamWriter(connection.getOutputStream(),
+ encoding);
+ StreamResult result = new StreamResult(writer);
+ marshaller.marshal(body, result);
+ writer.flush();
+ IOUtils.closeQuietly(writer);
+ }
+
+ // Read answer
+ reader = new InputStreamReader(connection.getInputStream(),
+ encoding);
+ Source source = new StreamSource(reader);
Object obj = unmarshaller.unmarshal(source);
return obj;
} finally {
- IOUtils.closeQuietly(in);
+ IOUtils.closeQuietly(reader);
+ IOUtils.closeQuietly(writer);
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ }
+
+ protected URL createUrl(String service, Map<String, String> parameters) {
+ // URL encoded with UTF-8, as recommended by W3C
+ final String urlEncoding = "UTF-8";
+
+ StringBuffer buf = new StringBuffer(baseUrl + service);
+ try {
+ if (parameters != null && parameters.size() != 0) {
+ buf.append('?');
+ Iterator<String> it = parameters.keySet().iterator();
+ String key = null;
+ while (it.hasNext()) {
+ if (key != null)
+ buf.append('&');
+ key = it.next();
+ String keyEncoded = URLEncoder.encode(key, urlEncoding);
+ String valueEncoded = URLEncoder.encode(
+ parameters.get(key), urlEncoding);
+ buf.append(keyEncoded).append('=').append(valueEncoded);
+ }
+ }
+
+ return new URL(buf.toString());
+ } catch (Exception e) {
+ throw new SlcException("Cannot create URL: " + buf, e);
}
}
public void setRetryPeriod(Long retryPeriod) {
this.retryPeriod = retryPeriod;
}
+
+ public void setMarshaller(Marshaller marshaller) {
+ this.marshaller = marshaller;
+ }
+
+ /** Default is UTF-8. */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /** Default is 30s*/
+ public void setDefaultTimeout(Long defaultTimeout) {
+ this.defaultTimeout = defaultTimeout;
+ }
+
}
package org.argeo.slc.server.client.impl;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.slc.Condition;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.execution.ExecutionFlowDescriptor;
+import org.argeo.slc.msg.ExecutionAnswer;
+import org.argeo.slc.msg.MsgConstants;
import org.argeo.slc.msg.ObjectList;
+import org.argeo.slc.process.RealizedFlow;
+import org.argeo.slc.process.SlcExecution;
import org.argeo.slc.runtime.SlcAgentDescriptor;
import org.argeo.slc.server.client.SlcServerHttpClient;
public class SlcServerHttpClientImpl extends AbstractHttpServicesClient
implements SlcServerHttpClient {
public final static String LIST_AGENTS = "listAgents.service";
+ public final static String IS_SERVER_READY = "isServerReady.service";
+ public final static String NEW_SLC_EXECUTION = "newSlcExecution.service";
private final static Log log = LogFactory
.getLog(SlcServerHttpClientImpl.class);
private Long retryTimeout = 60 * 1000l;
+ private Long serverReadyTimeout = 120 * 1000l;
+
+ public ExecutionAnswer startFlow(String agentId, String moduleName,
+ String version, String flowName) {
+ SlcExecution slcExecution = new SlcExecution();
+ slcExecution.setUuid(UUID.randomUUID().toString());
+
+ RealizedFlow realizedFlow = new RealizedFlow();
+ realizedFlow.setModuleName(moduleName);
+ realizedFlow.setModuleVersion(version);
+
+ ExecutionFlowDescriptor flowDescriptor = new ExecutionFlowDescriptor();
+ flowDescriptor.setName(flowName);
+
+ realizedFlow.setFlowDescriptor(flowDescriptor);
+ slcExecution.getRealizedFlows().add(realizedFlow);
+
+ Map<String, String> parameters = new HashMap<String, String>();
+ parameters.put(MsgConstants.PROPERTY_SLC_AGENT_ID, agentId);
+ ExecutionAnswer answer = callService(NEW_SLC_EXECUTION, parameters,
+ slcExecution);
+ return answer;
+ }
public SlcAgentDescriptor waitForOneAgent() {
ObjectList objectList = callServiceSafe(LIST_AGENTS, null,
return (SlcAgentDescriptor) objectList.getObjects().get(0);
}
- /** Timeout in ms after which a safe call will throw an exception. */
+ public void waitForServerToBeReady() {
+ ExecutionAnswer answer = callServiceSafe(IS_SERVER_READY, null, null,
+ serverReadyTimeout);
+ if (!answer.isOk())
+ throw new SlcException("Server is not ready: " + answer);
+ }
+
+ /**
+ * Timeout in ms after which a safe call will throw an exception. Default is
+ * 60s.
+ */
public void setRetryTimeout(Long retryTimeout) {
this.retryTimeout = retryTimeout;
}
+ /**
+ * Timeout in ms after which the client will stop waiting for the server to
+ * be ready and throw an exception. Default is 120s.
+ */
+ public void setServerReadyTimeout(Long serverReadyTimeout) {
+ this.serverReadyTimeout = serverReadyTimeout;
+ }
+
}
package org.argeo.slc.server.unit;
-import org.argeo.slc.SlcException;
import org.argeo.slc.msg.ExecutionAnswer;
import org.argeo.slc.server.client.SlcServerHttpClient;
import org.argeo.slc.unit.AbstractSpringTestCase;
public abstract class AbstractHttpClientTestCase extends AbstractSpringTestCase {
private SlcServerHttpClient httpClient = null;
- private String isServerReadyService = "isServerReady.service";
-
protected void setUp() throws Exception {
super.setUp();
httpClient = createHttpClient();
- waitForServerToBeReady();
- }
-
- protected void waitForServerToBeReady() {
- ExecutionAnswer answer = httpClient.callServiceSafe(
- isServerReadyService, null, null, getServerReadyTimeout());
- if (!answer.isOk())
- throw new SlcException("Server is not ready: " + answer);
+ httpClient.waitForServerToBeReady();
}
protected SlcServerHttpClient createHttpClient() {
return httpClient;
}
- /** Default is 120s */
- protected Long getServerReadyTimeout() {
- return 120 * 1000l;
+ protected void assertAnswerOk(ExecutionAnswer answer) {
+ if (!answer.isOk()) {
+ fail("Server execution answer is not ok: " + answer.getMessage());
+ }
}
}
import org.apache.commons.logging.LogFactory;
import org.argeo.slc.SlcException;
import org.argeo.slc.dao.process.SlcExecutionDao;
-import org.argeo.slc.msg.process.SlcExecutionRequest;
import org.argeo.slc.msg.process.SlcExecutionStatusRequest;
import org.argeo.slc.process.SlcExecution;
import org.argeo.slc.services.process.SlcExecutionService;
import org.argeo.slc.services.process.SlcExecutionService;\r
import org.argeo.slc.web.mvc.AbstractServiceController;\r
import org.springframework.oxm.Unmarshaller;\r
+import org.springframework.util.Assert;\r
import org.springframework.web.servlet.ModelAndView;\r
import org.springframework.xml.transform.StringSource;\r
\r
\r
String agentId = request\r
.getParameter(MsgConstants.PROPERTY_SLC_AGENT_ID);\r
+ Assert.notNull(agentId, "agent id");\r
\r
String answer = request.getParameter("body");\r
if (answer == null) {\r
<bean id="slcDefault.serverHttpClient" class="org.argeo.slc.server.client.impl.SlcServerHttpClientImpl"
lazy-init="true">
<property name="unmarshaller" ref="slcDefault.castor.marshaller" />
+ <property name="marshaller" ref="slcDefault.castor.marshaller" />
<property name="baseUrl" value="http://localhost:7070/org.argeo.slc.webapp/" />
</bean>
</beans>
\ No newline at end of file
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
default-lazy-init="true">
- <bean id="slcDefault.castor.marshaller"
- class="org.springframework.oxm.castor.CastorMarshaller">
+ <bean id="slcDefault.castor.marshaller" class="org.springframework.oxm.castor.CastorMarshaller">
<property name="mappingLocations">
<list>
<value>
</list>
</property>
<property name="whitespacePreserve" value="true" />
+ <property name="encoding" value="UTF-8" />
</bean>
- <bean id="slcDefault.castor.xsltReportGenerator"
- class="org.argeo.slc.xml.test.tree.XsltReportGenerator"
+ <bean id="slcDefault.castor.xsltReportGenerator" class="org.argeo.slc.xml.test.tree.XsltReportGenerator"
init-method="init">
<property name="xsltStyleSheet"
value="classpath:/org/argeo/slc/core/test/tree/basicReport.xslt" />
<property name="outputDir" value="${slc.workDir}/results/html" />
</bean>
- <bean name="slcDefault.castor.fileSlcExecutionNotifier"
- class="org.argeo.slc.xml.process.FileSlcExecutionNotifier">
+ <bean name="slcDefault.castor.fileSlcExecutionNotifier" class="org.argeo.slc.xml.process.FileSlcExecutionNotifier">
<property name="basePath" value="${slc.workDir}/process" />
<property name="marshaller" ref="slcDefault.castor.marshaller" />
</bean>
uuid);\r
}\r
\r
+ @SuppressWarnings("unchecked")\r
public List<SlcExecution> listSlcExecutions() {\r
return (List<SlcExecution>) getHibernateTemplate().loadAll(\r
SlcExecution.class);\r