/**
* Copyright 2015 Otto (GmbH & Co KG)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ottogroup.bi.spqr.node.resource.pipeline;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import org.apache.commons.lang3.StringUtils;
import com.codahale.metrics.annotation.Timed;
import com.ottogroup.bi.spqr.exception.ComponentInitializationFailedException;
import com.ottogroup.bi.spqr.exception.NonUniqueIdentifierException;
import com.ottogroup.bi.spqr.exception.PipelineInstantiationFailedException;
import com.ottogroup.bi.spqr.exception.QueueInitializationFailedException;
import com.ottogroup.bi.spqr.exception.RequiredInputMissingException;
import com.ottogroup.bi.spqr.node.resource.pipeline.MicroPipelineShutdownResponse.MicroPipelineShutdownState;
import com.ottogroup.bi.spqr.pipeline.MicroPipeline;
import com.ottogroup.bi.spqr.pipeline.MicroPipelineConfiguration;
import com.ottogroup.bi.spqr.pipeline.MicroPipelineManager;
import com.ottogroup.bi.spqr.pipeline.MicroPipelineValidationResult;
/**
* REST resource providing access to {@link MicroPipeline pipelines} managed by {@link MicroPipelineManager}. The resource provides methods for
* <ul>
* <li>{@link MicroPipelineResource#instantiatePipeline(String, MicroPipelineConfiguration) pipeline instantiation}</li>
* <li>{@link MicroPipelineResource#shutdown(String) pipeline shutdown}</li>
* </ul>
* @author mnxfst
* @since Mar 13, 2015
*/
@Path("/pipelines")
public class MicroPipelineResource {
public static final String ERROR_MSG_PIPELINE_ID_MISSING = "Missing required pipeline id";
public static final String ERROR_MSG_PIPELINE_CONFIGURATION_MISSING = "Missing required pipeline configuration";
public static final String ERROR_MSG_PIPELINE_IDS_DIFFER = "Pipeline id referenced in path is not equal to id found in configuration";
public static final String LIST_PIPELINES_MODE_FULL = "FULL";
public static final String LIST_PIPELINES_MODE_SIMPLE = "SIMPLE";
private final MicroPipelineManager microPipelineManager;
/**
* Initializes the micro pipeline resource using the provided input
* @param microPipelineManager
*/
public MicroPipelineResource(final MicroPipelineManager microPipelineManager) throws RequiredInputMissingException {
if(microPipelineManager == null)
throw new RequiredInputMissingException("Missing required micro pipeline manager instance");
this.microPipelineManager = microPipelineManager;
}
/**
* Creates a new pipeline for the given identifier and {@link MicroPipelineConfiguration}
* @param pipelineId
* @param configuration
* @return
*/
@Produces(value = "application/json")
@Timed(name = "pipeline-instantiation")
@POST
public MicroPipelineInstantiationResponse instantiatePipeline(final MicroPipelineConfiguration configuration) {
if(configuration == null)
return new MicroPipelineInstantiationResponse("", MicroPipelineValidationResult.MISSING_CONFIGURATION, ERROR_MSG_PIPELINE_CONFIGURATION_MISSING);
if(StringUtils.isBlank(configuration.getId()))
return new MicroPipelineInstantiationResponse("", MicroPipelineValidationResult.MISSING_CONFIGURATION, ERROR_MSG_PIPELINE_ID_MISSING);
try {
String id = this.microPipelineManager.executePipeline(configuration);
return new MicroPipelineInstantiationResponse(id, MicroPipelineValidationResult.OK, "");
} catch (RequiredInputMissingException e) {
return new MicroPipelineInstantiationResponse(configuration.getId(), MicroPipelineValidationResult.MISSING_CONFIGURATION, e.getMessage());
} catch (QueueInitializationFailedException e) {
return new MicroPipelineInstantiationResponse(configuration.getId(), MicroPipelineValidationResult.QUEUE_INITIALIZATION_FAILED, e.getMessage());
} catch (ComponentInitializationFailedException e) {
return new MicroPipelineInstantiationResponse(configuration.getId(), MicroPipelineValidationResult.COMPONENT_INITIALIZATION_FAILED, e.getMessage());
} catch (PipelineInstantiationFailedException e) {
return new MicroPipelineInstantiationResponse(configuration.getId(), MicroPipelineValidationResult.PIPELINE_INITIALIZATION_FAILED, e.getMessage());
} catch (NonUniqueIdentifierException e) {
return new MicroPipelineInstantiationResponse(configuration.getId(), MicroPipelineValidationResult.NON_UNIQUE_PIPELINE_ID, e.getMessage());
} catch(Exception e) {
return new MicroPipelineInstantiationResponse(configuration.getId(), MicroPipelineValidationResult.TECHNICAL_ERROR, e.getMessage());
}
}
/**
* Creates or updates a pipeline for the given identifier and {@link MicroPipelineConfiguration}
* @param pipelineId
* @param configuration
* @return
*/
@Produces(value = "application/json")
@Timed(name = "pipeline-instantiation")
@PUT
@Path("{pipelineId}")
public MicroPipelineInstantiationResponse updatePipeline(@PathParam("pipelineId") final String pipelineId, final MicroPipelineConfiguration configuration) {
if(StringUtils.isBlank(pipelineId))
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.MISSING_CONFIGURATION, ERROR_MSG_PIPELINE_ID_MISSING);
if(configuration == null)
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.MISSING_CONFIGURATION, ERROR_MSG_PIPELINE_CONFIGURATION_MISSING);
if(!StringUtils.equalsIgnoreCase(StringUtils.trim(pipelineId), configuration.getId()))
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.PIPELINE_INITIALIZATION_FAILED, ERROR_MSG_PIPELINE_IDS_DIFFER);
try {
// shutdown running instance of pipeline
if(this.microPipelineManager.hasPipeline(pipelineId)) {
this.microPipelineManager.shutdownPipeline(pipelineId);
}
String id = this.microPipelineManager.executePipeline(configuration);
return new MicroPipelineInstantiationResponse(id, MicroPipelineValidationResult.OK, "");
} catch (RequiredInputMissingException e) {
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.MISSING_CONFIGURATION, e.getMessage());
} catch (QueueInitializationFailedException e) {
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.QUEUE_INITIALIZATION_FAILED, e.getMessage());
} catch (ComponentInitializationFailedException e) {
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.COMPONENT_INITIALIZATION_FAILED, e.getMessage());
} catch (PipelineInstantiationFailedException e) {
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.PIPELINE_INITIALIZATION_FAILED, e.getMessage());
} catch (NonUniqueIdentifierException e) {
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.NON_UNIQUE_PIPELINE_ID, e.getMessage());
} catch(Exception e) {
return new MicroPipelineInstantiationResponse(pipelineId, MicroPipelineValidationResult.TECHNICAL_ERROR, e.getMessage());
}
}
/**
* Shuts down the referenced {@link MicroPipeline}
* @param pipelineId
* @return
*/
@Produces(value = "application/json")
@Timed(name = "pipeline-shutdown")
@DELETE
@Path("{pipelineId}")
public MicroPipelineShutdownResponse shutdown(@PathParam("pipelineId") final String pipelineId) {
if(StringUtils.isBlank(pipelineId))
return new MicroPipelineShutdownResponse(pipelineId, MicroPipelineShutdownState.PIPELINE_ID_MISSING, ERROR_MSG_PIPELINE_ID_MISSING);
try {
return new MicroPipelineShutdownResponse(this.microPipelineManager.shutdownPipeline(pipelineId), MicroPipelineShutdownState.OK, "");
} catch(Exception e) {
return new MicroPipelineShutdownResponse(pipelineId, MicroPipelineShutdownState.TECHNICAL_ERROR, e.getMessage());
}
}
/**
* Lists all {@link MicroPipeline} instances registered with this node. Depending on the <i>mode</i> parameter, the
* result contains either just a list of pipeline identifiers or contains the associated {@link MicroPipelineConfiguration} as well.
* @param mode result mode: SIMPLE, FULL (default: SIMPLE)
* @return
*/
@Produces(value = "application/json" )
@Timed(name = "pipeline-list" )
@GET
@Path("list")
public ListRegisteredMicroPipelinesResponse listRegisteredPipelines(@QueryParam("mode") final String mode) {
if(StringUtils.isBlank(mode) || StringUtils.equalsIgnoreCase(mode, LIST_PIPELINES_MODE_SIMPLE)) {
return new ListRegisteredMicroPipelinesResponse(this.microPipelineManager.getProcessingNodeId(), this.microPipelineManager.getPipelineIds());
}
return new ListRegisteredMicroPipelinesResponse(this.microPipelineManager.getProcessingNodeId(), this.microPipelineManager.getPipelineIds(), this.microPipelineManager.getPipelineConfigurations());
}
}