org.tonguetied.keywordmanagement.Translation.java Source code

Java tutorial

Introduction

Here is the source code for org.tonguetied.keywordmanagement.Translation.java

Source

/*
 * Copyright 2008 The Tongue-Tied 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 org.tonguetied.keywordmanagement;

import java.io.Serializable;
import java.util.Comparator;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;

import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.hibernate.annotations.AccessType;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.ForeignKey;
import org.hibernate.annotations.Type;
import org.tonguetied.audit.Auditable;
import org.tonguetied.utils.pagination.DeepCloneable;

/**
 * A translation is a specific value of a {@link Keyword} for a 
 * {@link Language}, {@link Country} and {@link Bundle}.
 * 
 * @author mforslund
 * @author bsion
 */
@Entity
@AccessType("property")
@NamedQueries({ @NamedQuery(name = Translation.QUERY_FIND_TRANSLATIONS, query = "select translation "
        + "from Translation translation " + "where translation.country in (:countries) "
        + "and translation.bundle in (:bundles) " + "and translation.language in (:languages) "
        + "and translation.state = :state " + "order by lower(translation.keyword.keyword), "
        + "translation.language, " + "translation.country, " + "translation.bundle") })
@Table(name = Translation.TABLE_TRANSLATION, uniqueConstraints = {
        @UniqueConstraint(columnNames = { "keyword_id", "language_id", "country_id", "bundle_id" }) })
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Translation implements DeepCloneable<Translation>, Comparable<Translation>, Auditable {
    private Long id;
    private String value;
    private Language language;
    private Country country;
    private Bundle bundle;
    private Keyword keyword;
    private TranslationState state;

    // This attribute is used for optimistic concurrency control in DB
    private Integer version;

    public static final String TABLE_TRANSLATION = "translation";
    private static final String COL_ID = TABLE_TRANSLATION + "_id";
    private static final String FK_BUNDLE = "fk_" + Bundle.TABLE_BUNDLE + "_" + TABLE_TRANSLATION;
    private static final String FK_COUNTRY = "fk_" + Country.TABLE_COUNTRY + "_" + TABLE_TRANSLATION;
    private static final String FK_KEYWORD = "fk_" + Keyword.TABLE_KEYWORD + "_" + TABLE_TRANSLATION;
    private static final String FK_LANGUAGE = "fk_" + Language.TABLE_LANGUAGE + "_" + TABLE_TRANSLATION;

    /**
     * Name of the query to search for translations.
     */
    public static final String QUERY_FIND_TRANSLATIONS = "find.translations";

    /**
     * Create a new instance of Translation. This constructor initialises all
     * the required fields.
     */
    public Translation() {
        this.state = TranslationState.UNVERIFIED;
    }

    /**
     * Create a new instance of Translation.
     * 
     * @param bundle the {@link Bundle} of this Translation
     * @param country the {@link Country} of this Translation
     * @param language the {@link Language} of this Translation
     * @param value the translated value
     * @param state the state of this Translation
     * @throws IllegalArgumentException if the <code>state</code> parameter is
     * <code>null</code>
     */
    public Translation(Bundle bundle, Country country, Language language, String value, TranslationState state) {
        if (state == null)
            throw new IllegalArgumentException("state cannot be null");

        this.value = value;
        this.language = language;
        this.country = country;
        this.bundle = bundle;
        this.state = state;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO, generator = "translation_generator")
    @SequenceGenerator(name = "translation_generator", sequenceName = "translation_id_seq")
    @Column(name = COL_ID)
    public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }

    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "bundle_id")
    @ForeignKey(name = FK_BUNDLE)
    public Bundle getBundle() {
        return bundle;
    }

    public void setBundle(final Bundle bundle) {
        this.bundle = bundle;
    }

    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "country_id")
    @ForeignKey(name = FK_COUNTRY)
    public Country getCountry() {
        return country;
    }

    public void setCountry(final Country country) {
        this.country = country;
    }

    @ManyToOne
    @JoinColumn(name = "keyword_id", insertable = false, updatable = false)
    @ForeignKey(name = FK_KEYWORD)
    public Keyword getKeyword() {
        return keyword;
    }

    public void setKeyword(final Keyword keyword) {
        this.keyword = keyword;
    }

    @OneToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = "language_id")
    @ForeignKey(name = FK_LANGUAGE)
    public Language getLanguage() {
        return language;
    }

    public void setLanguage(final Language language) {
        this.language = language;
    }

    /**
     * 
     * @return the translated value
     */
    @Type(type = "text")
    public String getValue() {
        return value;
    }

    public void setValue(final String value) {
        this.value = value;
    }

    /**
     * @return the flag indicating if the workflow state of this Translation
     */
    @Column(nullable = false, length = 10)
    @Enumerated(EnumType.STRING)
    public TranslationState getState() {
        return state;
    }

    /**
     * @param state the {@link TranslationState} to set
     */
    public void setState(final TranslationState state) {
        this.state = state;
    }

    /**
     * This field is used for optimistic locking.
     * 
     * @return the version
     */
    @Version
    @Column(name = "optlock")
    public Integer getVersion() {
        return version;
    }

    /**
     * This field is used for optimistic locking.
     * 
     * @param version the version to set
     */
    public void setVersion(Integer version) {
        this.version = version;
    }

    /* (non-Javadoc)
     * @see java.lang.Comparable#compareTo(java.lang.Object)
     */
    public int compareTo(final Translation other) {
        return new CompareToBuilder().append(keyword, other.keyword).append(language, other.language)
                .append(country, other.country).append(bundle, other.bundle).append(value, other.value)
                .append(state, other.state).toComparison();
    }

    @Override
    public boolean equals(Object obj) {
        boolean isEqual = false;
        // a good optimization
        if (this == obj) {
            isEqual = true;
        } else if (obj instanceof Translation) {
            final Translation other = (Translation) obj;

            EqualsBuilder builder = new EqualsBuilder();
            isEqual = builder.append(value, other.value).append(bundle, other.bundle).append(country, other.country)
                    .append(language, other.language).append(keyword, other.keyword).append(state, other.state)
                    .isEquals();
        }

        return isEqual;
    }

    @Override
    public int hashCode() {
        HashCodeBuilder builder = new HashCodeBuilder(33, 19);
        builder.append(keyword).append(bundle).append(country).append(language).append(value).append(state);
        //            append(keyword).append(value);

        return builder.toHashCode();
    }

    public Translation deepClone() {
        Translation clone;
        try {
            clone = (Translation) super.clone();
        } catch (CloneNotSupportedException cnse) {
            clone = null;
        }
        return clone;
    }

    @Override
    public String toString() {
        return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
    }

    public String toLogString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Translation[bundle=").append(bundle == null ? null : bundle.toLogString())
                .append(", country=").append(country == null ? null : country.toLogString()).append(", language=")
                .append(language == null ? null : language.toLogString()).append(", state=").append(state)
                .append(", value=").append(value).append("]");

        return builder.toString();
    }

    /**
     * These values represent the workflow states for a translation.
     * 
     * @author bsion
     *
     */
    public static enum TranslationState {
        UNVERIFIED, VERIFIED, QUERIED
    }

    /**
     * Comparator class used when Translations should be compared by the 
     * {@link Translation#id} rather than the business key as used in the 
     * equals method.
     * 
     * @author bsion
     * @see Translation#equals(Object)
     */
    protected static class TranslationIdComparator implements Comparator<Translation>, Serializable {
        private static final long serialVersionUID = 8942014286479032574L;

        public int compare(Translation t1, Translation t2) {
            int result;
            if (t1.getId() == null && t2.getId() == null) {
                result = 0;
            } else if (t1.getId() != null && t2.getId() == null) {
                result = -1;
            } else if (t1.getId() == null && t2.getId() != null) {
                result = 1;
            } else {
                result = t1.getId().compareTo(t2.getId());
            }
            return result;
        }

    }
}