Skip to content

Commit

Permalink
fixed post methods for bpmn model upload, documentation (#892)
Browse files Browse the repository at this point in the history
  • Loading branch information
rsoika committed Jan 8, 2025
1 parent 5e047b0 commit e88ee6f
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 326 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public void saveModel(BPMNModel model, String _filename) throws ModelException {
// default filename
filename = version + ".bpmn";
}
logger.log(Level.INFO, "Import bpmn-model: {0} ▶ {1}", new Object[] { _filename,
logger.log(Level.INFO, "Import bpmn-model: {0} ▶ {1}", new Object[] { filename,
BPMNUtil.getVersion(model) });
// Write the model XML object into a byte array and store it into the
// modelItemCol as a FileData object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
package org.imixs.workflow.jaxrs;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
Expand All @@ -47,12 +48,11 @@
import org.imixs.workflow.engine.DocumentService;
import org.imixs.workflow.engine.ModelService;
import org.imixs.workflow.exceptions.ModelException;
import org.imixs.workflow.xml.XMLDataCollection;
import org.imixs.workflow.xml.XMLDocument;
import org.imixs.workflow.xml.XMLDocumentAdapter;
import org.openbpmn.bpmn.BPMNModel;
import org.openbpmn.bpmn.elements.Activity;
import org.openbpmn.bpmn.elements.BPMNProcess;
import org.openbpmn.bpmn.exceptions.BPMNModelException;
import org.openbpmn.bpmn.util.BPMNModelFactory;

import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
Expand Down Expand Up @@ -396,149 +396,95 @@ public void deleteModel(@PathParam("version") String version) {
* @return
*/
@PUT
@Path("/bpmn")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN })
public Response putBPMNModel(BPMNModel bpmnmodel) {
try {
logger.fine("BPMN Model posted... ");
modelService.saveModel(bpmnmodel);
} catch (ModelException e) {
logger.log(Level.WARNING, "Unable to update model: {0}", e.getMessage());
return Response.status(Response.Status.NOT_ACCEPTABLE).build();
}
logger.fine("putBPMNModel finished! ");
return Response.status(Response.Status.OK).build();
}

/**
* This method consumes a Imixs BPMN model file and updates the corresponding
* model information.
* <p>
* The filename param is used to store the file in the corresponding bpmn
* document.
*
* @param model
* @return
*/
@PUT
@Path("/bpmn/{filename}")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN })
public Response putBPMNModel(@PathParam("filename") String filename, BPMNModel bpmnmodel) {
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
public Response putBPMNModel(@PathParam("filename") String filename, InputStream inputStream) {
try {
logger.fine("BPMN Model posted... ");
modelService.saveModel(bpmnmodel, filename);
} catch (ModelException e) {
logger.log(Level.WARNING, "Unable to update model: {0}", e.getMessage());
return Response.status(Response.Status.NOT_ACCEPTABLE).build();
}
logger.fine("putBPMNModel finished! ");
return Response.status(Response.Status.OK).build();
}
logger.fine("BPMN Model file upload started for file: " + filename);

@POST
@Path("/bpmn")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN })
public Response postBPMNModel(BPMNModel bpmnmodel) {
return putBPMNModel(bpmnmodel);
}
// Validate filename
if (!filename.toLowerCase().endsWith(".bpmn")) {
return Response.status(Response.Status.BAD_REQUEST)
.entity("File must have .bpmn extension")
.build();
}

@POST
@Path("/bpmn/{filename}")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_OCTET_STREAM, MediaType.TEXT_PLAIN })
public Response postBPMNModel(@PathParam("filename") String filename, BPMNModel bpmnmodel) {
return putBPMNModel(filename, bpmnmodel);
}
// Parse input stream to BPMN model
BPMNModel model = BPMNModelFactory.read(inputStream);

