All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.occurrent.application.converter.xstream.XStreamCloudEventConverter Maven / Gradle / Ivy

There is a newer version: 0.19.3
Show newest version
/*
 *
 *  Copyright 2021 Johan Haleby
 *
 *  Licensed 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.occurrent.application.converter.xstream;

import com.thoughtworks.xstream.XStream;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import org.occurrent.application.converter.CloudEventConverter;
import org.occurrent.application.converter.typemapper.CloudEventTypeGetter;

import java.net.URI;
import java.nio.charset.Charset;
import java.time.OffsetDateTime;
import java.util.UUID;
import java.util.function.Function;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.time.ZoneOffset.UTC;
import static java.util.Objects.requireNonNull;

/**
 * An {@link CloudEventConverter} that uses {@link XStream} to serialize a domain event into XML (content type {@value #DEFAULT_CONTENT_TYPE}) that is used as data in a {@link CloudEvent}.
 *
 * @param  The type of your domain event(s) to convert
 */
public class XStreamCloudEventConverter implements CloudEventConverter {
    private static final String DEFAULT_CONTENT_TYPE = "application/xml";
    private static final Charset DEFAULT_CHARSET = UTF_8;

    private final XStream xStream;
    private final URI cloudEventSource;
    private final Function idMapper;
    private final CloudEventTypeGetter cloudEventTypeGetter;
    private final Function timeMapper;
    private final Function subjectMapper;
    private final String contentType;
    private final Charset charset;

    /**
     * Create a new instance of the {@link XStreamCloudEventConverter} that does the following:
     * 
    *
  1. Uses a random UUID as cloud event id
  2. *
  3. Uses the simple name of the domain event class as cloud event type.
  4. *
  5. Uses {@code OffsetDateTime.now(UTC)} as cloud event time
  6. *
  7. Uses charset UTF-8 when converting the domain event to/from XML
  8. *
  9. No subject
  10. *
*

* See cloud event documentation for info on what the cloud event attributes mean.

* Use {@link Builder} for more advanced configuration. * * @param xStream The XStream instance to use * @param cloudEventSource The cloud event source. * @see Builder The Builder for more advanced configuration */ public XStreamCloudEventConverter(XStream xStream, URI cloudEventSource) { this(xStream, cloudEventSource, defaultIdMapperFunction(), defaultCloudEventTypeGetter(), defaultTimeMapperFunction(), defaultSubjectMapperFunction(), DEFAULT_CONTENT_TYPE, DEFAULT_CHARSET); } private XStreamCloudEventConverter(XStream xStream, URI cloudEventSource, Function idMapper, CloudEventTypeGetter cloudEventTypeGetter, Function timeMapper, Function subjectMapper, String contentType, Charset charset) { requireNonNull(xStream, XStream.class.getSimpleName() + " cannot be null"); requireNonNull(cloudEventSource, "cloudEventSource cannot be null"); requireNonNull(idMapper, "idMapper cannot be null"); requireNonNull(cloudEventTypeGetter, "cloudEventTypeGetter cannot be null"); requireNonNull(timeMapper, "timeMapper cannot be null"); requireNonNull(subjectMapper, "subjectMapper cannot be null"); requireNonNull(charset, Charset.class.getSimpleName() + " cannot be null"); this.xStream = xStream; this.cloudEventSource = cloudEventSource; this.idMapper = idMapper; this.timeMapper = timeMapper; this.subjectMapper = subjectMapper; this.contentType = contentType; this.charset = charset; this.cloudEventTypeGetter = cloudEventTypeGetter; } /** * Converts the {@code domainEvent} into a {@link CloudEvent} using {@link XStream}. * * @param domainEvent The domain event to convert * @return A {@link CloudEvent} converted from the domainEvent. */ @Override public CloudEvent toCloudEvent(T domainEvent) { requireNonNull(domainEvent, "Domain event cannot be null"); return CloudEventBuilder.v1() .withId(idMapper.apply(domainEvent)) .withSource(cloudEventSource) .withType(cloudEventTypeGetter.getCloudEventType(domainEvent)) .withTime(timeMapper.apply(domainEvent)) .withSubject(subjectMapper.apply(domainEvent)) .withDataContentType(contentType) .withData(xStream.toXML(domainEvent).getBytes(charset)) .build(); } /** * Converts the {@link CloudEvent} back into a {@code domainEvent} using {@link XStream}. * * @param cloudEvent The cloud event to convert * @return A domainEvent converted from a {@link CloudEvent}. */ @SuppressWarnings("unchecked") @Override public T toDomainEvent(CloudEvent cloudEvent) { return (T) xStream.fromXML(new String(requireNonNull(cloudEvent.getData()).toBytes(), charset)); } @Override public String getCloudEventType(Class type) { return cloudEventTypeGetter.getCloudEventType(type); } public static final class Builder { private final XStream xStream; private final URI cloudEventSource; private String contentType = DEFAULT_CONTENT_TYPE; private Charset charset = DEFAULT_CHARSET; private Function idMapper = defaultIdMapperFunction(); private CloudEventTypeGetter cloudEventTypeGetter = defaultCloudEventTypeGetter(); private Function timeMapper = defaultTimeMapperFunction(); private Function subjectMapper = defaultSubjectMapperFunction(); public Builder(XStream xStream, URI cloudEventSource) { this.xStream = xStream; this.cloudEventSource = cloudEventSource; } /** * @param contentType Specify the content type to use in the generated cloud event */ public Builder contentType(String contentType) { this.contentType = contentType; return this; } /** * @param idMapper A function that generates the cloud event id based on the domain event. By default, a random UUID is used. */ public Builder idMapper(Function idMapper) { this.idMapper = idMapper; return this; } /** * @param cloudEventTypeGetter A function that generates the cloud event type based on the domain event. By default, the "simple name" of the domain event is used. */ public Builder typeGetter(CloudEventTypeGetter cloudEventTypeGetter) { this.cloudEventTypeGetter = cloudEventTypeGetter; return this; } /** * @param timeMapper A function that generates the cloud event time based on the domain event. By default, {@code OffsetDateTime.now(UTC)} is always returned. */ public Builder timeMapper(Function timeMapper) { this.timeMapper = timeMapper; return this; } /** * @param subjectMapper A function that generates the cloud event subject based on the domain event. By default, {@code null} is always returned. */ public Builder subjectMapper(Function subjectMapper) { this.subjectMapper = subjectMapper; return this; } /** * @param charset Specify the charset that XStream should use when serializing the domain event to bytes that is stored as the cloud event data attribute. */ public Builder charset(Charset charset) { this.charset = charset; return this; } /** * @return A {@link XStreamCloudEventConverter} instance with the configured settings */ public XStreamCloudEventConverter build() { return new XStreamCloudEventConverter<>(xStream, cloudEventSource, idMapper, cloudEventTypeGetter, timeMapper, subjectMapper, contentType, charset); } } private static Function defaultIdMapperFunction() { return __ -> UUID.randomUUID().toString(); } private static CloudEventTypeGetter defaultCloudEventTypeGetter() { return Class::getSimpleName; } private static Function defaultTimeMapperFunction() { return __ -> OffsetDateTime.now(UTC); } private static Function defaultSubjectMapperFunction() { return __ -> null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy