com.carlomicieli.jtrains.core.models.Brand.java Source code

Java tutorial

Introduction

Here is the source code for com.carlomicieli.jtrains.core.models.Brand.java

Source

/*
 * Copyright 2014 the original author or authors.
 *
 *  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 com.carlomicieli.jtrains.core.models;

import com.carlomicieli.jtrains.AppGlobals;
import com.carlomicieli.jtrains.infrastructure.mapping.EntityLink;
import com.carlomicieli.jtrains.util.Fun;
import com.carlomicieli.jtrains.util.Slug;
import com.carlomicieli.jtrains.validation.constraints.ContainsDefault;
import com.carlomicieli.jtrains.value.objects.Address;
import com.carlomicieli.jtrains.value.objects.LocalizedField;
import com.fasterxml.jackson.annotation.JsonCreator;
import org.bson.types.ObjectId;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.URL;
import org.jongo.marshall.jackson.oid.Id;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.function.UnaryOperator;

/**
 * It represents a {@code Brand} for a model railways rolling stock manufacturer.
 *
 *  <p>
 *  Two distinct family of manufacturer exists:
 *  <ul>
 *      <li>
 *          {@code industrial}: these manufactures produce models using the die casting method;
 *      </li>
 *      <li>
 *          {@code brass models}: these manufacturers produce models which are made of brass or
 *          similar alloys. They are usually more expensive than the industrial series due to the limited
 *          production quantities and the {@code "hand made"} nature of the production.
 *      </li>
 *  </ul>
 * </p>
 *
 *  <p>
 *      A {@code Brand} could possibly have local branches in a given country, either a local
 *      office or a distribution company. They are stored in the {@code Address}es map.
 *  </p>
 *
 *  <p>
 *      {@code Brand} objects are <strong>immutable</strong> and therefore {@code thread-safe}.
 *  </p>
 *
 * @author Carlo Micieli
 * @since 1.0
 * @see com.carlomicieli.jtrains.value.objects.Address 
 * @see com.carlomicieli.jtrains.value.objects.LocalizedField 
 */
public final class Brand {
    @Id
    private final ObjectId id;

    @NotBlank(message = "brand.name.required")
    @Size(min = 3, max = 25, message = "brand.name.size.notmet")
    private final String name;

    private final String slug;

    private final String companyName;

    private final Map<String, Address> addresses;

    @URL(message = "brand.website.url.invalid")
    private final String website;

    @Email(message = "brand.emailAddress.email.invalid")
    private final String emailAddress;

    @NotNull(message = "brand.description.required")
    @ContainsDefault(message = "brand.description.default.required")
    private final LocalizedField<String> description;

    private final boolean industrial;

    private final LocalDateTime lastModified;

    @JsonCreator
    protected Brand(ObjectId _id, String name, String slug, String companyName, Map<String, Address> addresses,
            String website, String emailAddress, LocalizedField<String> description, boolean industrial,
            LocalDateTime lastModified) {
        this.id = _id;
        this.name = name;
        this.slug = slug;
        this.companyName = companyName;
        this.addresses = addresses;
        this.website = website;
        this.emailAddress = emailAddress;
        this.description = description;
        this.industrial = industrial;
        this.lastModified = lastModified;
    }

    private Brand(Builder b) {
        this.id = b.id;
        this.name = b.name;
        this.slug = Slug.orElseGet(b.slug, () -> Slug.of(b.name));
        this.companyName = b.companyName;
        this.addresses = b.addresses;
        this.website = b.website;
        this.emailAddress = b.emailAddress;
        this.description = b.description;
        this.industrial = b.industrial;
        this.lastModified = b.lastModified;
    }

    /**
     * Constructs a new {@code Brand} objects using the builder fluent interface.
     *
     *  <p>
     *      <pre>
     *  Brand acme = build(b -> b
     *             .id(new ObjectId("607c7f79bcf86cd7994f6c0a"))
     *             .name("ACME")
     *             .companyName("Anonima Costruttori Modelli Esatti")
     *             .website("http://www.acmetreni.com")
     *             .emailAddress("mail@acme.com")
     *             .description(Locale.ENGLISH, "ACME description")
     *             .industrial(true));
     *      </pre>
     *  </p>
     */
    public static Brand build(UnaryOperator<Builder> op) {
        return op.apply(new Builder()).build();
    }

