ACS-12297 Zero Dependency Storage Connector AMP (#4242)

This commit is contained in:
Cezary Witkowski
2026-07-31 10:00:18 +02:00
committed by GitHub
parent 3c1d3e724e
commit a8d40ef941
3 changed files with 166 additions and 23 deletions
+18
View File
@@ -57,12 +57,30 @@
<groupId>jakarta.xml.soap</groupId>
<artifactId>jakarta.xml.soap-api</artifactId>
</dependency>
<!-- Google drive AMP -->
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-drive</artifactId>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-oauth2</artifactId>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
</dependency>
<!-- 'provided' dependencies, not packaged in war -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<!-- Test dependencies -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-core</artifactId>
@@ -0,0 +1,119 @@
/*
* #%L
* Alfresco Content Services Community WAR
* %%
* Copyright (C) 2026 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.integrations.compatibility;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.List;
import com.fasterxml.jackson.core.Version;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.apache.v2.ApacheHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.model.File;
import org.junit.Test;
/**
* Guards the compatibility contract the community content-services WAR owns for the Google Drive SDK it ships (so the Google Drive AMPs can stay zero-dependency): the bundled Drive SDK must be binary-compatible with the platform libraries it now runs against (jackson, guava, httpclient), and jackson must resolve to a single platform-aligned version.
*
* <p>
* The Drive SDK jars (google-api-services-drive, google-api-services-oauth2, google-http-client-jackson2 and their transitives) are compile dependencies of this module, so they are on the test classpath at exactly the versions {@code WEB-INF/lib} ships - resolved through the alfresco-community-repo dependency management, where the jackson BOM is imported ahead of the Google libraries BOM. A downgraded or SDK-driven library surfaces here as a {@code NoSuchMethodError} / {@code NoClassDefFoundError} on the build instead of in a deployed repository.
* </p>
*
* <p>
* Everything is offline: the clients are only constructed to force resolution of the SDK's dependency graph - no credentials, Drive files or network are touched.
* </p>
*/
public class DriveSdkPlatformCompatibilityTest
{
@Test
public void jacksonModulesResolveToASinglePlatformAlignedVersion()
{
// The jackson the Drive SDK parses JSON with (via google-http-client-jackson2) must land on the
// same minor line as the platform jackson-databind; otherwise the SDK's own (newer) jackson has
// leaked past the platform-aligned jackson BOM.
String platform = minor(com.fasterxml.jackson.core.json.PackageVersion.VERSION);
assertEquals("jackson-databind must match the platform jackson-core minor line",
platform, minor(com.fasterxml.jackson.databind.cfg.PackageVersion.VERSION));
}
@Test
public void buildsDriveClientAgainstPlatformDependencies()
{
Drive drive = new Drive.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance(), null)
.setApplicationName("smoke-test")
.build();
assertNotNull(drive);
}
@Test
public void serialisesDriveRestModelWithPlatformJackson() throws Exception
{
File file = new File()
.setName("smoke.txt")
.setMimeType("text/plain")
.setParents(List.of("root"));
JsonFactory factory = JacksonFactory.getDefaultInstance();
File parsed = factory.fromString(factory.toString(file), File.class);
assertEquals("smoke.txt", parsed.getName());
assertEquals("text/plain", parsed.getMimeType());
}
@Test
public void exercisesSdkJsonTransportAgainstPlatformJacksonAndGson() throws Exception
{
roundTripJson(JacksonFactory.getDefaultInstance());
roundTripJson(GsonFactory.getDefaultInstance());
}
@Test
public void buildsApacheHttpTransportFromPlatformHttpClient() throws Exception
{
HttpTransport transport = new ApacheHttpTransport();
transport.shutdown();
}
private static void roundTripJson(JsonFactory factory) throws Exception
{
GenericJson object = new GenericJson();
object.set("name", "smoke.txt");
object.set("mimeType", "text/plain");
GenericJson parsed = factory.fromString(factory.toString(object), GenericJson.class);
assertEquals("smoke.txt", parsed.get("name"));
}
private static String minor(Version version)
{
return version.getMajorVersion() + "." + version.getMinorVersion();
}
}
+29 -23
View File
@@ -61,7 +61,6 @@
<dependency.spring-security.version>7.0.6</dependency.spring-security.version>
<dependency.antlr.version>3.5.3</dependency.antlr.version>
<dependency.jackson.version>2.22.0</dependency.jackson.version>
<dependency.jackson.annotations.version>2.22</dependency.jackson.annotations.version>
<dependency.cxf.version>4.1.7</dependency.cxf.version>
<dependency.opencmis.version>1.0.0-jakarta-1</dependency.opencmis.version>
<dependency.webscripts.version>10.2</dependency.webscripts.version>
@@ -81,6 +80,10 @@
<dependency.httpcomponents-httpcore5-h2.version>5.3.4</dependency.httpcomponents-httpcore5-h2.version>
<dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version>
<dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version>
<dependency.google-cloud-libraries-bom.version>26.84.0</dependency.google-cloud-libraries-bom.version>
<dependency.google-api-services-drive.version>v3-rev20250511-2.0.0</dependency.google-api-services-drive.version>
<dependency.google-api-services-oauth2.version>v2-rev20200213-2.0.0</dependency.google-api-services-oauth2.version>
<dependency.opencensus.version>0.31.1</dependency.opencensus.version>
<dependency.slf4j.version>2.0.16</dependency.slf4j.version>
<dependency.log4j.version>2.25.4</dependency.log4j.version>
<dependency.groovy.version>3.0.25</dependency.groovy.version>
@@ -611,41 +614,44 @@
<version>${dependency.spring.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<groupId>com.fasterxml.jackson</groupId>
<artifactId>jackson-bom</artifactId>
<version>${dependency.jackson.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${dependency.jackson.version}</version>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>${dependency.google-cloud-libraries-bom.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${dependency.jackson.version}</version>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-drive</artifactId>
<version>${dependency.google-api-services-drive.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${dependency.jackson.version}</version>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-oauth2</artifactId>
<version>${dependency.google-api-services-oauth2.version}</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-api</artifactId>
<version>${dependency.opencensus.version}</version>
</dependency>
<dependency>
<groupId>io.opencensus</groupId>
<artifactId>opencensus-contrib-http-util</artifactId>
<version>${dependency.opencensus.version}</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${dependency.jackson.annotations.version}</version>
</dependency>
<!-- newer dependency from camel-jackson -->
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${dependency.jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>