diff --git a/pom.xml b/pom.xml index 6075387..5e3d82c 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ 5.7.2 5.2.14.RELEASE 2.34 + 3.3.2 @@ -49,11 +50,28 @@ jackson-databind 2.12.2 + + com.fasterxml.jackson.jaxrs + jackson-jaxrs-json-provider + 2.12.2 + jakarta.ws.rs jakarta.ws.rs-api 2.1.6 + + org.glassfish.jersey.ext + jersey-proxy-client + ${jersey.version} + provided + + + org.apache.cxf + cxf-rt-rs-client + ${cxf.version} + provided + org.glassfish.jersey.core jersey-client @@ -72,12 +90,6 @@ ${jersey.version} test - - org.glassfish.jersey.ext - jersey-proxy-client - ${jersey.version} - test - org.junit.jupiter junit-jupiter-api @@ -90,6 +102,12 @@ ${spring.version} test + + org.apache.httpcomponents + httpclient + 4.5.9 + test + diff --git a/src/main/java/com/inteligr8/alfresco/acs/AcsClient.java b/src/main/java/com/inteligr8/alfresco/acs/AcsClient.java index dbd10c1..728911c 100644 --- a/src/main/java/com/inteligr8/alfresco/acs/AcsClient.java +++ b/src/main/java/com/inteligr8/alfresco/acs/AcsClient.java @@ -2,34 +2,170 @@ package com.inteligr8.alfresco.acs; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.ClientRequestFilter; import javax.ws.rs.client.WebTarget; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.fasterxml.jackson.core.util.JacksonFeature; +import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; +import com.inteligr8.alfresco.acs.api.ActionsApi; +import com.inteligr8.alfresco.acs.api.ActivitiesApi; +import com.inteligr8.alfresco.acs.api.AspectsApi; +import com.inteligr8.alfresco.acs.api.AuditApi; +import com.inteligr8.alfresco.acs.api.AuthenticationApi; +import com.inteligr8.alfresco.acs.api.CommentsApi; +import com.inteligr8.alfresco.acs.api.DiscoveryApi; +import com.inteligr8.alfresco.acs.api.DownloadsApi; +import com.inteligr8.alfresco.acs.api.FavoritesApi; +import com.inteligr8.alfresco.acs.api.GroupsApi; +import com.inteligr8.alfresco.acs.api.NetworksApi; +import com.inteligr8.alfresco.acs.api.NodesApi; +import com.inteligr8.alfresco.acs.api.PeopleApi; +import com.inteligr8.alfresco.acs.api.PreferencesApi; +import com.inteligr8.alfresco.acs.api.ProbesApi; +import com.inteligr8.alfresco.acs.api.QueriesApi; +import com.inteligr8.alfresco.acs.api.RatingsApi; +import com.inteligr8.alfresco.acs.api.RenditionsApi; +import com.inteligr8.alfresco.acs.api.SearchApi; +import com.inteligr8.alfresco.acs.api.SharedLinksApi; +import com.inteligr8.alfresco.acs.api.SitesApi; +import com.inteligr8.alfresco.acs.api.TagsApi; +import com.inteligr8.alfresco.acs.api.TrashcanApi; +import com.inteligr8.alfresco.acs.api.TypesApi; +import com.inteligr8.alfresco.acs.api.VersionsApi; /** * Afresco Content Services Spring Client */ -@Component +@Component("acsClient") public class AcsClient { @Autowired private AcsClientConfiguration config; + protected AcsClientConfiguration getConfig() { + return this.config; + } + public Client getClient() { - Client client = ClientBuilder.newBuilder() - .register(JacksonFeature.class) - .build(); + ClientRequestFilter authFilter = this.config.getAuthorizationFilter(); - this.config.authorize(client); - return client; + ClientBuilder clientBuilder = ClientBuilder.newBuilder() + .register(new JacksonJaxbJsonProvider()); + if (authFilter != null) + clientBuilder.register(authFilter); + + return clientBuilder.build(); } public WebTarget getTarget() { return this.getClient() .target(this.config.getBaseUrl()); } + + protected T getApi(Class apiClass) { + throw new UnsupportedOperationException(); + } + + public ActionsApi getActionsApi() { + return this.getApi(ActionsApi.class); + } + + public ActivitiesApi getActivitiesApi() { + return this.getApi(ActivitiesApi.class); + } + + public AspectsApi getAspectsApi() { + return this.getApi(AspectsApi.class); + } + + public AuditApi getAuditApi() { + return this.getApi(AuditApi.class); + } + + public AuthenticationApi getAuthenticationApi() { + return this.getApi(AuthenticationApi.class); + } + + public CommentsApi getCommentsApi() { + return this.getApi(CommentsApi.class); + } + + public DiscoveryApi getDiscoveryApi() { + return this.getApi(DiscoveryApi.class); + } + + public DownloadsApi getDownloadsApi() { + return this.getApi(DownloadsApi.class); + } + + public FavoritesApi getFavoritesApi() { + return this.getApi(FavoritesApi.class); + } + + public GroupsApi getGroupsApi() { + return this.getApi(GroupsApi.class); + } + + public NetworksApi getNetworksApi() { + return this.getApi(NetworksApi.class); + } + + public NodesApi getNodesApi() { + return this.getApi(NodesApi.class); + } + + public PeopleApi getPeopleApi() { + return this.getApi(PeopleApi.class); + } + + public PreferencesApi getPreferencesApi() { + return this.getApi(PreferencesApi.class); + } + + public ProbesApi getProbesApi() { + return this.getApi(ProbesApi.class); + } + + public QueriesApi getQueriesApi() { + return this.getApi(QueriesApi.class); + } + + public RatingsApi getRatingsApi() { + return this.getApi(RatingsApi.class); + } + + public RenditionsApi getRenditionsApi() { + return this.getApi(RenditionsApi.class); + } + + public SearchApi getSearchApi() { + return this.getApi(SearchApi.class); + } + + public SharedLinksApi getSharedLinksApi() { + return this.getApi(SharedLinksApi.class); + } + + public SitesApi getSitesApi() { + return this.getApi(SitesApi.class); + } + + public TagsApi getTagsApi() { + return this.getApi(TagsApi.class); + } + + public TrashcanApi getTrashcanApi() { + return this.getApi(TrashcanApi.class); + } + + public TypesApi getTypesApi() { + return this.getApi(TypesApi.class); + } + + public VersionsApi getVersionsApi() { + return this.getApi(VersionsApi.class); + } } diff --git a/src/main/java/com/inteligr8/alfresco/acs/AcsClientConfiguration.java b/src/main/java/com/inteligr8/alfresco/acs/AcsClientConfiguration.java index 857ca8e..ff3a402 100644 --- a/src/main/java/com/inteligr8/alfresco/acs/AcsClientConfiguration.java +++ b/src/main/java/com/inteligr8/alfresco/acs/AcsClientConfiguration.java @@ -1,6 +1,6 @@ package com.inteligr8.alfresco.acs; -import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientRequestFilter; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.ComponentScan; @@ -19,18 +19,20 @@ public class AcsClientConfiguration { @Value("${content.service.security.basicAuth.password:admin}") private String basicAuthPassword; - @Value("${content.service.security.accessToken}") + @Value("${content.service.security.accessToken:#{null}}") private String accessToken; public String getBaseUrl() { return this.baseUrl; } - public void authorize(Client client) { + public ClientRequestFilter getAuthorizationFilter() { if (this.accessToken != null) { - client.register(new AccessTokenRequestFilter(this.accessToken)); + return new AccessTokenRequestFilter(this.accessToken); } else if (this.basicAuthUsername != null) { - client.register(new BasicAuthRequestFilter(this.basicAuthUsername, this.basicAuthPassword)); + return new BasicAuthRequestFilter(this.basicAuthUsername, this.basicAuthPassword); + } else { + return null; } } diff --git a/src/main/java/com/inteligr8/alfresco/acs/AcsClientCxfImpl.java b/src/main/java/com/inteligr8/alfresco/acs/AcsClientCxfImpl.java new file mode 100644 index 0000000..2dc699a --- /dev/null +++ b/src/main/java/com/inteligr8/alfresco/acs/AcsClientCxfImpl.java @@ -0,0 +1,58 @@ +package com.inteligr8.alfresco.acs; + +import java.util.LinkedList; +import java.util.List; + +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.ext.RuntimeDelegate; + +import org.apache.cxf.jaxrs.client.JAXRSClientFactory; +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; + +/** + * Afresco Content Services Spring Client for CXF + */ +@Component("acsClient.cxf") +@Lazy +public class AcsClientCxfImpl extends AcsClient implements InitializingBean { + + private final Logger logger = LoggerFactory.getLogger(AcsClientCxfImpl.class); + + @Override + public void afterPropertiesSet() { + if (RuntimeDelegate.getInstance() == null) { + this.logger.info("Setting JAX-RS runtime delegate to the CXF library"); + RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); + } else if (RuntimeDelegate.getInstance() instanceof RuntimeDelegateImpl) { + this.logger.info("JAX-RS runtime delegate already the CXF library"); + } else { + this.logger.warn("Setting JAX-RS runtime delegate to the CXF library; was: " + RuntimeDelegate.getInstance().getClass().getName()); + RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); + } + } + + public WebClient getCxfClient() { + List providersAndFilters = new LinkedList(); + providersAndFilters.add(new JacksonJaxbJsonProvider()); + + ClientRequestFilter authFilter = this.getConfig().getAuthorizationFilter(); + if (authFilter != null) + providersAndFilters.add(authFilter); + + return WebClient.create(this.getConfig().getBaseUrl(), providersAndFilters); + } + + @Override + protected T getApi(Class apiClass) { + return JAXRSClientFactory.fromClient(this.getCxfClient(), apiClass); + } + +} diff --git a/src/main/java/com/inteligr8/alfresco/acs/AcsClientJerseyImpl.java b/src/main/java/com/inteligr8/alfresco/acs/AcsClientJerseyImpl.java new file mode 100644 index 0000000..7cdfcb6 --- /dev/null +++ b/src/main/java/com/inteligr8/alfresco/acs/AcsClientJerseyImpl.java @@ -0,0 +1,40 @@ +package com.inteligr8.alfresco.acs; + +import javax.ws.rs.ext.RuntimeDelegate; + +import org.glassfish.jersey.client.proxy.WebResourceFactory; +import org.glassfish.jersey.internal.RuntimeDelegateImpl; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +/** + * Afresco Content Services Spring Client for Jersey + */ +@Component("acsClient.jersey") +@Lazy +public class AcsClientJerseyImpl extends AcsClient implements InitializingBean { + + private final Logger logger = LoggerFactory.getLogger(AcsClientJerseyImpl.class); + + @Override + public void afterPropertiesSet() { + if (RuntimeDelegate.getInstance() == null) { + this.logger.info("Setting JAX-RS runtime delegate to the Jersey library"); + RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); + } else if (RuntimeDelegate.getInstance() instanceof RuntimeDelegateImpl) { + this.logger.info("JAX-RS runtime delegate already the Jersey library"); + } else { + this.logger.warn("Setting JAX-RS runtime delegate to the Jersey library; was: " + RuntimeDelegate.getInstance().getClass().getName()); + RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); + } + } + + @Override + protected T getApi(Class apiClass) { + return WebResourceFactory.newResource(apiClass, this.getTarget()); + } + +} diff --git a/src/test/java/com/inteligr8/alfresco/acs/ConnectionClientIT.java b/src/test/java/com/inteligr8/alfresco/acs/ConnectionClientIT.java deleted file mode 100644 index 6b95894..0000000 --- a/src/test/java/com/inteligr8/alfresco/acs/ConnectionClientIT.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.inteligr8.alfresco.acs; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpClient.Redirect; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.net.http.HttpResponse.BodyHandlers; - -import javax.ws.rs.client.Client; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.ext.RuntimeDelegate; - -import org.glassfish.jersey.client.proxy.WebResourceFactory; -import org.glassfish.jersey.internal.RuntimeDelegateImpl; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIf; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; - -import com.inteligr8.alfresco.acs.api.DiscoveryApi; -import com.inteligr8.alfresco.acs.model.RepositoryInfo; - -@TestPropertySource(locations = {"/local.properties"}) -@SpringJUnitConfig(classes = {AcsClientConfiguration.class, AcsClient.class}) -public class ConnectionClientIT { - - @BeforeAll - public static void jersey() { - RuntimeDelegateImpl rd = new RuntimeDelegateImpl(); - RuntimeDelegate.setInstance(rd); - Assertions.assertEquals(rd.getClass().getName(), RuntimeDelegate.getInstance().getClass().getName()); - } - - @Autowired - private AcsClient client; - - @Test - //@EnabledIf("hostExists") - public void testDiscovery() { - WebTarget target = this.client.getTarget(); - DiscoveryApi api = WebResourceFactory.newResource(DiscoveryApi.class, target); - RepositoryInfo repoInfo = api.getRepositoryInformation().getEntry().getRepository(); - - Assertions.assertNotNull(repoInfo); - Assertions.assertFalse(repoInfo.getStatus().isIsReadOnly()); - Assertions.assertEquals("6", repoInfo.getVersion().getMajor()); - } - - public boolean hostExists() { - URI uri = this.client.getTarget().getUri(); - - HttpRequest request = HttpRequest.newBuilder(uri) - .GET() - .build(); - - HttpClient client = HttpClient.newBuilder() - .followRedirects(Redirect.ALWAYS) - .build(); - - try { - HttpResponse response = client.send(request, BodyHandlers.discarding()); - return response.statusCode() < 300; - } catch (Exception e) { - return false; - } - } -} diff --git a/src/test/java/com/inteligr8/alfresco/acs/ConnectionCxfClientIT.java b/src/test/java/com/inteligr8/alfresco/acs/ConnectionCxfClientIT.java new file mode 100644 index 0000000..feaae16 --- /dev/null +++ b/src/test/java/com/inteligr8/alfresco/acs/ConnectionCxfClientIT.java @@ -0,0 +1,59 @@ +package com.inteligr8.alfresco.acs; + +import java.net.URI; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.DefaultRedirectStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; + +import com.inteligr8.alfresco.acs.api.DiscoveryApi; +import com.inteligr8.alfresco.acs.model.RepositoryInfo; + +@TestPropertySource(locations = {"/local.properties"}) +@ContextConfiguration(classes = {AcsClientConfiguration.class, AcsClient.class, AcsClientCxfImpl.class}) +public class ConnectionCxfClientIT { + + @Autowired + @Qualifier("acsClient.cxf") + private AcsClient client; + + @Test + @EnabledIf("hostExists") + public void testDiscovery() { + DiscoveryApi api = this.client.getDiscoveryApi(); + RepositoryInfo repoInfo = api.getRepositoryInformation().getEntry().getRepository(); + + Assertions.assertNotNull(repoInfo); + Assertions.assertFalse(repoInfo.getStatus().isIsReadOnly()); + Assertions.assertEquals("6", repoInfo.getVersion().getMajor()); + } + + public boolean hostExists() { + URI uri = this.client.getTarget().getUri(); + + HttpUriRequest request = RequestBuilder.get() + .setUri(uri) + .build(); + + HttpClient client = HttpClientBuilder.create() + .setRedirectStrategy(DefaultRedirectStrategy.INSTANCE) + .build(); + + try { + HttpResponse response = client.execute(request); + return response.getStatusLine().getStatusCode() < 300; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/test/java/com/inteligr8/alfresco/acs/ConnectionJerseyClientIT.java b/src/test/java/com/inteligr8/alfresco/acs/ConnectionJerseyClientIT.java new file mode 100644 index 0000000..5c630e6 --- /dev/null +++ b/src/test/java/com/inteligr8/alfresco/acs/ConnectionJerseyClientIT.java @@ -0,0 +1,58 @@ +package com.inteligr8.alfresco.acs; + +import java.net.URI; + +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.DefaultRedirectStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.junit.jupiter.api.Assertions; +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.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; + +import com.inteligr8.alfresco.acs.api.DiscoveryApi; +import com.inteligr8.alfresco.acs.model.RepositoryInfo; + +@TestPropertySource(locations = {"/local.properties"}) +@ContextConfiguration(classes = {AcsClientConfiguration.class, AcsClient.class, AcsClientJerseyImpl.class}) +public class ConnectionJerseyClientIT { + + @Autowired + @Qualifier("acsClient.jersey") + private AcsClient client; + + @Test + //@EnabledIf("hostExists") + public void testDiscovery() { + DiscoveryApi api = this.client.getDiscoveryApi(); + RepositoryInfo repoInfo = api.getRepositoryInformation().getEntry().getRepository(); + + Assertions.assertNotNull(repoInfo); + Assertions.assertFalse(repoInfo.getStatus().isIsReadOnly()); + Assertions.assertEquals("6", repoInfo.getVersion().getMajor()); + } + + public boolean hostExists() { + URI uri = this.client.getTarget().getUri(); + + HttpUriRequest request = RequestBuilder.get() + .setUri(uri) + .build(); + + HttpClient client = HttpClientBuilder.create() + .setRedirectStrategy(DefaultRedirectStrategy.INSTANCE) + .build(); + + try { + HttpResponse response = client.execute(request); + return response.getStatusLine().getStatusCode() < 300; + } catch (Exception e) { + return false; + } + } +}