/**
* This method updates a Model provided in a EntityCollection object for a
* provided model version. The Method expects a subresource with a ModelVersion.
* Next the method updates each Entity object with the property $ModelVersion.
* An old version will be automatically removed before update.
*
* @param version - $modelversion
* @param ecol - model data
*/
@PUT
@Path("/{version}")
@Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public void putModelByVersion(@PathParam("version") final String _modelVersion, XMLDataCollection ecol) {
// Save model using the model service with filename
modelService.saveModel(model, filename);

String sModelVersion = _modelVersion;
XMLDocument entity;
ItemCollection itemCollection;
try {
if (ecol.getDocument().length > 0) {
/*
* first we need to delete the old model if available.
*/
if (sModelVersion == null)
sModelVersion = "";

// delete old model if a modelversion is available
if (!"".equals(sModelVersion))
modelService.getModelManager().removeModel(sModelVersion);

// save new entities into database and update modelversion.....
for (int i = 0; i < ecol.getDocument().length; i++) {
entity = ecol.getDocument()[i];
itemCollection = XMLDocumentAdapter.putDocument(entity);
// update model version
itemCollection.replaceItemValue("$modelVersion", sModelVersion);
// save entity
documentService.save(itemCollection);
}
}
logger.fine("BPMN Model file upload completed successfully");
return Response.status(Response.Status.OK).build();

} catch (Exception e) {
e.printStackTrace();
} catch (BPMNModelException e) {
logger.log(Level.WARNING, "Failed to parse BPMN model file: {0}", e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("Invalid BPMN file format: " + e.getMessage())
.build();
} catch (ModelException e) {
logger.log(Level.WARNING, "Failed to save model: {0}", e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Failed to save model: " + e.getMessage())
.build();
} finally {
try {
inputStream.close();
} catch (IOException e) {
logger.log(Level.WARNING, "Failed to close input stream", e);
}
}

}

@POST
@Path("/{version}")
@Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public void postModelByVersion(@PathParam("version") String sModelVersion, XMLDataCollection ecol) {
putModelByVersion(sModelVersion, ecol);
@Path("/bpmn/{filename}")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
public Response postBPMNModel(@PathParam("filename") String filename, InputStream inputStream) {
return putBPMNModel(filename, inputStream);
}

/**
* This method updates a Model provided in a EntityCollection object.
*
* The method takes the first entity to get the provided $modelVersion. An old
* version will be automatically removed before update.
*
* @param ecol
*/
@PUT
@Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public void putModel(XMLDataCollection ecol) {
String sModelVersion = null;
XMLDocument entity;
ItemCollection itemCollection;
@Path("/bpmn")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
public Response putBPMNModel(InputStream inputStream) {
try {
if (ecol.getDocument().length > 0) {
/*
* first we need get model version from first entity
*/
entity = ecol.getDocument()[0];
itemCollection = XMLDocumentAdapter.putDocument(entity);
sModelVersion = itemCollection.getItemValueString("$ModelVersion");
logger.fine("BPMN Model file upload started... ");

putModelByVersion(sModelVersion, ecol);
// Parse input stream to BPMN model
BPMNModel model = BPMNModelFactory.read(inputStream);

}
// Save model using the model service
modelService.saveModel(model);

} catch (Exception e) {
e.printStackTrace();
}
logger.fine("BPMN Model file upload completed successfully");
return Response.status(Response.Status.OK).build();

} catch (BPMNModelException e) {
logger.log(Level.WARNING, "Failed to parse BPMN model file: {0}",
e.getMessage());
return Response.status(Response.Status.BAD_REQUEST)
.entity("Invalid BPMN file format: " + e.getMessage())
.build();
} catch (ModelException e) {
logger.log(Level.WARNING, "Failed to save model: {0}", e.getMessage());
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity("Failed to save model: " + e.getMessage())
.build();
} finally {
try {
inputStream.close();
} catch (IOException e) {
logger.log(Level.WARNING, "Failed to close input stream", e);
}
}
}

@POST
@Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public void postModel(XMLDataCollection ecol) {
putModel(ecol);
@Path("/bpmn")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
public Response postBPMNModel(InputStream inputStream) {
return putBPMNModel(inputStream);
}

/**
Expand Down
79 changes: 37 additions & 42 deletions src/site/markdown/docker.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Imixs Docker

The Imixs-Workflow project supports several Docker Images to run Imixs-Workflow in a containerized infrastructure.
The Imixs-Workflow project supports several Docker Images to run Imixs-Workflow in a containerized infrastructure.
The Imixs Docker Images are hosted on [Docker Hub](https://hub.docker.com/r/imixs/) and can be installed and extended in various ways.


## The Imixs Microservice

The subproject [Imixs-Microservice](https://github.com/imixs/imixs-microservice) provides a WebService Interface which can be used to interact with the Imixs-Workflow-Engine over the [Imixs Rest API](./restapi/index.html). The 'Imixs-Microsoervice' is a Java EE Web Module which extends the Imixs-Workflow Engine providing a Rest Service for Human Centric Workflow Applications. This service can be used as a single Microservice or bundled with a Java EE Business Application. See also the [Deployment Guide](./deployment/index.html) for details.
Expand All @@ -12,50 +11,51 @@ The subproject [Imixs-Microservice](https://github.com/imixs/imixs-microservice)

To use Imixs-Workflow out of the box, you can create a 'docker-compose' file:

version: '3.3'
services:
db:
image: postgres:9.6.1
environment:
POSTGRES_PASSWORD: adminadmin
POSTGRES_DB: workflow
app:
image: imixs/imixs-microservice
environment:
WILDFLY_PASS: adminadmin
POSTGRES_HOST: "db"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "adminadmin"
POSTGRES_DATABASE: "workflow"
POSTGRES_CONNECTION: "jdbc:postgresql://db/workflow"
ports:
- "8080:8080"
version: '3.3'
services:
db:
image: postgres:9.6.1
environment:
POSTGRES_PASSWORD: adminadmin
POSTGRES_DB: workflow
app:
image: imixs/imixs-microservice
environment:
WILDFLY_PASS: adminadmin
POSTGRES_HOST: "db"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "adminadmin"
POSTGRES_DATABASE: "workflow"
POSTGRES_CONNECTION: "jdbc:postgresql://db/workflow"
ports:
- "8080:8080"

Run start imixs-wokflow with docker-compose run:

$ docker-compose up
**Note:** The container is linked to the postgres container providing a database name 'workflow'. See the [docker project home](https://hub.docker.com/r/imixs/imixs-microservice/) for more information.
$ docker-compose up


**Note:** The container is linked to the postgres container providing a database name 'workflow'. See the [docker project home](https://hub.docker.com/r/imixs/imixs-microservice/) for more information.

## Testing the Imixs-Microservice

Using the command-line tool '[curl](http://curl.haxx.se/)' makes it easy to test the Imixs-Microservice. Here are some examples.

**NOTE**: As Imixs-Workflow is a human-centric Workflow Engine onyl authenticated users (Actors) can interact with the engine. Therefore it is necessary to authenticate against the Imixs-Rest service API. Imixs-Microservice provides a User-Management-Service to register and authenticate users. The default user has the userid 'admin' and the default password 'adminadmin'. This user is used in the following examples. Run the setup url of Imixs-Micorservice to initalize the admin user acount:
**NOTE**: As Imixs-Workflow is a human-centric Workflow Engine onyl authenticated users (Actors) can interact with the engine. Therefore it is necessary to authenticate against the Imixs-Rest service API. Imixs-Microservice provides a User-Management-Service to register and authenticate users. The default user has the userid 'admin' and the default password 'adminadmin'. This user is used in the following examples. Run the setup url of Imixs-Micorservice to initalize the admin user acount:

http://localhost:8080/imixs-microservice/setup
http://localhost:8080/imixs-microservice/setup

### Deploy a new BPMN model

With the following command a BPMN model created with the [Imixs-BPMN Modeling Tool](./modelling/index.html) can be deployed into the Imixs-Microservce.

curl --user admin:adminadmin --request POST \
-Tticket.bpmn \
http://localhost:8080/imixs-microservice/model/bpmn
http://localhost:8080/imixs-microservice/model/bpmn/

### Request the Deployed Model Version

The following command returns the model versions deployed into the service:
The following command returns the model versions deployed into the service:

curl --user admin:adminadmin -H \
"Accept: application/xml" \
Expand All @@ -69,23 +69,21 @@ To request the current task list for the user 'admin' run:
"Accept: application/json" \
http://localhost:8080/imixs-microservice/workflow/tasklist/creator/admin


### Create a new Process Instance
The next example shows how to post a new Workitem in JSON Format. The request post a JSON structure for a new workitem with the txtWorkflowGroup 'Ticket', the ProcessID 1000 and ActivityID 10. The result is a new process instance controlled by Imixs-Workflow Engine


The next example shows how to post a new Workitem in JSON Format. The request post a JSON structure for a new workitem with the txtWorkflowGroup 'Ticket', the ProcessID 1000 and ActivityID 10. The result is a new process instance controlled by Imixs-Workflow Engine

curl --user admin:adminadmin -H "Content-Type: application/json" -H "Accept: application/json" -d \
'{"item":[
{"name": "$modelversion", "value":["1.0"]},
{"name": "$taskid", "value": [1000] },
{"name": "$eventid", "value": [10] },
{"name": "_subject", "value": ["some data...","more data..."]}
]}' \
http://localhost:8080/api/workflow/workitem

curl --user admin:adminadmin -H "Content-Type: application/json" -H "Accept: application/json" -d \
'{"item":[
{"name": "$modelversion", "value":["1.0"]},
{"name": "$taskid", "value": [1000] },
{"name": "$eventid", "value": [10] },
{"name": "_subject", "value": ["some data...","more data..."]}
]}' \
http://localhost:8080/api/workflow/workitem

### Read a Process Instance

After posting a new process instance the Imixs-Workflow engine will retrun a datastructure includign the uniqueid of the created process instance.
The uniqueid is used to request a single Workitem from the Imixs-Microservice. See the following curl example to request a workitem by it's $UniqueID in JSON format:

Expand All @@ -95,7 +93,4 @@ The uniqueid is used to request a single Workitem from the Imixs-Microservice. S

This example returns the content of the Workitem with the UniqueID '14b65352f58-259f4f9b'. You can also restrict the result to a subset of properties when you add the query parameter 'items':


For more details read the section [Imixs-Rest API](./restapi/index.html)


Loading

0 comments on commit e88ee6f

Please sign in to comment.