From 879bda7e36df3a44dea013262fbf96d4d24f867f Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Tue, 8 Mar 2022 13:36:12 -0500 Subject: [PATCH 1/3] added log4j logging for testing --- pom.xml | 6 ++++++ src/test/resources/log4j2.properties | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/test/resources/log4j2.properties diff --git a/pom.xml b/pom.xml index 3e28155..d86f989 100644 --- a/pom.xml +++ b/pom.xml @@ -97,6 +97,12 @@ 4.5.9 test + + org.apache.logging.log4j + log4j-slf4j-impl + 2.16.0 + test + diff --git a/src/test/resources/log4j2.properties b/src/test/resources/log4j2.properties new file mode 100644 index 0000000..df444d4 --- /dev/null +++ b/src/test/resources/log4j2.properties @@ -0,0 +1,19 @@ +rootLogger.level=trace +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.spring.name=org.springframework +logger.spring.level=info + +logger.common-rest-api.name=com.inteligr8.rs +logger.common-rest-api.level=trace + +logger.this.name=com.inteligr8.alfresco.acs +logger.this.level=trace + +logger.jaxrslog.name=jaxrs.request +logger.jaxrslog.level=trace + +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%C [%t] %m%n From 1972a5ca468def381e5b3763da4bf89ebaf05f69 Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Tue, 8 Mar 2022 13:36:26 -0500 Subject: [PATCH 2/3] added upload vscode test --- src/test/vscode/createNode.http | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/test/vscode/createNode.http diff --git a/src/test/vscode/createNode.http b/src/test/vscode/createNode.http new file mode 100644 index 0000000..99f9ed1 --- /dev/null +++ b/src/test/vscode/createNode.http @@ -0,0 +1,53 @@ +@baseUrl = http://localhost:8080/alfresco +@username = admin +@password = admin + +### Find Folder +# @name find +POST {{baseUrl}}/api/-default-/public/search/versions/1/search HTTP/1.1 +Authorization: Basic {{username}}:{{password}} + +{ + "query": { + "language": "afts", + "query": "=@cm:name:'Shared'" + } +} + +@folderNodeId = {{find.response.body.list.entries[0].entry.id}} + +### Upload File +# @name upload +POST {{baseUrl}}/api/-default-/public/alfresco/versions/1/nodes/{{folderNodeId}}/children?autoRename=true +Authorization: Basic {{username}}:{{password}} +Content-type: application/json + +{ + "name": "TestFolder", + "nodeType": "cm:content", + "properties": null +} + +### Upload File +# @name upload-form +POST {{baseUrl}}/api/-default-/public/alfresco/versions/1/nodes/{{folderNodeId}}/children +Authorization: Basic {{username}}:{{password}} +Content-type: multipart/form-data; boundary=----Test + +------Test +Content-disposition: form-data; name="name" + +TestFolder +------Test +Content-disposition: form-data; name="nodeType" + +cm:content +------Test +Content-disposition: form-data; name="autoRename" + +true +------Test +Content-disposition: form-data; name="filedata"; filename="test.txt" + +This is a test +------Test-- \ No newline at end of file From 177ab2bd5385d31535cd28ed6728c89020392f0b Mon Sep 17 00:00:00 2001 From: "Brian M. Long" Date: Tue, 8 Mar 2022 13:36:39 -0500 Subject: [PATCH 3/3] fixed CXF createNode --- .../acs/api/NodeBodyCreateMultipart.java | 99 +++++++++++++++++++ .../alfresco/acs/api/NodesCxfApi.java | 48 ++++++--- .../alfresco/acs/api/NodesJerseyApi.java | 11 +-- .../alfresco/acs/ConnectionCxfClientIT.java | 34 ++++++- 4 files changed, 170 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/inteligr8/alfresco/acs/api/NodeBodyCreateMultipart.java diff --git a/src/main/java/com/inteligr8/alfresco/acs/api/NodeBodyCreateMultipart.java b/src/main/java/com/inteligr8/alfresco/acs/api/NodeBodyCreateMultipart.java new file mode 100644 index 0000000..90236f8 --- /dev/null +++ b/src/main/java/com/inteligr8/alfresco/acs/api/NodeBodyCreateMultipart.java @@ -0,0 +1,99 @@ +package com.inteligr8.alfresco.acs.api; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.core.MediaType; + +import org.apache.cxf.jaxrs.ext.multipart.Attachment; +import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition; +import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.inteligr8.alfresco.acs.model.NodeBodyCreate; + +public class NodeBodyCreateMultipart extends MultipartBody { + + private static final ObjectMapper om = new ObjectMapper(); + + public static NodeBodyCreateMultipart from( + NodeBodyCreate nodeBody, String filename, InputStream istream, + Boolean autoRename, Boolean majorVersion, Boolean versioningEnabled) throws IOException { + List atts = new LinkedList<>(); + atts.addAll(toAttachments(nodeBody)); + if (autoRename != null) + atts.add(toAttachment("autoRename", String.valueOf(autoRename))); + if (majorVersion != null) + atts.add(toAttachment("majorVersion", String.valueOf(majorVersion))); + if (versioningEnabled != null) + atts.add(toAttachment("versioningEnabled", String.valueOf(versioningEnabled))); + atts.add(toAttachment(filename, istream)); + return new NodeBodyCreateMultipart(atts, true); + } + + public NodeBodyCreateMultipart(List atts) throws IOException { + super(atts); + } + + public NodeBodyCreateMultipart(List atts, boolean outbound) throws IOException { + super(atts, outbound); + } + + public NodeBodyCreate getBody() throws IOException { + if (!MediaType.APPLICATION_JSON_TYPE.equals(this.getRootAttachment().getContentType())) + throw new IllegalStateException(); + + InputStream istream = this.getRootAttachment().getDataHandler().getInputStream(); + try { + return om.readValue(istream, NodeBodyCreate.class); + } finally { + istream.close(); + } + } + + public Attachment getFiledataAttachment() { + return this.getAttachment("filedata"); + } + + + + @SuppressWarnings("unchecked") + private static List toAttachments(NodeBodyCreate nodeBody) throws IOException { + List atts = new LinkedList<>(); + atts.add(toAttachment("name", nodeBody.getName())); + atts.add(toAttachment("nodeType", nodeBody.getNodeType())); + if (nodeBody.getAspectNames() != null) + atts.add(toAttachment("aspectNames", nodeBody.getAspectNames())); + if (nodeBody.getProperties() != null) + atts.add(toAttachment("properties", (Map)nodeBody.getProperties())); + return atts; + } + + private static Attachment toAttachment(String name, String value) { + return new Attachment(name, new ByteArrayInputStream(value.getBytes()), new ContentDisposition("form-data; name=\"" + name + "\"")); + } + + private static Attachment toAttachment(String name, Collection c) throws JsonProcessingException { + return toJsonAttachment(name, c); + } + + private static Attachment toAttachment(String name, Map map) throws JsonProcessingException { + return toJsonAttachment(name, map); + } + + private static Attachment toJsonAttachment(String name, Object obj) throws JsonProcessingException { + String json = om.writeValueAsString(obj); + return new Attachment(name, new ByteArrayInputStream(json.getBytes()), new ContentDisposition("form-data; name=\"" + name + "\"")); + } + + private static Attachment toAttachment(String filename, InputStream istream) { + return new Attachment("filedata", istream, new ContentDisposition("form-data; name=\"filedata\"; filename=\"" + filename + "\"")); + } + +} diff --git a/src/main/java/com/inteligr8/alfresco/acs/api/NodesCxfApi.java b/src/main/java/com/inteligr8/alfresco/acs/api/NodesCxfApi.java index fcfd028..f4f69ea 100644 --- a/src/main/java/com/inteligr8/alfresco/acs/api/NodesCxfApi.java +++ b/src/main/java/com/inteligr8/alfresco/acs/api/NodesCxfApi.java @@ -1,20 +1,15 @@ package com.inteligr8.alfresco.acs.api; -import java.util.List; - import javax.ws.rs.Consumes; import javax.ws.rs.POST; 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.MediaType; -import org.apache.cxf.jaxrs.ext.multipart.Attachment; -import org.apache.cxf.jaxrs.ext.multipart.Multipart; +import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; import com.inteligr8.alfresco.acs.model.Error; -import com.inteligr8.alfresco.acs.model.NodeBodyCreate; import com.inteligr8.alfresco.acs.model.NodeEntry; import io.swagger.annotations.Api; @@ -31,7 +26,7 @@ public interface NodesCxfApi { @Consumes({ MediaType.MULTIPART_FORM_DATA }) @Produces({ MediaType.APPLICATION_JSON }) @ApiOperation(value = "Create a node", tags={ }) - @ApiResponses(value = { + @ApiResponses(value = { @ApiResponse(code = 201, message = "Successful response", response = NodeEntry.class), @ApiResponse(code = 400, message = "Invalid parameter: **nodeId** is not a valid format or **nodeBodyCreate** is invalid "), @ApiResponse(code = 401, message = "Authentication failed"), @@ -45,12 +40,35 @@ public interface NodesCxfApi { @ApiResponse(code = 200, message = "Unexpected error", response = Error.class) }) public NodeEntry createNode( @PathParam("nodeId") String nodeId, - @Multipart NodeBodyCreate nodeBodyCreate, - @QueryParam("autoRename") Boolean autoRename, - @QueryParam("majorVersion") Boolean majorVersion, - @QueryParam("versioningEnabled") Boolean versioningEnabled, - @QueryParam("include") List include, - @QueryParam("fields") List fields, - @Multipart(value = "filedata", required = false) Attachment attachment); - + MultipartBody body); +/* + * This better impl doesn't work + * + @POST + @Path("/nodes/{nodeId}/children") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + @ApiOperation(value = "Create a node", tags={ }) + @ApiResponses(value = { + @ApiResponse(code = 201, message = "Successful response", response = NodeEntry.class), + @ApiResponse(code = 400, message = "Invalid parameter: **nodeId** is not a valid format or **nodeBodyCreate** is invalid "), + @ApiResponse(code = 401, message = "Authentication failed"), + @ApiResponse(code = 403, message = "Current user does not have permission to create children of **nodeId**"), + @ApiResponse(code = 404, message = "**nodeId** or **renditionId** does not exist "), + @ApiResponse(code = 409, message = "New name clashes with an existing node in the current parent folder"), + @ApiResponse(code = 413, message = "Content exceeds individual file size limit configured for the network or system"), + @ApiResponse(code = 415, message = "Content Type is not supported"), + @ApiResponse(code = 422, message = "Model integrity exception including a file name containing invalid characters"), + @ApiResponse(code = 507, message = "Content exceeds overall storage quota limit configured for the network or system"), + @ApiResponse(code = 200, message = "Unexpected error", response = Error.class) }) + public NodeEntry createNode( + @PathParam("nodeId") String nodeId, + @Multipart("name") String name, + @Multipart("nodeType") String nodeType, + @Multipart("filedata") InputStream fileStream, + @Multipart("filedata") ContentDisposition disposition, + @Multipart(value = "autoRename", required = false) Boolean autoRename, + @Multipart(value = "majorVersion", required = false) Boolean majorVersion, + @Multipart(value = "versioningEnabled", required = false) Boolean versioningEnabled); +*/ } diff --git a/src/main/java/com/inteligr8/alfresco/acs/api/NodesJerseyApi.java b/src/main/java/com/inteligr8/alfresco/acs/api/NodesJerseyApi.java index 6bbccfb..d5d59b2 100644 --- a/src/main/java/com/inteligr8/alfresco/acs/api/NodesJerseyApi.java +++ b/src/main/java/com/inteligr8/alfresco/acs/api/NodesJerseyApi.java @@ -8,7 +8,6 @@ import javax.ws.rs.POST; 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.MediaType; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; @@ -47,11 +46,11 @@ public interface NodesJerseyApi { public NodeEntry createNode( @PathParam("nodeId") String nodeId, NodeBodyCreate nodeBodyCreate, - @QueryParam("autoRename") Boolean autoRename, - @QueryParam("majorVersion") Boolean majorVersion, - @QueryParam("versioningEnabled") Boolean versioningEnabled, - @QueryParam("include") List include, - @QueryParam("fields") List fields, + @FormDataParam("autoRename") Boolean autoRename, + @FormDataParam("majorVersion") Boolean majorVersion, + @FormDataParam("versioningEnabled") Boolean versioningEnabled, + @FormDataParam("include") List include, + @FormDataParam("fields") List fields, @FormDataParam("filedata") InputStream filedataStream, @FormDataParam("filedata") FormDataContentDisposition filedataDisposition); diff --git a/src/test/java/com/inteligr8/alfresco/acs/ConnectionCxfClientIT.java b/src/test/java/com/inteligr8/alfresco/acs/ConnectionCxfClientIT.java index 4b979c1..31379e7 100644 --- a/src/test/java/com/inteligr8/alfresco/acs/ConnectionCxfClientIT.java +++ b/src/test/java/com/inteligr8/alfresco/acs/ConnectionCxfClientIT.java @@ -1,10 +1,21 @@ package com.inteligr8.alfresco.acs; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import com.inteligr8.alfresco.acs.api.NodeBodyCreateMultipart; +import com.inteligr8.alfresco.acs.model.NodeBodyCreate; +import com.inteligr8.alfresco.acs.model.RequestQuery; +import com.inteligr8.alfresco.acs.model.RequestQuery.LanguageEnum; +import com.inteligr8.alfresco.acs.model.ResultNode; +import com.inteligr8.alfresco.acs.model.ResultSetPaging; +import com.inteligr8.alfresco.acs.model.SearchRequest; import com.inteligr8.rs.ClientConfiguration; @TestPropertySource(locations = {"/local.properties"}) @@ -13,7 +24,7 @@ public class ConnectionCxfClientIT extends ConnectionClientIT { @Autowired @Qualifier("acs.api.cxf") - private AcsPublicRestApi client; + private AcsPublicRestApiCxfImpl client; @Override public AcsPublicRestApi getClient() { @@ -25,4 +36,25 @@ public class ConnectionCxfClientIT extends ConnectionClientIT { return this.client.getConfig(); } + @Test + public void uploadFile() throws IOException { + RequestQuery query = new RequestQuery(); + query.setLanguage(LanguageEnum.AFTS); + query.setQuery("=@cm:name:'Shared'"); + + SearchRequest searchRequest = new SearchRequest(); + searchRequest.setQuery(query); + + ResultSetPaging paging = this.client.getSearchApi().search(searchRequest); + ResultNode folderNode = paging.getList().getEntries().iterator().next().getEntry(); + String folderNodeId = folderNode.getId(); + + NodeBodyCreate nodeBody = new NodeBodyCreate().nodeType("cm:content").name("TestFolder"); + + ByteArrayInputStream istream = new ByteArrayInputStream("This is a test".getBytes()); + NodeBodyCreateMultipart body = NodeBodyCreateMultipart.from(nodeBody, "test.txt", istream, true, null, null); + + this.client.getNodesExtApi().createNode(folderNodeId, body); + } + }