http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/lib/pom.xml ---------------------------------------------------------------------- diff --git a/client/lib/pom.xml b/client/lib/pom.xml new file mode 100644 index 0000000..c4886be --- /dev/null +++ b/client/lib/pom.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.syncope</groupId> + <artifactId>syncope-client</artifactId> + <version>2.0.0-SNAPSHOT</version> + </parent> + + <name>Apache Syncope Client Lib</name> + <description>Apache Syncope Client Lib</description> + <groupId>org.apache.syncope.client</groupId> + <artifactId>syncope-client-lib</artifactId> + <packaging>jar</packaging> + + <properties> + <rootpom.basedir>${basedir}/../..</rootpom.basedir> + </properties> + + <dependencies> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-rs-client</artifactId> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.jaxrs</groupId> + <artifactId>jackson-jaxrs-json-provider</artifactId> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.apache.syncope.common</groupId> + <artifactId>syncope-common-rest-api</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + </plugin> + </plugins> + </build> +</project>
http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java ---------------------------------------------------------------------- diff --git a/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java new file mode 100644 index 0000000..bb772bc --- /dev/null +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientExceptionMapper.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.lib; + +import java.security.AccessControlException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.ws.rs.BadRequestException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import javax.xml.ws.WebServiceException; +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.jaxrs.client.ResponseExceptionMapper; +import org.apache.syncope.common.lib.SyncopeClientCompositeException; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.types.ClientExceptionType; +import org.apache.syncope.common.rest.api.RESTHeaders; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Provider +public class RestClientExceptionMapper implements ExceptionMapper<Exception>, ResponseExceptionMapper<Exception> { + + private static final Logger LOG = LoggerFactory.getLogger(RestClientExceptionMapper.class); + + @Override + public Response toResponse(final Exception exception) { + throw new UnsupportedOperationException( + "Call of toResponse() method is not expected in RestClientExceptionnMapper"); + } + + @Override + public Exception fromResponse(final Response response) { + final int statusCode = response.getStatus(); + Exception ex; + + // 1. Check for client (possibly composite) exception in HTTP header + SyncopeClientCompositeException scce = checkSyncopeClientCompositeException(response); + if (scce != null) { + if (scce.getExceptions().size() == 1) { + ex = scce.getExceptions().iterator().next(); + } else { + ex = scce; + } + } // 2. Map SC_UNAUTHORIZED + else if (statusCode == Response.Status.UNAUTHORIZED.getStatusCode()) { + ex = new AccessControlException("Remote unauthorized exception"); + } // 3. Map SC_BAD_REQUEST + else if (statusCode == Response.Status.BAD_REQUEST.getStatusCode()) { + ex = new BadRequestException(); + } // 4. All other codes are mapped to runtime exception with HTTP code information + else { + ex = new WebServiceException(String.format("Remote exception with status code: %s", + Response.Status.fromStatusCode(statusCode).name())); + } + LOG.error("Exception thrown by REST methods: " + ex.getMessage(), ex); + return ex; + } + + private SyncopeClientCompositeException checkSyncopeClientCompositeException(final Response response) { + List<Object> exTypesInHeaders = response.getHeaders().get(RESTHeaders.ERROR_CODE); + if (exTypesInHeaders == null) { + LOG.debug("No " + RESTHeaders.ERROR_CODE + " provided"); + return null; + } + + final SyncopeClientCompositeException compException = SyncopeClientException.buildComposite(); + + final Set<String> handledExceptions = new HashSet<String>(); + for (Object exceptionTypeValue : exTypesInHeaders) { + final String exTypeAsString = (String) exceptionTypeValue; + ClientExceptionType exceptionType = null; + try { + exceptionType = ClientExceptionType.fromHeaderValue(exTypeAsString); + } catch (IllegalArgumentException e) { + LOG.error("Unexpected value of " + RESTHeaders.ERROR_CODE + ": " + exTypeAsString, e); + } + if (exceptionType != null) { + handledExceptions.add(exTypeAsString); + + final SyncopeClientException clientException = SyncopeClientException.build(exceptionType); + + if (response.getHeaders().get(RESTHeaders.ERROR_INFO) != null + && !response.getHeaders().get(RESTHeaders.ERROR_INFO).isEmpty()) { + + for (Object value : response.getHeaders().get(RESTHeaders.ERROR_INFO)) { + final String element = value.toString(); + if (element.startsWith(exceptionType.getHeaderValue())) { + clientException.getElements().add(StringUtils.substringAfter(value.toString(), ":")); + } + } + } + compException.addException(clientException); + } + } + + exTypesInHeaders.removeAll(handledExceptions); + if (!exTypesInHeaders.isEmpty()) { + LOG.error("Unmanaged exceptions: " + exTypesInHeaders); + } + + if (compException.hasExceptions()) { + return compException; + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java ---------------------------------------------------------------------- diff --git a/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java new file mode 100644 index 0000000..4d77f2f --- /dev/null +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/RestClientFactoryBean.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.lib; + +import javax.ws.rs.core.MediaType; +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; +import org.apache.cxf.jaxrs.client.WebClient; + +/** + * Provides shortcuts for creating JAX-RS service instances via CXF's <tt>JAXRSClientFactoryBean</tt>. + */ +public class RestClientFactoryBean extends JAXRSClientFactoryBean { + + /** + * Creates an anonymous instance of the given service class, for the given content type. + * + * @param <T> any service class + * @param serviceClass service class reference + * @param mediaType XML or JSON are suppoorted + * @return anonymous service instance of the given reference class + */ + public <T> T createServiceInstance(final Class<T> serviceClass, final MediaType mediaType) { + return createServiceInstance(serviceClass, mediaType, null, null); + } + + /** + * Creates an authenticated instance of the given service class, for the given content type. + * + * @param <T> any service class + * @param serviceClass service class reference + * @param mediaType XML or JSON are suppoorted + * @param username username for REST authentication + * @param password password for REST authentication + * @return anonymous service instance of the given reference class + */ + public <T> T createServiceInstance( + final Class<T> serviceClass, final MediaType mediaType, final String username, final String password) { + + if (StringUtils.isNotBlank(username)) { + setUsername(username); + } + if (StringUtils.isNotBlank(password)) { + setPassword(password); + } + setServiceClass(serviceClass); + final T serviceInstance = create(serviceClass); + WebClient.client(serviceInstance).type(mediaType).accept(mediaType); + return serviceInstance; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java ---------------------------------------------------------------------- diff --git a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java new file mode 100644 index 0000000..43c2fea --- /dev/null +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClient.java @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.lib; + +import javax.ws.rs.core.EntityTag; +import javax.ws.rs.core.MediaType; +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.syncope.common.lib.search.OrderByClauseBuilder; +import org.apache.syncope.common.lib.search.RoleFiqlSearchConditionBuilder; +import org.apache.syncope.common.lib.search.UserFiqlSearchConditionBuilder; +import org.apache.syncope.common.rest.api.Preference; +import org.apache.syncope.common.rest.api.RESTHeaders; + +/** + * Entry point for client access to all REST services exposed by Syncope core; obtain instances via + * {@link SyncopeClientFactoryBean}. + */ +public class SyncopeClient { + + private final MediaType mediaType; + + private final RestClientFactoryBean restClientFactory; + + private final String username; + + private final String password; + + public SyncopeClient(final MediaType mediaType, final RestClientFactoryBean restClientFactory, + final String username, final String password) { + + this.mediaType = mediaType; + this.restClientFactory = restClientFactory; + this.username = username; + this.password = password; + } + + /** + * Returns a new instance of <tt>UserFiqlSearchConditionBuilder</tt>, for assisted building of FIQL queries. + * + * @return default instance of <tt>UserFiqlSearchConditionBuilder</tt> + */ + public static UserFiqlSearchConditionBuilder getUserSearchConditionBuilder() { + return new UserFiqlSearchConditionBuilder(); + } + + /** + * Returns a new instance of <tt>RoleFiqlSearchConditionBuilder</tt>, for assisted building of FIQL queries. + * + * @return default instance of <tt>RoleFiqlSearchConditionBuilder</tt> + */ + public static RoleFiqlSearchConditionBuilder getRoleSearchConditionBuilder() { + return new RoleFiqlSearchConditionBuilder(); + } + + /** + * Returns a new instance of <tt>OrderByClauseBuilder</tt>, for assisted building of <tt>orderby</tt> clauses. + * + * @return default instance of <tt>OrderByClauseBuilder</tt> + */ + public static OrderByClauseBuilder getOrderByClauseBuilder() { + return new OrderByClauseBuilder(); + } + + /** + * Creates an instance of the given service class, with configured content type and authentication. + * + * @param <T> any service class + * @param serviceClass service class reference + * @return service instance of the given reference class + */ + public <T> T getService(final Class<T> serviceClass) { + return restClientFactory.createServiceInstance(serviceClass, mediaType, username, password); + } + + /** + * Sets the given header on the give service instance. + * + * @param <T> any service class + * @param service service class instance + * @param key HTTP header key + * @param values HTTP header values + * @return given service instance, with given header set + */ + public <T> T header(final T service, final String key, final Object... values) { + WebClient.client(service).header(key, values); + return service; + } + + /** + * Creates an instance of the given service class and sets the given header. + * + * @param <T> any service class + * @param serviceClass service class reference + * @param key HTTP header key + * @param values HTTP header values + * @return service instance of the given reference class, with given header set + */ + public <T> T header(final Class<T> serviceClass, final String key, final Object... values) { + return header(getService(serviceClass), key, values); + } + + /** + * Sets the <tt>Prefer</tt> header on the give service instance. + * + * @param <T> any service class + * @param service service class instance + * @param preference preference to be set via <tt>Prefer</tt> header + * @return given service instance, with <tt>Prefer</tt> header set + */ + public <T> T prefer(final T service, final Preference preference) { + return header(service, RESTHeaders.PREFER, preference.toString()); + } + + /** + * Creates an instance of the given service class, with <tt>Prefer</tt> header set. + * + * @param <T> any service class + * @param serviceClass service class reference + * @param preference preference to be set via <tt>Prefer</tt> header + * @return service instance of the given reference class, with <tt>Prefer</tt> header set + */ + public <T> T prefer(final Class<T> serviceClass, final Preference preference) { + return header(serviceClass, RESTHeaders.PREFER, preference.toString()); + } + + /** + * Sets the <tt>If-Match</tt> or <tt>If-None-Match</tt> header on the given service instance. + * + * @param <T> any service class + * @param service service class instance + * @param etag ETag value + * @param ifNot if true then <tt>If-None-Match</tt> is set, <tt>If-Match</tt> otherwise + * @return given service instance, with <tt>If-Match</tt> or <tt>If-None-Match</tt> set + */ + private <T> T match(final T service, final EntityTag etag, final boolean ifNot) { + WebClient.client(service).match(etag, ifNot); + return service; + } + + /** + * Sets the <tt>If-Match</tt> header on the given service instance. + * + * @param <T> any service class + * @param service service class instance + * @param etag ETag value + * @return given service instance, with <tt>If-Match</tt> set + */ + public <T> T ifMatch(final T service, final EntityTag etag) { + return match(service, etag, false); + } + + /** + * Creates an instance of the given service class, with <tt>If-Match</tt> header set. + * + * @param <T> any service class + * @param serviceClass service class reference + * @param etag ETag value + * @return given service instance, with <tt>If-Match</tt> set + */ + public <T> T ifMatch(final Class<T> serviceClass, final EntityTag etag) { + return match(getService(serviceClass), etag, false); + } + + /** + * Sets the <tt>If-None-Match</tt> header on the given service instance. + * + * @param <T> any service class + * @param service service class instance + * @param etag ETag value + * @return given service instance, with <tt>If-None-Match</tt> set + */ + public <T> T ifNoneMatch(final T service, final EntityTag etag) { + return match(service, etag, true); + } + + /** + * Creates an instance of the given service class, with <tt>If-None-Match</tt> header set. + * + * @param <T> any service class + * @param serviceClass service class reference + * @param etag ETag value + * @return given service instance, with <tt>If-None-Match</tt> set + */ + public <T> T ifNoneMatch(final Class<T> serviceClass, final EntityTag etag) { + return match(getService(serviceClass), etag, true); + } + + /** + * Fetches <tt>ETag</tt> header value from latest service run (if available). + * + * @param <T> any service class + * @param service service class instance + * @return <tt>ETag</tt> header value from latest service run (if available) + */ + public <T> EntityTag getLatestEntityTag(final T service) { + return WebClient.client(service).getResponse().getEntityTag(); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java ---------------------------------------------------------------------- diff --git a/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java new file mode 100644 index 0000000..53e0fda --- /dev/null +++ b/client/lib/src/main/java/org/apache/syncope/client/lib/SyncopeClientFactoryBean.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.lib; + +import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.ws.rs.core.MediaType; +import javax.xml.bind.Marshaller; +import org.apache.commons.lang3.StringUtils; +import org.apache.cxf.feature.Feature; +import org.apache.cxf.feature.LoggingFeature; +import org.apache.cxf.jaxrs.provider.JAXBElementProvider; +import org.apache.cxf.staxutils.DocumentDepthProperties; +import org.apache.syncope.common.lib.to.AbstractPolicyTO; + +/** + * Factory bean for creating instances of {@link SyncopeClient}. + * Supports Spring-bean configuration and override via subclassing (see protected methods). + */ +public class SyncopeClientFactoryBean { + + public enum ContentType { + + JSON(MediaType.APPLICATION_JSON_TYPE), + XML(MediaType.APPLICATION_XML_TYPE); + + private final MediaType mediaType; + + private ContentType(final MediaType mediaType) { + this.mediaType = mediaType; + } + + public MediaType getMediaType() { + return mediaType; + } + + public static ContentType fromString(final String value) { + return StringUtils.isNotBlank(value) && value.equalsIgnoreCase(XML.getMediaType().toString()) + ? XML + : JSON; + } + } + + private JacksonJaxbJsonProvider jsonProvider; + + @SuppressWarnings("rawtypes") + private JAXBElementProvider jaxbProvider; + + private RestClientExceptionMapper exceptionMapper; + + private String address; + + private ContentType contentType; + + private RestClientFactoryBean restClientFactoryBean; + + protected JacksonJaxbJsonProvider defaultJsonProvider() { + return new JacksonJaxbJsonProvider(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected JAXBElementProvider defaultJAXBProvider() { + JAXBElementProvider defaultJAXBProvider = new JAXBElementProvider(); + + DocumentDepthProperties depthProperties = new DocumentDepthProperties(); + depthProperties.setInnerElementCountThreshold(500); + defaultJAXBProvider.setDepthProperties(depthProperties); + + Map marshallerProperties = new HashMap(); + marshallerProperties.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + defaultJAXBProvider.setMarshallerProperties(marshallerProperties); + + Map<String, String> collectionWrapperMap = new HashMap<String, String>(); + collectionWrapperMap.put(AbstractPolicyTO.class.getName(), "policies"); + defaultJAXBProvider.setCollectionWrapperMap(collectionWrapperMap); + + return defaultJAXBProvider; + } + + protected RestClientExceptionMapper defaultExceptionMapper() { + return new RestClientExceptionMapper(); + } + + protected RestClientFactoryBean defaultRestClientFactoryBean() { + RestClientFactoryBean defaultRestClientFactoryBean = new RestClientFactoryBean(); + + if (StringUtils.isBlank(address)) { + throw new IllegalArgumentException("Property 'address' is missing"); + } + defaultRestClientFactoryBean.setAddress(address); + + defaultRestClientFactoryBean.setThreadSafe(true); + defaultRestClientFactoryBean.setInheritHeaders(true); + + List<Feature> features = new ArrayList<Feature>(); + features.add(new LoggingFeature()); + defaultRestClientFactoryBean.setFeatures(features); + + List<Object> providers = new ArrayList<Object>(3); + providers.add(getJaxbProvider()); + providers.add(getJsonProvider()); + providers.add(getExceptionMapper()); + defaultRestClientFactoryBean.setProviders(providers); + + return defaultRestClientFactoryBean; + } + + public JacksonJaxbJsonProvider getJsonProvider() { + return jsonProvider == null + ? defaultJsonProvider() + : jsonProvider; + } + + public void setJsonProvider(final JacksonJaxbJsonProvider jsonProvider) { + this.jsonProvider = jsonProvider; + } + + public JAXBElementProvider getJaxbProvider() { + return jaxbProvider == null + ? defaultJAXBProvider() + : jaxbProvider; + } + + public SyncopeClientFactoryBean setJaxbProvider(final JAXBElementProvider jaxbProvider) { + this.jaxbProvider = jaxbProvider; + return this; + } + + public RestClientExceptionMapper getExceptionMapper() { + return exceptionMapper == null + ? defaultExceptionMapper() + : exceptionMapper; + } + + public SyncopeClientFactoryBean setExceptionMapper(final RestClientExceptionMapper exceptionMapper) { + this.exceptionMapper = exceptionMapper; + return this; + } + + public String getAddress() { + return address; + } + + public SyncopeClientFactoryBean setAddress(final String address) { + this.address = address; + return this; + } + + public ContentType getContentType() { + return contentType == null + ? ContentType.JSON + : contentType; + } + + public SyncopeClientFactoryBean setContentType(final ContentType contentType) { + this.contentType = contentType; + return this; + } + + public SyncopeClientFactoryBean setContentType(final String contentType) { + this.contentType = ContentType.fromString(contentType); + return this; + } + + public RestClientFactoryBean getRestClientFactoryBean() { + return restClientFactoryBean == null + ? defaultRestClientFactoryBean() + : restClientFactoryBean; + } + + public SyncopeClientFactoryBean setRestClientFactoryBean(final RestClientFactoryBean restClientFactoryBean) { + this.restClientFactoryBean = restClientFactoryBean; + return this; + } + + public SyncopeClient createAnonymous() { + return create(null, null); + } + + public SyncopeClient create(final String username, final String password) { + return new SyncopeClient(getContentType().getMediaType(), getRestClientFactoryBean(), username, password); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/pom.xml ---------------------------------------------------------------------- diff --git a/client/pom.xml b/client/pom.xml index f618315..78bfcbd 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -31,89 +31,12 @@ under the License. <description>Apache Syncope Client</description> <groupId>org.apache.syncope</groupId> <artifactId>syncope-client</artifactId> - <packaging>bundle</packaging> + <packaging>pom</packaging> - <distributionManagement> - <site> - <id>syncope.website</id> - <name>Apache Syncope website</name> - <url>${site.deploymentBaseUrl}/${project.artifactId}</url> - </site> - </distributionManagement> + <modules> + <module>lib</module> + <module>console</module> + <module>cli</module> + </modules> - <dependencies> - <dependency> - <groupId>org.apache.syncope</groupId> - <artifactId>syncope-common</artifactId> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>javax.ws.rs</groupId> - <artifactId>javax.ws.rs-api</artifactId> - </dependency> - - <dependency> - <groupId>org.apache.cxf</groupId> - <artifactId>cxf-rt-rs-client</artifactId> - </dependency> - - <dependency> - <groupId>com.fasterxml.jackson.jaxrs</groupId> - <artifactId>jackson-jaxrs-json-provider</artifactId> - </dependency> - - <dependency> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </dependency> - </dependencies> - - <build> - <plugins> - <plugin> - <groupId>org.apache.felix</groupId> - <artifactId>maven-bundle-plugin</artifactId> - <extensions>true</extensions> - <configuration> - <instructions> - <Bundle-Name>${project.name}</Bundle-Name> - <Bundle-SymbolicName>org.apache.syncope.client</Bundle-SymbolicName> - <Bundle-Version>${project.version}</Bundle-Version> - <Export-Package> - org.apache.syncope.client*;version=${project.version};-split-package:=merge-first - </Export-Package> - <Import-Package> - com.fasterxml.jackson*;version="[2.2.2,2.3)", - org.slf4j;resolution:=optional, - * - </Import-Package> - </instructions> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-checkstyle-plugin</artifactId> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-pmd-plugin</artifactId> - </plugin> - </plugins> - - <resources> - <resource> - <directory>..</directory> - <targetPath>META-INF</targetPath> - <includes> - <include>LICENSE</include> - <include>NOTICE</include> - </includes> - </resource> - <resource> - <directory>src/main/resources/META-INF</directory> - <targetPath>META-INF</targetPath> - </resource> - </resources> - </build> </project> http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/src/main/java/org/apache/syncope/client/SyncopeClient.java ---------------------------------------------------------------------- diff --git a/client/src/main/java/org/apache/syncope/client/SyncopeClient.java b/client/src/main/java/org/apache/syncope/client/SyncopeClient.java deleted file mode 100644 index f955951..0000000 --- a/client/src/main/java/org/apache/syncope/client/SyncopeClient.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client; - -import javax.ws.rs.core.EntityTag; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import org.apache.cxf.jaxrs.client.WebClient; -import org.apache.syncope.client.rest.RestClientFactoryBean; -import org.apache.syncope.common.search.OrderByClauseBuilder; -import org.apache.syncope.common.search.RoleFiqlSearchConditionBuilder; -import org.apache.syncope.common.search.UserFiqlSearchConditionBuilder; -import org.apache.syncope.common.services.RouteService; -import org.apache.syncope.common.services.UserSelfService; -import org.apache.syncope.common.services.WorkflowService; -import org.apache.syncope.common.types.Preference; -import org.apache.syncope.common.types.RESTHeaders; -import org.apache.syncope.common.types.SubjectType; - -/** - * Entry point for client access to all REST services exposed by Syncope core; obtain instances via - * <tt>SyncopeClientFactoryBean</tt>. - * - * @see SyncopeClientFactoryBean - */ -public class SyncopeClient { - - private final MediaType mediaType; - - private final RestClientFactoryBean restClientFactory; - - private final String username; - - private final String password; - - public SyncopeClient(final MediaType mediaType, final RestClientFactoryBean restClientFactory, - final String username, final String password) { - - this.mediaType = mediaType; - this.restClientFactory = restClientFactory; - this.username = username; - this.password = password; - } - - /** - * Returns a new instance of <tt>UserFiqlSearchConditionBuilder</tt>, for assisted building of FIQL queries. - * - * @return default instance of <tt>UserFiqlSearchConditionBuilder</tt> - */ - public static UserFiqlSearchConditionBuilder getUserSearchConditionBuilder() { - return new UserFiqlSearchConditionBuilder(); - } - - /** - * Returns a new instance of <tt>RoleFiqlSearchConditionBuilder</tt>, for assisted building of FIQL queries. - * - * @return default instance of <tt>RoleFiqlSearchConditionBuilder</tt> - */ - public static RoleFiqlSearchConditionBuilder getRoleSearchConditionBuilder() { - return new RoleFiqlSearchConditionBuilder(); - } - - /** - * Returns a new instance of <tt>OrderByClauseBuilder</tt>, for assisted building of <tt>orderby</tt> clauses. - * - * @return default instance of <tt>OrderByClauseBuilder</tt> - */ - public static OrderByClauseBuilder getOrderByClauseBuilder() { - return new OrderByClauseBuilder(); - } - - /** - * Creates an instance of the given service class, with configured content type and authentication. - * - * @param <T> any service class - * @param serviceClass service class reference - * @return service instance of the given reference class - */ - public <T> T getService(final Class<T> serviceClass) { - return restClientFactory.createServiceInstance(serviceClass, mediaType, username, password); - } - - /** - * Sets the given header on the give service instance. - * - * @param <T> any service class - * @param service service class instance - * @param key HTTP header key - * @param values HTTP header values - * @return given service instance, with given header set - */ - public <T> T header(final T service, final String key, final Object... values) { - WebClient.client(service).header(key, values); - return service; - } - - /** - * Creates an instance of the given service class and sets the given header. - * - * @param <T> any service class - * @param serviceClass service class reference - * @param key HTTP header key - * @param values HTTP header values - * @return service instance of the given reference class, with given header set - */ - public <T> T header(final Class<T> serviceClass, final String key, final Object... values) { - return header(getService(serviceClass), key, values); - } - - /** - * Sets the <tt>Prefer</tt> header on the give service instance. - * - * @param <T> any service class - * @param service service class instance - * @param preference preference to be set via <tt>Prefer</tt> header - * @return given service instance, with <tt>Prefer</tt> header set - */ - public <T> T prefer(final T service, final Preference preference) { - return header(service, RESTHeaders.PREFER, preference.toString()); - } - - /** - * Creates an instance of the given service class, with <tt>Prefer</tt> header set. - * - * @param <T> any service class - * @param serviceClass service class reference - * @param preference preference to be set via <tt>Prefer</tt> header - * @return service instance of the given reference class, with <tt>Prefer</tt> header set - */ - public <T> T prefer(final Class<T> serviceClass, final Preference preference) { - return header(serviceClass, RESTHeaders.PREFER, preference.toString()); - } - - /** - * Sets the <tt>If-Match</tt> or <tt>If-None-Match</tt> header on the given service instance. - * - * @param <T> any service class - * @param service service class instance - * @param etag ETag value - * @param ifNot if true then <tt>If-None-Match</tt> is set, <tt>If-Match</tt> otherwise - * @return given service instance, with <tt>If-Match</tt> or <tt>If-None-Match</tt> set - */ - private <T> T match(final T service, final EntityTag etag, final boolean ifNot) { - WebClient.client(service).match(etag, ifNot); - return service; - } - - /** - * Sets the <tt>If-Match</tt> header on the given service instance. - * - * @param <T> any service class - * @param service service class instance - * @param etag ETag value - * @return given service instance, with <tt>If-Match</tt> set - */ - public <T> T ifMatch(final T service, final EntityTag etag) { - return match(service, etag, false); - } - - /** - * Creates an instance of the given service class, with <tt>If-Match</tt> header set. - * - * @param <T> any service class - * @param serviceClass service class reference - * @param etag ETag value - * @return given service instance, with <tt>If-Match</tt> set - */ - public <T> T ifMatch(final Class<T> serviceClass, final EntityTag etag) { - return match(getService(serviceClass), etag, false); - } - - /** - * Sets the <tt>If-None-Match</tt> header on the given service instance. - * - * @param <T> any service class - * @param service service class instance - * @param etag ETag value - * @return given service instance, with <tt>If-None-Match</tt> set - */ - public <T> T ifNoneMatch(final T service, final EntityTag etag) { - return match(service, etag, true); - } - - /** - * Creates an instance of the given service class, with <tt>If-None-Match</tt> header set. - * - * @param <T> any service class - * @param serviceClass service class reference - * @param etag ETag value - * @return given service instance, with <tt>If-None-Match</tt> set - */ - public <T> T ifNoneMatch(final Class<T> serviceClass, final EntityTag etag) { - return match(getService(serviceClass), etag, true); - } - - /** - * Checks whether self-registration is allowed by calling <tt>UserSelfService</tt>'s options. - * - * @return whether self-registration is allowed - * @see UserSelfService#getOptions() - */ - public boolean isSelfRegAllowed() { - return Boolean.valueOf(restClientFactory.createServiceInstance(UserSelfService.class, mediaType, null, null). - getOptions().getHeaderString(RESTHeaders.SELFREG_ALLOWED)); - } - - /** - * Checks whether password reset is allowed by calling <tt>UserSelfService</tt>'s options. - * - * @return whether password reset is allowed - * @see UserSelfService#getOptions() - */ - public boolean isPwdResetAllowed() { - return Boolean.valueOf(restClientFactory.createServiceInstance(UserSelfService.class, mediaType, null, null). - getOptions().getHeaderString(RESTHeaders.PWDRESET_ALLOWED)); - } - - /** - * Checks whether password reset requires security question by calling <tt>UserSelfService</tt>'s options. - * - * @return whether password reset requires security question - * @see UserSelfService#getOptions() - */ - public boolean isPwdResetRequiringSecurityQuestions() { - return Boolean.valueOf(restClientFactory.createServiceInstance(UserSelfService.class, mediaType, null, null). - getOptions().getHeaderString(RESTHeaders.PWDRESET_NEEDS_SECURITYQUESTIONS)); - } - - /** - * Checks whether Activiti workflow is enabled for users / roles, by calling <tt>WorkflowService</tt>'s options. - * - * @param subjectType user / role - * @return whether Activiti workflow is enabled for given attributable type - * @see WorkflowService#getOptions(org.apache.syncope.common.types.SubjectType) - */ - public boolean isActivitiEnabledFor(final SubjectType subjectType) { - Response options = getService(WorkflowService.class).getOptions(subjectType); - - boolean result; - switch (subjectType) { - case ROLE: - result = Boolean.valueOf(options.getHeaderString(RESTHeaders.ACTIVITI_ROLE_ENABLED)); - break; - - case USER: - default: - result = Boolean.valueOf(options.getHeaderString(RESTHeaders.ACTIVITI_USER_ENABLED)); - break; - } - - return result; - } - - /** - * Checks whether Camel is enabled for users / roles, by calling <tt>RouteService</tt>'s options. - * - * @param subjectType user / role - * @return whether Camel Provisioning is enabled for given attributable type - * @see RouteService#getOptions(org.apache.syncope.common.types.SubjectType) - */ - public boolean isCamelEnabledFor(final SubjectType subjectType) { - Response options = getService(RouteService.class).getOptions(subjectType); - - boolean result; - switch (subjectType) { - case ROLE: - result = Boolean.valueOf(options.getHeaderString(RESTHeaders.CAMEL_ROLE_PROVISIONING_MANAGER)); - break; - - case USER: - default: - result = Boolean.valueOf(options.getHeaderString(RESTHeaders.CAMEL_USER_PROVISIONING_MANAGER)); - break; - } - - return result; - } - - /** - * Fetches <tt>ETag</tt> header value from latest service run (if available). - * - * @param <T> any service class - * @param service service class instance - * @return <tt>ETag</tt> header value from latest service run (if available) - */ - public <T> EntityTag getLatestEntityTag(final T service) { - return WebClient.client(service).getResponse().getEntityTag(); - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/src/main/java/org/apache/syncope/client/SyncopeClientFactoryBean.java ---------------------------------------------------------------------- diff --git a/client/src/main/java/org/apache/syncope/client/SyncopeClientFactoryBean.java b/client/src/main/java/org/apache/syncope/client/SyncopeClientFactoryBean.java deleted file mode 100644 index 234625b..0000000 --- a/client/src/main/java/org/apache/syncope/client/SyncopeClientFactoryBean.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client; - -import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.ws.rs.core.MediaType; -import javax.xml.bind.Marshaller; -import org.apache.commons.lang3.StringUtils; -import org.apache.cxf.feature.Feature; -import org.apache.cxf.feature.LoggingFeature; -import org.apache.cxf.jaxrs.provider.JAXBElementProvider; -import org.apache.cxf.staxutils.DocumentDepthProperties; -import org.apache.syncope.client.rest.RestClientExceptionMapper; -import org.apache.syncope.client.rest.RestClientFactoryBean; -import org.apache.syncope.common.to.AbstractPolicyTO; - -/** - * Factory bean for creating instances of <tt>SyncopeClient</tt>. - * Supports Spring-bean configuration and override via subclassing (see protected methods). - */ -public class SyncopeClientFactoryBean { - - public enum ContentType { - - JSON(MediaType.APPLICATION_JSON_TYPE), - XML(MediaType.APPLICATION_XML_TYPE); - - private final MediaType mediaType; - - private ContentType(final MediaType mediaType) { - this.mediaType = mediaType; - } - - public MediaType getMediaType() { - return mediaType; - } - - public static ContentType fromString(final String value) { - return StringUtils.isNotBlank(value) && value.equalsIgnoreCase(XML.getMediaType().toString()) - ? XML - : JSON; - } - } - - private JacksonJaxbJsonProvider jsonProvider; - - @SuppressWarnings("rawtypes") - private JAXBElementProvider jaxbProvider; - - private RestClientExceptionMapper exceptionMapper; - - private String address; - - private ContentType contentType; - - private RestClientFactoryBean restClientFactoryBean; - - protected JacksonJaxbJsonProvider defaultJsonProvider() { - return new JacksonJaxbJsonProvider(); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected JAXBElementProvider defaultJAXBProvider() { - JAXBElementProvider defaultJAXBProvider = new JAXBElementProvider(); - - DocumentDepthProperties depthProperties = new DocumentDepthProperties(); - depthProperties.setInnerElementCountThreshold(500); - defaultJAXBProvider.setDepthProperties(depthProperties); - - Map marshallerProperties = new HashMap(); - marshallerProperties.put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); - defaultJAXBProvider.setMarshallerProperties(marshallerProperties); - - Map<String, String> collectionWrapperMap = new HashMap<String, String>(); - collectionWrapperMap.put(AbstractPolicyTO.class.getName(), "policies"); - defaultJAXBProvider.setCollectionWrapperMap(collectionWrapperMap); - - return defaultJAXBProvider; - } - - protected RestClientExceptionMapper defaultExceptionMapper() { - return new RestClientExceptionMapper(); - } - - protected RestClientFactoryBean defaultRestClientFactoryBean() { - RestClientFactoryBean defaultRestClientFactoryBean = new RestClientFactoryBean(); - - if (StringUtils.isBlank(address)) { - throw new IllegalArgumentException("Property 'address' is missing"); - } - defaultRestClientFactoryBean.setAddress(address); - - defaultRestClientFactoryBean.setThreadSafe(true); - defaultRestClientFactoryBean.setInheritHeaders(true); - - List<Feature> features = new ArrayList<Feature>(); - features.add(new LoggingFeature()); - defaultRestClientFactoryBean.setFeatures(features); - - List<Object> providers = new ArrayList<Object>(3); - providers.add(getJaxbProvider()); - providers.add(getJsonProvider()); - providers.add(getExceptionMapper()); - defaultRestClientFactoryBean.setProviders(providers); - - return defaultRestClientFactoryBean; - } - - public JacksonJaxbJsonProvider getJsonProvider() { - return jsonProvider == null - ? defaultJsonProvider() - : jsonProvider; - } - - public void setJsonProvider(final JacksonJaxbJsonProvider jsonProvider) { - this.jsonProvider = jsonProvider; - } - - public JAXBElementProvider getJaxbProvider() { - return jaxbProvider == null - ? defaultJAXBProvider() - : jaxbProvider; - } - - public SyncopeClientFactoryBean setJaxbProvider(final JAXBElementProvider jaxbProvider) { - this.jaxbProvider = jaxbProvider; - return this; - } - - public RestClientExceptionMapper getExceptionMapper() { - return exceptionMapper == null - ? defaultExceptionMapper() - : exceptionMapper; - } - - public SyncopeClientFactoryBean setExceptionMapper(final RestClientExceptionMapper exceptionMapper) { - this.exceptionMapper = exceptionMapper; - return this; - } - - public String getAddress() { - return address; - } - - public SyncopeClientFactoryBean setAddress(final String address) { - this.address = address; - return this; - } - - public ContentType getContentType() { - return contentType == null - ? ContentType.JSON - : contentType; - } - - public SyncopeClientFactoryBean setContentType(final ContentType contentType) { - this.contentType = contentType; - return this; - } - - public SyncopeClientFactoryBean setContentType(final String contentType) { - this.contentType = ContentType.fromString(contentType); - return this; - } - - public RestClientFactoryBean getRestClientFactoryBean() { - return restClientFactoryBean == null - ? defaultRestClientFactoryBean() - : restClientFactoryBean; - } - - public SyncopeClientFactoryBean setRestClientFactoryBean(final RestClientFactoryBean restClientFactoryBean) { - this.restClientFactoryBean = restClientFactoryBean; - return this; - } - - public SyncopeClient createAnonymous() { - return create(null, null); - } - - public SyncopeClient create(final String username, final String password) { - return new SyncopeClient(getContentType().getMediaType(), getRestClientFactoryBean(), username, password); - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java ---------------------------------------------------------------------- diff --git a/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java b/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java deleted file mode 100644 index 1a9d2ef..0000000 --- a/client/src/main/java/org/apache/syncope/client/rest/RestClientExceptionMapper.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client.rest; - -import java.security.AccessControlException; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import javax.ws.rs.BadRequestException; -import javax.ws.rs.core.Response; -import javax.ws.rs.ext.ExceptionMapper; -import javax.ws.rs.ext.Provider; -import javax.xml.ws.WebServiceException; -import org.apache.commons.lang3.StringUtils; -import org.apache.cxf.jaxrs.client.ResponseExceptionMapper; -import org.apache.syncope.common.types.ClientExceptionType; -import org.apache.syncope.common.types.RESTHeaders; -import org.apache.syncope.common.SyncopeClientCompositeException; -import org.apache.syncope.common.SyncopeClientException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Provider -public class RestClientExceptionMapper implements ExceptionMapper<Exception>, ResponseExceptionMapper<Exception> { - - private static final Logger LOG = LoggerFactory.getLogger(RestClientExceptionMapper.class); - - @Override - public Response toResponse(final Exception exception) { - throw new UnsupportedOperationException( - "Call of toResponse() method is not expected in RestClientExceptionnMapper"); - } - - @Override - public Exception fromResponse(final Response response) { - final int statusCode = response.getStatus(); - Exception ex; - - // 1. Check for client (possibly composite) exception in HTTP header - SyncopeClientCompositeException scce = checkSyncopeClientCompositeException(response); - if (scce != null) { - if (scce.getExceptions().size() == 1) { - ex = scce.getExceptions().iterator().next(); - } else { - ex = scce; - } - } // 2. Map SC_UNAUTHORIZED - else if (statusCode == Response.Status.UNAUTHORIZED.getStatusCode()) { - ex = new AccessControlException("Remote unauthorized exception"); - } // 3. Map SC_BAD_REQUEST - else if (statusCode == Response.Status.BAD_REQUEST.getStatusCode()) { - ex = new BadRequestException(); - } // 4. All other codes are mapped to runtime exception with HTTP code information - else { - ex = new WebServiceException(String.format("Remote exception with status code: %s", - Response.Status.fromStatusCode(statusCode).name())); - } - LOG.error("Exception thrown by REST methods: " + ex.getMessage(), ex); - return ex; - } - - private SyncopeClientCompositeException checkSyncopeClientCompositeException(final Response response) { - List<Object> exTypesInHeaders = response.getHeaders().get(RESTHeaders.ERROR_CODE); - if (exTypesInHeaders == null) { - LOG.debug("No " + RESTHeaders.ERROR_CODE + " provided"); - return null; - } - - final SyncopeClientCompositeException compException = SyncopeClientException.buildComposite(); - - final Set<String> handledExceptions = new HashSet<String>(); - for (Object exceptionTypeValue : exTypesInHeaders) { - final String exTypeAsString = (String) exceptionTypeValue; - ClientExceptionType exceptionType = null; - try { - exceptionType = ClientExceptionType.fromHeaderValue(exTypeAsString); - } catch (IllegalArgumentException e) { - LOG.error("Unexpected value of " + RESTHeaders.ERROR_CODE + ": " + exTypeAsString, e); - } - if (exceptionType != null) { - handledExceptions.add(exTypeAsString); - - final SyncopeClientException clientException = SyncopeClientException.build(exceptionType); - - if (response.getHeaders().get(RESTHeaders.ERROR_INFO) != null - && !response.getHeaders().get(RESTHeaders.ERROR_INFO).isEmpty()) { - - for (Object value : response.getHeaders().get(RESTHeaders.ERROR_INFO)) { - final String element = value.toString(); - if (element.startsWith(exceptionType.getHeaderValue())) { - clientException.getElements().add(StringUtils.substringAfter(value.toString(), ":")); - } - } - } - compException.addException(clientException); - } - } - - exTypesInHeaders.removeAll(handledExceptions); - if (!exTypesInHeaders.isEmpty()) { - LOG.error("Unmanaged exceptions: " + exTypesInHeaders); - } - - if (compException.hasExceptions()) { - return compException; - } - - return null; - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java ---------------------------------------------------------------------- diff --git a/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java b/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java deleted file mode 100644 index e10840a..0000000 --- a/client/src/main/java/org/apache/syncope/client/rest/RestClientFactoryBean.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client.rest; - -import javax.ws.rs.core.MediaType; -import org.apache.commons.lang3.StringUtils; -import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; -import org.apache.cxf.jaxrs.client.WebClient; - -/** - * Provides shortcuts for creating JAX-RS service instances via CXF's <tt>JAXRSClientFactoryBean</tt>. - */ -public class RestClientFactoryBean extends JAXRSClientFactoryBean { - - /** - * Creates an anonymous instance of the given service class, for the given content type. - * - * @param <T> any service class - * @param serviceClass service class reference - * @param mediaType XML or JSON are suppoorted - * @return anonymous service instance of the given reference class - */ - public <T> T createServiceInstance(final Class<T> serviceClass, final MediaType mediaType) { - return createServiceInstance(serviceClass, mediaType, null, null); - } - - /** - * Creates an authenticated instance of the given service class, for the given content type. - * - * @param <T> any service class - * @param serviceClass service class reference - * @param mediaType XML or JSON are suppoorted - * @param username username for REST authentication - * @param password password for REST authentication - * @return anonymous service instance of the given reference class - */ - public <T> T createServiceInstance( - final Class<T> serviceClass, final MediaType mediaType, final String username, final String password) { - - if (StringUtils.isNotBlank(username)) { - setUsername(username); - } - if (StringUtils.isNotBlank(password)) { - setPassword(password); - } - setServiceClass(serviceClass); - final T serviceInstance = create(serviceClass); - WebClient.client(serviceInstance).type(mediaType).accept(mediaType); - return serviceInstance; - } -} http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/client/src/main/resources/META-INF/cxf/org.apache.cxf.Logger ---------------------------------------------------------------------- diff --git a/client/src/main/resources/META-INF/cxf/org.apache.cxf.Logger b/client/src/main/resources/META-INF/cxf/org.apache.cxf.Logger deleted file mode 100644 index 6e7bd36..0000000 --- a/client/src/main/resources/META-INF/cxf/org.apache.cxf.Logger +++ /dev/null @@ -1 +0,0 @@ -org.apache.cxf.common.logging.Slf4jLogger http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/common/lib/pom.xml ---------------------------------------------------------------------- diff --git a/common/lib/pom.xml b/common/lib/pom.xml new file mode 100644 index 0000000..2bdc6ea --- /dev/null +++ b/common/lib/pom.xml @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.syncope</groupId> + <artifactId>syncope-common</artifactId> + <version>2.0.0-SNAPSHOT</version> + </parent> + + <name>Apache Syncope Common Lib</name> + <description>Apache Syncope Common Lib</description> + <groupId>org.apache.syncope.common</groupId> + <artifactId>syncope-common-lib</artifactId> + <packaging>jar</packaging> + + <properties> + <rootpom.basedir>${basedir}/../..</rootpom.basedir> + </properties> + + <dependencies> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-rs-extension-search</artifactId> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-api</artifactId> + </dependency> + + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-pmd-plugin</artifactId> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/syncope/blob/2d194636/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java ---------------------------------------------------------------------- diff --git a/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java b/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java new file mode 100644 index 0000000..8a6d9c4 --- /dev/null +++ b/common/lib/src/main/java/org/apache/syncope/common/lib/AbstractBaseBean.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.common.lib; + +import java.io.Serializable; +import javax.xml.bind.annotation.XmlSeeAlso; +import javax.xml.bind.annotation.XmlType; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.apache.syncope.common.lib.to.AbstractTaskTO; +import org.apache.syncope.common.lib.to.ReportTO; +import org.apache.syncope.common.lib.to.RoleTO; +import org.apache.syncope.common.lib.to.UserTO; + +@XmlType +// Reporting here only classes used via PagedResult +@XmlSeeAlso({ AbstractTaskTO.class, ReportTO.class, RoleTO.class, UserTO.class }) +public abstract class AbstractBaseBean implements Serializable { + + private static final long serialVersionUID = 3119542005279892164L; + + @Override + public boolean equals(final Object obj) { + return EqualsBuilder.reflectionEquals(this, obj); + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } + + @Override + public String toString() { + return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE); + } +}
