Files
rest4i/src/main/java/dev/alexzaw/rest4i/api/jaxrs/IFSRESTService.java
2025-08-15 22:17:59 -07:00

132 lines
13 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package dev.alexzaw.rest4i.api.jaxrs;
import javax.ws.rs.core.MediaType;
import dev.alexzaw.rest4i.api.IFSAPIImpl;
import dev.alexzaw.rest4i.session.Session;
import dev.alexzaw.rest4i.util.CommonUtil;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
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 javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.media.Content;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirements;
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
import org.eclipse.microprofile.openapi.annotations.tags.Tags;
@Path("/")
@Tags({@Tag(name = "IFS Services", description = "Integrated File System (IFS) Services provide APIs for accessing objects in a way that is like personal computer and UNIX operating systems. This includes listing objects in directories, reading from files, and writing to files.")})
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class IFSRESTService extends RESTService {
@Path("/v1/ifs/list")
@GET
@Produces({"application/json; charset=utf-8"})
@APIResponses({@APIResponse(responseCode = "200", description = "Successful request.", content = {@Content(mediaType = "application/json", example = "{\n \"objects\": [\n {\n \"path\": \"/QSYS.LIB/USER1.LIB/QCLSRC.FILE\",\n \"description\": \"\\\"test\\\"\",\n \"isDir\": true,\n \"subType\": \"PF-SRC\"\n },\n {\n \"path\": \"/QSYS.LIB/USER1.LIB/QCSRC.FILE\",\n \"description\": \"\",\n \"isDir\": true,\n \"subType\": \"PF-SRC\"\n },\n {\n \"path\": \"/QSYS.LIB/USER1.LIB/QRPGLESRC.FILE\",\n \"description\": \"\",\n \"isDir\": true,\n \"subType\": \"PF-SRC\"\n },\n {\n \"path\": \"/QSYS.LIB/USER1.LIB/QSQDSRC.FILE\",\n \"description\": \"SQL PROCEDURES\",\n \"isDir\": true,\n \"subType\": \"PF-SRC\"\n },\n {\n \"path\": \"/QSYS.LIB/USER1.LIB/QSRVSRC.FILE\",\n \"description\": \"\",\n \"isDir\": true,\n \"subType\": \"PF-DTA\"\n },\n {\n \"path\": \"/QSYS.LIB/USER1.LIB/QWOBJ.FILE\",\n \"description\": \"\",\n \"isDir\": true,\n \"subType\": \"PF-SRC\"\n },\n {\n \"path\": \"/QSYS.LIB/USER1.LIB/QAUDJR0043.JRNRCV\",\n \"description\": \"\",\n \"isDir\": false,\n \"subType\": \"\"\n }\n ]\n}")}), @APIResponse(responseCode = "400", description = "Bad request."), @APIResponse(responseCode = "401", description = "Unauthorized request was made."), @APIResponse(responseCode = "403", description = "The request is forbidden."), @APIResponse(responseCode = "404", description = "The specified resource was not found."), @APIResponse(responseCode = "500", description = "Unable to process the request due to an internal server error.")})
@Operation(summary = "Gets a list of objects in the specified path.", description = "Gets a list of objects in the specified path. The information returned includes the name, whether object is a directory, the description, and the object subtype. For objects that are not in the QSYS.LIB file system, any part of the path may contain an asterisk (\\*) , which is a wildcard that means zero or more instances of any character. For example, a path of '/tmp/am\\*1.txt' will return all objects in directory '/tmp' that have names that begin with 'am' and end with '1.txt'. For QSYS.LIB objects, only generic names may be specified in any part of the path. A generic name is a character string that contains one or more characters followed by an asterisk. For example, '/qsys.lib/am\\*.lib' will return all libraries that have names that start with 'am'. Another example is /qsys.lib/am\\*.\\*, which would return all objects that start with am. This would be equivalent to specifying a path of /qsys.lib/am\\*'.")
@SecurityRequirements({@SecurityRequirement(name = "bearerHttpAuthentication"), @SecurityRequirement(name = "basicHttpAuthentication")})
public Response ifsListDir(@Context HttpServletRequest req, @Parameter(description = "The authorization HTTP header.") @HeaderParam("Authorization") String authorization, @Parameter(description = "The working directory. For example, /u/IBM/test", required = true) @QueryParam("path") String path, @Parameter(description = "Subtype of objects to return. Valid values include a specific object type (*LIB, *FILE, *PGM, *OUTQ, etc.) or *ALL. Note that many file system objects do not have a subtype. For example, any Root, QOpenSys or UDFS object. ", required = false) @QueryParam("subtype") String subtype, @Parameter(description = "Whether to show hidden files.", required = false) @DefaultValue("false") @QueryParam("includehidden") boolean includehidden) {
CommonUtil._serviceContext.set(req);
Session session = null;
String payload = null;
try {
session = getSession(req, authorization, true);
payload = IFSAPIImpl.ifsListDir(session, path, subtype, includehidden);
} catch (Exception e) {
return handleException("getFiles", e);
} finally {
releaseSession(session);
}
CommonUtil._serviceContext.remove();
return Response.status(Response.Status.OK).entity(payload).build();
}
@Path("/v1/ifs/{path}")
@GET
@Consumes({"*/*"})
@Produces({"application/json; charset=utf-8"})
@APIResponses({@APIResponse(responseCode = "200", description = "Successful request.", content = {@Content(mediaType = "application/json", example = "{\n \"ccsid\": 819,\n \"content\": \"Hello world\\n\"\n}")}), @APIResponse(responseCode = "400", description = "Bad request."), @APIResponse(responseCode = "401", description = "Unauthorized request was made."), @APIResponse(responseCode = "403", description = "The request is forbidden."), @APIResponse(responseCode = "404", description = "The specified resource was not found."), @APIResponse(responseCode = "500", description = "Unable to process the request due to an internal server error.")})
@Operation(summary = "Get the content of a file.", description = "Get the content of a file. The content is returned in a JSON object. ")
@SecurityRequirements({@SecurityRequirement(name = "bearerHttpAuthentication"), @SecurityRequirement(name = "basicHttpAuthentication")})
public Response ifsGetFileContent(@Context HttpServletRequest req, @Parameter(description = "The authorization HTTP header.") @HeaderParam("Authorization") String authorization, @Parameter(description = "Whether to return checksum for the file.", required = false) @HeaderParam("ETag") boolean etag, @Parameter(description = "Path to file for which the data is to be read.", required = true) @PathParam("path") String path) {
CommonUtil._serviceContext.set(req);
Session session = null;
String payload = null;
IFSAPIImpl.IFSFileOperationResult output = null;
try {
session = getSession(req, authorization, true);
output = IFSAPIImpl.ifsGetFileContent(session, path, etag);
payload = output.fileContentInternal_.toJSON();
} catch (Exception e) {
return handleException("getFileContent", e);
} finally {
releaseSession(session);
}
CommonUtil._serviceContext.remove();
if (output.etagHeader_ != null)
return Response.status(Response.Status.OK).header("ETag", output.etagHeader_).entity(payload).build();
return Response.status(Response.Status.OK).entity(payload).build();
}
@Path("/v1/ifs/{path}")
@PUT
@Consumes({"application/json", "text/plain"})
@APIResponses({@APIResponse(responseCode = "204", description = "Successful request, no content."), @APIResponse(responseCode = "400", description = "Bad request."), @APIResponse(responseCode = "401", description = "Unauthorized request was made."), @APIResponse(responseCode = "403", description = "The request is forbidden."), @APIResponse(responseCode = "404", description = "The specified resource was not found."), @APIResponse(responseCode = "412", description = "Precondition failed."), @APIResponse(responseCode = "500", description = "Unable to process the request due to an internal server error.")})
@Operation(summary = "Write a string to a file.", description = "Write a string to a file. The file must exist and its contents will be replaced by the string specified in the request.")
@SecurityRequirements({@SecurityRequirement(name = "bearerHttpAuthentication"), @SecurityRequirement(name = "basicHttpAuthentication")})
public Response ifsPutFileContent(@Context HttpServletRequest req, @Parameter(description = "The authorization HTTP header.") @HeaderParam("Authorization") String authorization, @Parameter(description = "If the If-Match HTTP header is passed, RSE API will check to see if the Etag (MD5 hash of the object content) matches the provided Etag value. If this value matches, the operation will proceed. If the match fails, the system will return a 412 (Precondition Failed) error.", required = false) @HeaderParam("If-Match") String matchEtag, @Parameter(description = "Path to file in which the data will be written.", required = true) @PathParam("path") String path, @RequestBody(description = "File content.", required = true, content = {@Content(schema = @Schema(implementation = IFSAPIImpl.RSEAPI_FileContent.class), mediaType = "application/json", example = "{\n \"content\": \"some data that will be written to file.\"\n}"), @Content(mediaType = "text/plain", example = "some data that will be written to file.\n")}) IFSAPIImpl.RSEAPI_FileContent fileContentInfo) {
CommonUtil._serviceContext.set(req);
Session session = null;
String newChecksum = null;
try {
session = getSession(req, authorization, true);
newChecksum = IFSAPIImpl.ifsPutFileContent(session, path, matchEtag, fileContentInfo.content);
} catch (Exception e) {
return handleException("putFileContent", e);
} finally {
releaseSession(session);
}
CommonUtil._serviceContext.remove();
if (matchEtag != null && newChecksum != null)
return Response.status(Response.Status.NO_CONTENT).header("ETag", newChecksum).build();
return Response.status(Response.Status.NO_CONTENT).build();
}
@Path("/v1/ifs/{path}/info")
@GET
@Produces({"application/json; charset=utf-8"})
@APIResponses({@APIResponse(responseCode = "200", description = "Successful request.", content = {@Content(mediaType = "application/json", example = "{\n \"path\": \"/qsys.lib/user1.lib\",\n \"description\": \"user1's lib\",\n \"isDir\": true,\n \"subType\": \"PROD\",\n \"owner\": \"USER1\",\n \"ccsid\": 37,\n \"lastModified\": 1680559633,\n \"size\": 401408,\n \"recordLength\": -1,\n \"numberOfRecords\": -1\n}")}), @APIResponse(responseCode = "400", description = "Bad request."), @APIResponse(responseCode = "401", description = "Unauthorized request was made."), @APIResponse(responseCode = "403", description = "The request is forbidden."), @APIResponse(responseCode = "404", description = "The specified resource was not found."), @APIResponse(responseCode = "500", description = "Unable to process the request due to an internal server error.")})
@Operation(summary = "Returns information about the object referenced by the path.", description = "Returns information about the object referenced by the path. The information returned includes the name, whether object is a directory, the description, the object subtype, CCSID, size, last modified timestamp, and object subtype.")
@SecurityRequirements({@SecurityRequirement(name = "bearerHttpAuthentication"), @SecurityRequirement(name = "basicHttpAuthentication")})
public Response ifsGetFileInfo(@Context HttpServletRequest req, @Parameter(description = "The authorization HTTP header.") @HeaderParam("Authorization") String authorization, @Parameter(description = "Path to object for which information is to be returned.", required = true) @PathParam("path") String path) {
CommonUtil._serviceContext.set(req);
Session session = null;
String payload = null;
try {
session = getSession(req, authorization, true);
payload = IFSAPIImpl.ifsGetFileInfo(session, path);
} catch (Exception e) {
return handleException("getFileInfo", e);
} finally {
releaseSession(session);
}
CommonUtil._serviceContext.remove();
return Response.status(Response.Status.OK).entity(payload).build();
}
}