Commit eb4f59c7 authored by Francesco Chicchiricco's avatar Francesco Chicchiricco
Browse files

[CRV-17] First working implementation for enacting a new choreography

parent 392f21ad
......@@ -15,12 +15,48 @@
*/
package eu.chorevolution.idm.choremocks.ee;
import java.util.Date;
import java.util.UUID;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.brooklyn.rest.domain.TaskSummary;
import org.springframework.stereotype.Service;
@Service
public class ChoreographyResource implements ChoreographyApi {
@Context
private UriInfo uriInfo;
@Override
public Response deploy(final String choreography_name, final String choreography) {
String choreographyId = UUID.randomUUID().toString();
return Response.created(uriInfo.getAbsolutePathBuilder().path(choreographyId).build()).
entity(new TaskSummary(
UUID.randomUUID().toString(),
"Task for " + choreographyId,
null,
choreographyId,
choreography_name,
null,
new Date().getTime(),
new Date().getTime(),
new Date().getTime(),
"SUBMITTED",
null,
false,
false,
null,
null,
null,
null,
null,
null,
null)).
build();
}
@Override
public Response start(final String choreography_id) {
return null;
......@@ -41,11 +77,6 @@ public class ChoreographyResource implements ChoreographyApi {
return null;
}
@Override
public Response deploy(final String choreography_name, final String choreography) {
return null;
}
@Override
public Response resize(final String choreography_name, final int desired_size) {
return null;
......
......@@ -27,7 +27,6 @@ limitations under the License.
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- CXF Configuration - BEGIN -->
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
......@@ -35,6 +34,9 @@ limitations under the License.
<bean id="authenticationHandler" class="eu.chorevolution.idm.choremocks.AuthenticationHandler"/>
<bean id="jsonProvider" class="com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider"/>
<bean id="exceptionMapper" class="org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper">
<property name="addMessageToResponse" value="true"/>
</bean>
<jaxrs:server address="/"
basePackages="eu.chorevolution.idm.choremocks.ee,
......@@ -46,8 +48,8 @@ limitations under the License.
<jaxrs:providers>
<ref bean="authenticationHandler"/>
<ref bean="jsonProvider"/>
<ref bean="exceptionMapper"/>
</jaxrs:providers>
</jaxrs:server>
<!-- CXF Configuration - END -->
</beans>
......@@ -47,6 +47,15 @@ limitations under the License.
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-client</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
<dependency>
<groupId>eu.chorevolution.idm.ext.choreography</groupId>
<artifactId>syncope-ext-choreography-common-lib</artifactId>
......
......@@ -15,23 +15,133 @@
*/
package org.apache.syncope.core.logic;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import eu.chorevolution.idm.common.ChorevolutionEntitlement;
import eu.chorevolution.idm.common.types.ChoreographyAction;
import eu.chorevolution.idm.common.types.ChoreographyOperation;
import eu.chorevolution.idm.common.types.ServiceAction;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.syncope.common.lib.AbstractBaseBean;
import org.apache.syncope.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.to.AnyObjectTO;
import org.apache.syncope.common.lib.to.AttrTO;
import org.apache.syncope.core.persistence.api.dao.NotFoundException;
import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
import org.apache.syncope.core.persistence.api.entity.PlainSchema;
import org.apache.syncope.core.spring.security.Encryptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@Component
public class ChoreographyLogic extends AbstractTransactionalLogic<AbstractBaseBean> {
private static final String ENACTMENT_ENGINE_TYPE = "ENACTMENT ENGINE";
private static final String ENACTMENT_ENGINE_BASE_URL = "enactmentEngineBaseURL";
private static final String ENACTMENT_ENGINE_USERNAME = "enactmentEngineUsername";
private static final String ENACTMENT_ENGINE_PASSWORD = "enactmentEnginePassword";
@Autowired
private AnyObjectLogic anyObjectLogic;
@Autowired
private PlainSchemaDAO plainSchemaDAO;
private WebClient getWebClient(final String enactmentEngineKey, final String endpoint) throws Exception {
AnyObjectTO enactmentEngine = anyObjectLogic.read(enactmentEngineKey);
if (!ENACTMENT_ENGINE_TYPE.equals(enactmentEngine.getType())) {
throw new NotFoundException("Enactment Engine instance with key " + enactmentEngineKey);
}
Map<String, AttrTO> plainAttrs = enactmentEngine.getPlainAttrMap();
String baseURL = null;
if (plainAttrs.containsKey(ENACTMENT_ENGINE_BASE_URL)) {
List<String> values = plainAttrs.get(ENACTMENT_ENGINE_BASE_URL).getValues();
if (!values.isEmpty()) {
baseURL = values.get(0);
}
}
if (baseURL == null) {
throw new IllegalArgumentException(
"Could not find " + ENACTMENT_ENGINE_BASE_URL + " for " + enactmentEngineKey);
}
String username = null;
if (plainAttrs.containsKey(ENACTMENT_ENGINE_USERNAME)) {
List<String> values = plainAttrs.get(ENACTMENT_ENGINE_USERNAME).getValues();
if (!values.isEmpty()) {
username = values.get(0);
}
}
String password = null;
if (plainAttrs.containsKey(ENACTMENT_ENGINE_PASSWORD)) {
List<String> values = plainAttrs.get(ENACTMENT_ENGINE_PASSWORD).getValues();
if (!values.isEmpty()) {
PlainSchema enactmentEnginePasswordSchema = plainSchemaDAO.find(ENACTMENT_ENGINE_PASSWORD);
password = Encryptor.getInstance(enactmentEnginePasswordSchema.getSecretKey()).
decode(values.get(0), enactmentEnginePasswordSchema.getCipherAlgorithm());
}
}
List<Object> providers = new ArrayList<>();
providers.add(new JacksonJaxbJsonProvider());
return WebClient.create(
StringUtils.removeEndIgnoreCase(baseURL, "/") + endpoint, providers, username, password, null).
accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE);
}
@PreAuthorize("hasRole('" + ChorevolutionEntitlement.CHOREOGRAPHY_CREATE + "')")
public String enact(final String enactmentEngineKey, final InputStream chorSpec) {
return StringUtils.EMPTY;
String generatedChoreographyId = null;
Response response;
try {
WebClient webClient = getWebClient(enactmentEngineKey, "/deploy/TMP");
response = webClient.post(IOUtils.toString(chorSpec, SyncopeConstants.DEFAULT_CHARSET));
if (response.getStatus() != Response.Status.CREATED.getStatusCode()) {
throw new WebApplicationException(response);
}
if (response.hasEntity()) {
String responseBody =
IOUtils.toString((InputStream) response.getEntity(), SyncopeConstants.DEFAULT_CHARSET);
LOG.debug("Response from Enactment Engine {}:\n{}", enactmentEngineKey, responseBody);
JsonNode node = new ObjectMapper().readTree(responseBody);
if (node.has("entityId")) {
generatedChoreographyId = node.get("entityId").asText();
}
}
} catch (Exception e) {
LOG.error("While enacting on {}", enactmentEngineKey, e);
if (e instanceof WebApplicationException) {
throw WebApplicationException.class.cast(e);
} else {
throw new WebApplicationException("While enacting on " + enactmentEngineKey, e);
}
}
if (StringUtils.isEmpty(generatedChoreographyId)) {
throw new WebApplicationException("Could not extract the generated choreography id", response);
}
return generatedChoreographyId;
}
@PreAuthorize("hasRole('" + ChorevolutionEntitlement.CHOREOGRAPHY_UPDATE + "')")
......
......@@ -28,6 +28,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* REST services to be invoked by the Studio for operating on choreographies and / or their services.
......@@ -44,7 +45,7 @@ public interface ChoreographyService extends JAXRSService {
*/
@POST
@Consumes({ MediaType.APPLICATION_XML })
String enact(@NotNull @QueryParam("enactmentEngineKey") String enactmentEngineKey, InputStream chorSpec);
Response enact(@NotNull @QueryParam("enactmentEngineKey") String enactmentEngineKey, InputStream chorSpec);
/**
* Enact an existing choreography, with updated specification.
......
......@@ -20,6 +20,7 @@ import eu.chorevolution.idm.common.types.ChoreographyOperation;
import eu.chorevolution.idm.common.types.ServiceAction;
import org.apache.syncope.core.logic.ChoreographyLogic;
import java.io.InputStream;
import javax.ws.rs.core.Response;
import org.apache.syncope.common.rest.api.service.ChoreographyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -31,8 +32,10 @@ public class ChoreographyServiceImpl extends AbstractServiceImpl implements Chor
private ChoreographyLogic logic;
@Override
public String enact(final String enactmentEngineKey, final InputStream chorSpec) {
return logic.enact(enactmentEngineKey, chorSpec);
public Response enact(final String enactmentEngineKey, final InputStream chorSpec) {
return Response.status(Response.Status.CREATED).
header("X-CHOReVOLUTION-ChoreographyId", logic.enact(enactmentEngineKey, chorSpec)).
build();
}
@Override
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment