Java tutorial
/* * 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(); } }