    /**
     * Implements a fluent interface to construct {@code Brand} objects.
     */
    public static class Builder {
        private ObjectId id;
        private String name;
        private String slug;
        private String companyName;
        private Map<String, Address> addresses;
        private String website;
        private String emailAddress;
        private LocalizedField<String> description;
        private boolean industrial;
        private LocalDateTime lastModified;

        private Builder() {
        }

        public Builder id(ObjectId id) {
            this.id = id;
            return this;
        }

        public Builder industrial(boolean industrial) {
            this.industrial = industrial;
            return this;
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Builder companyName(String companyName) {
            this.companyName = companyName;
            return this;
        }

        public Builder slug(String slug) {
            this.slug = slug;
            return this;
        }

        public Builder emailAddress(String emailAddress) {
            this.emailAddress = emailAddress;
            return this;
        }

        public Builder website(String url) {
            website = url;
            return this;
        }

        public Builder description(String desc) {
            this.description = Fun.lazyApply(description, () -> LocalizedField.of(desc), field -> field.with(desc));
            return this;
        }

        public Builder description(Locale lang, String desc) {
            this.description = Fun.lazyApply(description, () -> LocalizedField.of(lang, desc),
                    field -> field.with(lang, desc));
            return this;
        }

        public Builder lastModified(LocalDateTime lastModified) {
            this.lastModified = lastModified;
            return this;
        }

        public Builder address(String country, Address a) {
            if (addresses == null) {
                addresses = new HashMap<>();
            }
            addresses.put(country, a);
            return this;
        }

        private Brand build() {
            return new Brand(this);
        }
    }

    /**
     * Returns the {@code Brand} id.
     * @return the unique id
     */
    public ObjectId getId() {
        return id;
    }

    /**
     * Returns the {@code Brand} name.
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * Returns the {@code Brand} slug.
     * <p>
     *  By default a value for the {@code Brand} slug is produced encoding
     *  the value from {@link Brand#getName()}.
     * </p>
     *
     * @return the slug
     */
    public String getSlug() {
        return slug;
    }

    /**
     * Returns the {@code Brand} company name.
     * @return the company name
     */
    public String getCompanyName() {
        return companyName;
    }

    /**
     * Returns the {@code Brand} addresses.
     * <p>
     *  The company can have more local branch, in case no {@code Address} has
     *  been provided this method will return an {@code EMPTY_MAP}.
     * </p>
     *
     * @return the addresses
     */
    public Map<String, Address> getAddresses() {
        return addresses;
    }

    /**
     * Returns the {@code Brand} website url.
     * @return the website url
     */
    public String getWebsite() {
        return website;
    }

    /**
     * Returns the {@code Brand} email address.
     * @return the email address
     */
    public String getEmailAddress() {
        return emailAddress;
    }

    /**
     * Returns the {@code Brand} company description.
     * @return the description
     */
    public LocalizedField<String> getDescription() {
        return description;
    }

    /**
     * Returns the {@code Brand} industrial flag.
     * @return {@code true} if this is a industrial series producer; {@code false} otherwise
     */
    public boolean isIndustrial() {
        return industrial;
    }

    /**
     * Returns the last modified timestamp.
     * @return the timestamp
     */
    public LocalDateTime getLastModified() {
        return lastModified;
    }

    public EntityLink asLink() {
        return EntityLink.to(Brand.class).with(this, Brand::getSlug, Brand::getName);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Brand))
            return false;

        Brand that = (Brand) obj;

        return Objects.equals(this.companyName, that.companyName) && Objects.equals(this.name, that.name)
                && Objects.equals(this.slug, that.slug) && Objects.equals(this.industrial, that.industrial)
                && Objects.equals(this.addresses, that.addresses)
                && Objects.equals(this.description, that.description) && Objects.equals(this.website, that.website)
                && Objects.equals(this.emailAddress, that.emailAddress);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, slug, companyName, addresses, website, emailAddress, description, industrial);
    }

    @Override
    public String toString() {
        return com.google.common.base.Objects.toStringHelper(Brand.class).omitNullValues().add("name", name)
                .add("slug", slug).add("companyName", companyName).add("addresses", addresses)
                .add("website", website).add("emailAddress", emailAddress).toString();
    }
}