315 lines
No EOL
9.5 KiB
Java
315 lines
No EOL
9.5 KiB
Java
package ai.dynamixs.mcp;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
import jakarta.json.Json;
|
|
import jakarta.json.JsonObject;
|
|
import jakarta.json.JsonObjectBuilder;
|
|
import jakarta.json.JsonString;
|
|
|
|
/**
|
|
* Represents an MCP Resource based on Imixs-Workflow BPMN models.
|
|
*
|
|
* MCP Resources represent entities that can be read by the MCP client. Each
|
|
* resource corresponds to a workflow task/event combination.
|
|
*/
|
|
public class MCPResource implements Serializable {
|
|
|
|
private static final long serialVersionUID = 1L;
|
|
|
|
// MCP Standard Fields
|
|
private String uri; // Resource URI
|
|
private String name; // Human-readable name
|
|
private String description; // Resource description
|
|
private String mimeType; // MIME type of the resource
|
|
private Map<String, Object> annotations; // Additional metadata
|
|
|
|
// Imixs-specific fields
|
|
private String modelVersion;
|
|
private int taskId;
|
|
private int eventId;
|
|
|
|
// Constructors
|
|
public MCPResource() {
|
|
this.annotations = new HashMap<>();
|
|
}
|
|
|
|
public MCPResource(String modelVersion, int taskId, int eventId) {
|
|
this();
|
|
this.modelVersion = modelVersion;
|
|
this.taskId = taskId;
|
|
this.eventId = eventId;
|
|
this.uri = createResourceUri(modelVersion, taskId, eventId);
|
|
}
|
|
|
|
/**
|
|
* Creates a resource URI from Imixs workflow components
|
|
*/
|
|
public static String createResourceUri(String modelVersion, int taskId, int eventId) {
|
|
if (modelVersion == null || modelVersion.trim().isEmpty()) {
|
|
throw new IllegalArgumentException("Model version cannot be null or empty");
|
|
}
|
|
return String.format("imixs://workflow/%s/%d/%d", modelVersion, taskId, eventId);
|
|
}
|
|
|
|
/**
|
|
* Parses model version from URI
|
|
*/
|
|
public String getModelVersionFromUri() {
|
|
if (uri == null || !uri.startsWith("imixs://workflow/")) {
|
|
throw new IllegalStateException("Invalid resource URI format: " + uri);
|
|
}
|
|
String path = uri.substring("imixs://workflow/".length());
|
|
String[] parts = path.split("/");
|
|
if (parts.length < 3) {
|
|
throw new IllegalStateException("Invalid resource URI format: " + uri);
|
|
}
|
|
return parts[0];
|
|
}
|
|
|
|
/**
|
|
* Parses task ID from URI
|
|
*/
|
|
public int getTaskIdFromUri() {
|
|
if (uri == null || !uri.startsWith("imixs://workflow/")) {
|
|
throw new IllegalStateException("Invalid resource URI format: " + uri);
|
|
}
|
|
String path = uri.substring("imixs://workflow/".length());
|
|
String[] parts = path.split("/");
|
|
if (parts.length < 3) {
|
|
throw new IllegalStateException("Invalid resource URI format: " + uri);
|
|
}
|
|
try {
|
|
return Integer.parseInt(parts[1]);
|
|
} catch (NumberFormatException e) {
|
|
throw new IllegalStateException("Invalid task ID in resource URI: " + uri, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses event ID from URI
|
|
*/
|
|
public int getEventIdFromUri() {
|
|
if (uri == null || !uri.startsWith("imixs://workflow/")) {
|
|
throw new IllegalStateException("Invalid resource URI format: " + uri);
|
|
}
|
|
String path = uri.substring("imixs://workflow/".length());
|
|
String[] parts = path.split("/");
|
|
if (parts.length < 3) {
|
|
throw new IllegalStateException("Invalid resource URI format: " + uri);
|
|
}
|
|
try {
|
|
return Integer.parseInt(parts[2]);
|
|
} catch (NumberFormatException e) {
|
|
throw new IllegalStateException("Invalid event ID in resource URI: " + uri, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Converts this resource to MCP JSON format
|
|
*/
|
|
public JsonObject toJsonObject() {
|
|
JsonObjectBuilder builder = Json.createObjectBuilder()
|
|
.add("uri", uri != null ? uri : "")
|
|
.add("name", name != null ? name : "")
|
|
.add("description", description != null ? description : "");
|
|
|
|
if (mimeType != null) {
|
|
builder.add("mimeType", mimeType);
|
|
}
|
|
|
|
// Annotations object
|
|
if (annotations != null && !annotations.isEmpty()) {
|
|
JsonObjectBuilder annotationsBuilder = Json.createObjectBuilder();
|
|
annotations.forEach((key, value) -> {
|
|
if (value instanceof String) {
|
|
annotationsBuilder.add(key, (String) value);
|
|
} else if (value instanceof Number) {
|
|
annotationsBuilder.add(key, ((Number) value).doubleValue());
|
|
} else if (value instanceof Boolean) {
|
|
annotationsBuilder.add(key, (Boolean) value);
|
|
} else if (value != null) {
|
|
annotationsBuilder.add(key, value.toString());
|
|
}
|
|
});
|
|
builder.add("annotations", annotationsBuilder.build());
|
|
}
|
|
|
|
return builder.build();
|
|
}
|
|
|
|
/**
|
|
* Creates an MCPResource from a JsonObject
|
|
*/
|
|
public static MCPResource fromJsonObject(JsonObject jsonObject) {
|
|
MCPResource resource = new MCPResource();
|
|
|
|
resource.setUri(jsonObject.getString("uri", ""));
|
|
resource.setName(jsonObject.getString("name", ""));
|
|
resource.setDescription(jsonObject.getString("description", ""));
|
|
|
|
if (jsonObject.containsKey("mimeType")) {
|
|
resource.setMimeType(jsonObject.getString("mimeType"));
|
|
}
|
|
|
|
// Annotations
|
|
if (jsonObject.containsKey("annotations")) {
|
|
JsonObject annotationsObject = jsonObject.getJsonObject("annotations");
|
|
Map<String, Object> annotations = new HashMap<>();
|
|
annotationsObject.forEach((key, value) -> {
|
|
switch (value.getValueType()) {
|
|
case STRING:
|
|
annotations.put(key, ((JsonString) value).getString());
|
|
break;
|
|
case NUMBER:
|
|
annotations.put(key, ((jakarta.json.JsonNumber) value).doubleValue());
|
|
break;
|
|
case TRUE:
|
|
annotations.put(key, Boolean.TRUE);
|
|
break;
|
|
case FALSE:
|
|
annotations.put(key, Boolean.FALSE);
|
|
break;
|
|
default:
|
|
annotations.put(key, value.toString());
|
|
}
|
|
});
|
|
resource.setAnnotations(annotations);
|
|
}
|
|
|
|
return resource;
|
|
}
|
|
|
|
/**
|
|
* Validates this resource for MCP compliance
|
|
*/
|
|
public boolean isValid() {
|
|
if (uri == null || uri.trim().isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
if (name == null || name.trim().isEmpty()) {
|
|
return false;
|
|
}
|
|
|
|
// Validate URI format
|
|
try {
|
|
getModelVersionFromUri();
|
|
getTaskIdFromUri();
|
|
getEventIdFromUri();
|
|
} catch (Exception e) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Getters and Setters
|
|
public String getUri() {
|
|
return uri;
|
|
}
|
|
|
|
public void setUri(String uri) {
|
|
this.uri = uri;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
public String getMimeType() {
|
|
return mimeType;
|
|
}
|
|
|
|
public void setMimeType(String mimeType) {
|
|
this.mimeType = mimeType;
|
|
}
|
|
|
|
public Map<String, Object> getAnnotations() {
|
|
return annotations;
|
|
}
|
|
|
|
public void setAnnotations(Map<String, Object> annotations) {
|
|
this.annotations = annotations != null ? annotations : new HashMap<>();
|
|
}
|
|
|
|
public String getModelVersion() {
|
|
return modelVersion;
|
|
}
|
|
|
|
public void setModelVersion(String modelVersion) {
|
|
this.modelVersion = modelVersion;
|
|
}
|
|
|
|
public int getTaskId() {
|
|
return taskId;
|
|
}
|
|
|
|
public void setTaskId(int taskId) {
|
|
this.taskId = taskId;
|
|
}
|
|
|
|
public int getEventId() {
|
|
return eventId;
|
|
}
|
|
|
|
public void setEventId(int eventId) {
|
|
this.eventId = eventId;
|
|
}
|
|
|
|
// Convenience methods for annotations
|
|
public void addAnnotation(String key, Object value) {
|
|
if (annotations == null) {
|
|
annotations = new HashMap<>();
|
|
}
|
|
annotations.put(key, value);
|
|
}
|
|
|
|
public String getAnnotationString(String key) {
|
|
Object value = annotations != null ? annotations.get(key) : null;
|
|
return value != null ? value.toString() : null;
|
|
}
|
|
|
|
public Boolean getAnnotationBoolean(String key) {
|
|
Object value = annotations != null ? annotations.get(key) : null;
|
|
if (value instanceof Boolean) {
|
|
return (Boolean) value;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return String.format("MCPResource{uri='%s', name='%s', modelVersion='%s', taskId=%d, eventId=%d}",
|
|
uri, name, modelVersion, taskId, eventId);
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null || getClass() != obj.getClass())
|
|
return false;
|
|
MCPResource that = (MCPResource) obj;
|
|
return uri != null ? uri.equals(that.uri) : that.uri == null;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return uri != null ? uri.hashCode() : 0;
|
|
}
|
|
} |