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

mplates.1.2.source-code.PojoBase.ftl Maven / Gradle / Ivy

<#include "license.ftl">
<@license/>
<#assign object = doc.object>
package ${object.@package}.model.base;

<#if object.attributes.html[0]??>
import redora.util.HtmlSanitizer;

<#list doc["/object/attributes/enum[@scope='global']"] as enum>
import ${object.@package}.model.enums.${enum.@class};


import redora.exceptions.*;
import ${object.@package}.service.*;

<#if object.attributes.set[0]??>
import redora.set.*;

import java.sql.ResultSet;
import java.util.Date;
import java.util.EnumMap;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.lang3.builder.HashCodeBuilder;

import redora.api.*;
<#if object.attributes.date[0]?? || object.attributes.datetime[0]??>
import java.text.ParseException;
import static redora.db.SQLParameter.yyyyMMdd;
import static redora.db.SQLParameter.yyyyMMddHHMMSS;

import java.util.logging.Level;
import java.util.logging.Logger;
import ${object.@package}.model.*;
import ${object.@package}.model.fields.${object.@name}Fields;

import static redora.api.fetch.Page.ALL_TABLE;
import static redora.api.fetch.Page.ALL_LIST;

<#if object.description[0]??>
/** 
 * ${object.description}
 * @author Redora (www.redora.net)
*/

public class ${object.@name}Base implements <#if object.sorted == "true">SortedPersistable<#if object.interface[0]??>, ${object.interface} {
    private static final transient Logger l = Logger.getLogger("${object.@package}.model.${object.@name}Base");
    
    /** How deep should the isDirty() check go. @see #isDirty() */
    public static final int MAX_DIRTY_LEVEL = 7;
    public Long id;
    @Override
    public Long getId() {
        return id;
    }
    public void setId(@org.jetbrains.annotations.NotNull Long id) {
        if (this.id != null) throw new IllegalArgumentException("It is not allowed to modify the id");
        this.id = id;
    }
    public Date creationDate;
    public Date getCreationDate() {
        assert fetchScope != redora.api.fetch.Scope.List : "This object is fetched as Scope.List. Fetch the object with Table or Form scope instead.";
        return this.creationDate;
    }
    public Date updateDate;
    public Date getUpdateDate() {
        assert fetchScope != redora.api.fetch.Scope.List : "This object is fetched as Scope.List. Fetch the object with Table or Form scope instead.";
        return this.updateDate;
    }
<#list doc["/object/attributes/enum[@scope='local']"] as att>
    <#if att.description[0]??>
    /** ${att.description} */
    
    public enum ${att.@class} {
    <#list att.element as value>
        <#if value.@description[0]??>
        /** ${value.@description} */
        
        ${value.@name}<#if value_has_next>,<#else>;
    
        /** @return Null, or the result of valueOf() */
        public static ${att.@class} valueOfNullSafe(String value) {
            if (value != null) {
                return valueOf(value);
            }
            return null;
        }
    }


<#list object.formScope?children as att><#if att?node_type == "element">
    <#if att.@notnull == "true" && att.@default[0]??>@org.jetbrains.annotations.NotNull
    public ${att.@className} ${att.@fieldName};
    
    <#if att?node_name == "object">
    /** @return true if ${att.@fieldName} does not need to be (lazy) fetched from DB anymore. */
    public boolean ${att.@fieldName}IsRetrieved() {
        return ${att.@fieldName} != null || ${att.@fieldName}Id == null || ${att.@fieldName}Id.equals(-1L);
    }


<#list object.attributes.set as att>
    protected final ${att.@className} ${att.@fieldName} = new Persistable<#if att.@multiplicity == "n-to-m" && (att.@sorted == "both" || att.@sorted == "them") || att.@sorted == "true">SortedArrayList<${att.@class}>(<#if att.@multiplicity == "n-to-m" && (att.@sorted == "both" || att.@sorted == "them")>true<#elseif att.@sorted == "true">false);
    /** @return true if ${att.@fieldName} does not need to be (lazy) fetched from DB anymore. */
    public boolean ${att.@fieldName}IsRetrieved() {
        return ${att.@fieldName}.isRetrieved();
    }


    public final Map<${object.@name}Fields, Object> dirty = new EnumMap<${object.@name}Fields, Object>(${object.@name}Fields.class);
    public boolean isNew;
    /** How is this object retrieved. By default (if for example the object is new) it's scope is assumed as Form. */
    public redora.api.fetch.Scope fetchScope;

    /**
    * This method will set default values for:
<#list doc["/object/attributes/*[@default]"] as att> * ${att.@fieldName} - ${att.@default};
*/ protected ${object.@name}Base() { super(); <#list doc["/object/attributes/*[@default]"] as att> <#if att?node_name == "boolean"> ${att.@fieldName} = Boolean.${att.@default?upper_case}; <#elseif att?node_name == "string"> ${att.@fieldName} = "${att.@default}"; <#elseif att?node_name == "integer" || att?node_name == "long" || att?node_name == "double"> ${att.@fieldName} = ${att.@default}<#if att?node_name == "long">L; <#elseif att?node_name == "enum"> ${att.@fieldName} = ${att.@className}.${att.@default}; <#else> error - undefined default ${att?node_name} isNew = true; fetchScope = redora.api.fetch.Scope.Form; <#list object.attributes.set as att> ${att.@fieldName}.reset(); } /** * Initializes ${object.@name} using a record in a ResultSet. * @param rs (Mandatory) ResultSet object using the field set defined in ${object.@name}SQLBase pointing to the record you want to serialize. * @param offset (Mandatory) Usually 0, but if the field set is more then this object's field set you must set the offset. * @param scope (Mandatory) The scope of the executed query, like Scope.Table of Scope.Form. */ public ${object.@name}Base(@org.jetbrains.annotations.NotNull ResultSet rs, int offset , @org.jetbrains.annotations.NotNull redora.api.fetch.Scope scope) throws CopyException { super(); ${object.@name}Util.copy(rs, offset, scope, this); isNew = false; dirty.clear(); } <#list object.formScope?children as att> <#if att.description[0]??> /** * ${att.description} */ public void set${att.@fieldName?cap_first}(@org.jetbrains.annotations.<#if att.@notnull == "true">NotNull<#else>Nullable ${att.@className} ${att.@fieldName}) <#if att.@lazy == "true" && att?node_name == "string">throws LazyException <#elseif att?node_name == "html">throws LazyException, FieldException{ assert fetchScope != redora.api.fetch.Scope.List : "Modification is not allowed, this object is fetched as Scope.List and cannot be persisted. Fetch the object with Table or Form scope instead."; <#if att?node_name == "date" || att?node_name == "datetime"> String stripped = null; //strip (nano) seconds - hours to ${att?node_name} level if (${att.@fieldName} != null) { stripped = yyyyMMdd<#if att?node_name == "datetime">HHMMSS.format(${att.@fieldName}); } if ((this.${att.@fieldName} == null ? null : yyyyMMdd<#if att?node_name == "datetime">HHMMSS.format(this.${att.@fieldName})) != stripped) { if (!dirty.containsKey(${object.@name}Fields.${att.@fieldName})) { dirty.put(${object.@name}Fields.${att.@fieldName}, this.${att.@fieldName}); } if (stripped == null) { this.${att.@fieldName} = null; } else { try { this.${att.@fieldName} = yyyyMMdd<#if att?node_name == "datetime">HHMMSS.parse(stripped); } catch (ParseException e) { l.log(Level.SEVERE, "Did not expect this would not parse to date " + stripped, e); throw new RuntimeException("Did not expect this would not parse to date " + stripped, e); } } } } <#elseif att?node_name == "object"> <#if att.@pigsear == "true"> assert !this.equals(${att.@fieldName}) : "Circular reference " + ${att.@fieldName}; if (!dirty.containsKey(${object.@name}Fields.${att.@fieldName}Id)) { if (${att.@fieldName}Id == null ? ${att.@fieldName} != null : ${att.@fieldName} == null || !${att.@fieldName}Id.equals(${att.@fieldName}.getId())) { dirty.put(${object.@name}Fields.${att.@fieldName}Id, this.${att.@fieldName}Id); } } this.${att.@fieldName} = ${att.@fieldName}; if (this.${att.@fieldName} != null) { this.${att.@fieldName}Id = ${att.@fieldName}.getId(); } else { this.${att.@fieldName}Id = null; } } <#elseif att?node_name == "html"> if (${att.@fieldName} != null) { String _cleanHtml = HtmlSanitizer.clean("${att.@policy[0]!"antisamy.xml"}", ${att.@fieldName}); if (!_cleanHtml.equals(this.${att.@fieldName})) { if (!dirty.containsKey(${object.@name}Fields.${att.@fieldName})) { dirty.put(${object.@name}Fields.${att.@fieldName}, get${att.@fieldName?cap_first}()); } this.${att.@fieldName} = _cleanHtml; } } else if (this.${att.@fieldName} != null) { if (!dirty.containsKey(${object.@name}Fields.${att.@fieldName})) { dirty.put(${object.@name}Fields.${att.@fieldName}, this.${att.@fieldName}); } this.${att.@fieldName} = null; } } <#elseif att?node_type == "element"> if ((${att.@fieldName} == null ? this.${att.@fieldName} != null : !${att.@fieldName}.equals(this.${att.@fieldName})) && !dirty.containsKey(${object.@name}Fields.${att.@fieldName})) { dirty.put(${object.@name}Fields.${att.@fieldName}, this.${att.@fieldName}); } this.${att.@fieldName} = ${att.@fieldName}; } <#if att.description[0]??> /** * ${att.description} */ public ${att.@className} get${att.@fieldName?cap_first}() <#if att.@lazy == "true">throws LazyException { <#if att.@list == "false"> assert fetchScope != redora.api.fetch.Scope.List : "This object is fetched as Scope.List. Fetch the object with Table or Form scope instead."; <#if att.@lazy == "true"> <#if att?node_name == "object"> if (${att.@fieldName}Id != null && ${att.@fieldName} == null) { <#else> if (fetchScope == redora.api.fetch.Scope.Table) { fetchLazy(); } return ${att.@fieldName}; } <#list object.attributes.set as att> /** <#if att.description[0]??> * ${att.description} <#if att.@sorted == "true"> *
* This relationship is sortable, use the moveTo() function like get${att.@fieldName?cap_first}().moveTo(object, position); *
* If you wish to add a ${att.@class} to this list, do something like: get${att.@class}s().add(${att.@class});. * All the Collection methods like add, remove, addAll and removeAll are supported. * When you add or update ${att.@plural} to this set, they will be persisted together with ${object.@name}. * @return Empty or filled list. */ @org.jetbrains.annotations.NotNull public ${att.@className} get${att.@fieldName?cap_first}() throws QueryException { if (!${att.@fieldName}.isRetrieved()) { ${att.@class}Service service = null; try { service = ServiceFactory.${att.@class?uncap_first}Service(); ${att.@fieldName}.addAll(service.finder(${object.@package}.sql.base.${att.@class}SQLBase.DefaultFinder.FindBy${att.@myName?cap_first}Id, id, fetchScope == redora.api.fetch.Scope.List ? ALL_LIST : ALL_TABLE)); } catch (RedoraException e) { throw new QueryException("Failed to retrieve ${att.@fieldName} for " + this.toString(), e); } finally { ServiceFactory.close(service); } ${att.@fieldName}.reset(); } return ${att.@fieldName}; } /** * Checks if any of the attributes have changed. Also the related children and objects are checked. * If you want to avoid the related object dirty check, use isDirty(${object.@name}.MAX_DIRTY_LEVEL) instead. * @return true if any of the attributes of ${object.@name} have changed */ public boolean isDirty() { return isDirty(new HashSet()); } /** * {@inheritDoc} * @see #isDirty() * @param ignore (Optional) List of already dirty checked objects to avoid circular checking. * @return true is somewhere something has changed */ @Override public boolean isDirty(@org.jetbrains.annotations.NotNull Set ignore) { if (!dirty.isEmpty()) { return true; } <#if doc["/object/attributes/set"][0]?? || doc["/object/attributes/object"][0]??> try { <#list doc["/object/attributes/set"] as att> if (${att.@fieldName}IsRetrieved() && get${att.@fieldName?cap_first}().isDirty(ignore)) { return true; } <#list doc["/object/attributes/object"] as att> if (${att.@fieldName}IsRetrieved() && get${att.@fieldName?cap_first}() != null && ignore.add(get${att.@fieldName?cap_first}()) && get${att.@fieldName?cap_first}().isDirty(ignore)) { return true; } } catch (RedoraException e) { l.log(Level.SEVERE, "This exception can't happen because i should not perform any kind of DB related activities", e); } return false; } @Override /** Checks primarily on Id, if there is no Id, it will try hashCode. */ public boolean equals(Object that) { if (this == that) return true; if (that instanceof ${object.@name}) return equals((${object.@name})that); return false; } /** Checks primarily on Id, if there is no Id, it will try hashCode. */ public boolean equals(${object.@name} that) { if (id != null) return that.id != null && id.longValue() == that.id.longValue(); else return that.id == null && hashCode() == that.hashCode(); } /** * The hashCode is computed on the Id which is as fast as it can get. If there is * no Id (new object), the hash code is calculated on all the other fields. * @return the hash code of Id, or, when null, a hash code created by all the other fields. */ @Override public int hashCode() { if (id != null) { return id.hashCode(); } return new HashCodeBuilder(<#if object.@sequence?number % 2 == 0>${object.@sequence?number + 97}<#else>${object.@sequence}, 37) <#list object.formScope?children as att> <#if att?node_name != "object"> .append(${att.@fieldName}) .toHashCode(); } /** * Provides info from following fields: <#if object.listScope[0]??> <#list object.listScope?children as att> <#if att?node_name != "object"> * ${att.@fieldName} * and id */ @Override public String toString() { StringBuilder retVal = new StringBuilder(); <#if object.listScope[0]??> <#list object.listScope?children as att> <#if att?node_name != "object"> retVal.append(${att.@fieldName}).append(" "); retVal.append('(').append(id).append(')'); return retVal.toString(); } /** * Creates a new ${object.@name} with all the same values, also related children are cloned. * When you persist, only the Id('s) will differ. *
* Parent objects, will be copied, 1-to-n children will be cloned, n-to-m children will * be copied. In fact, everything will be copied, only children will be cloned. *
* The clone method is somewhat potent because it also clones related objects. * It however restrains itself by cloning until the MAX_DIRTY_LEVEL and direct * pigsears (1-to-n and n-to-m) are resolved. Indirect pigsears (relations that * use an intermediate object) are not resolved and can lead to runaway cloning. *
* id, creationDate and updateDate are not copied. * @see #MAX_DIRTY_LEVEL * @return the cloned ${object.@name} or null when there was a LazyException. */ @Override @SuppressWarnings({"CloneDoesntCallSuperClone"}) public ${object.@name} clone() { return clone(1); } /** * Creates a new ${object.@name} with all the same values, also related children are cloned. * When you persist, only the Id('s) will differ. * This method is used primarily to implement the clone() method. * @see #clone() * @param depth The depth of the cloning process into a string of relations. * @return the cloned ${object.@name} or null when there was a LazyException. */ @Override public ${object.@name} clone(int depth) { ${object.@name} retVal = new ${object.@name}(); retVal.cloneMasterId = getId(); try { <#list object.attributes?children as att> <#if att?node_type == "element"> <#if att?node_name == "set"> <#if att.@multiplicity == "n-to-m"> retVal.get${att.@fieldName?cap_first}().addAll(get${att.@fieldName?cap_first}()); <#else> if (depth < MAX_DIRTY_LEVEL) { retVal.get${att.@fieldName?cap_first}().addAll(get${att.@fieldName?cap_first}().clone(depth + 1)); } <#elseif att?node_name == "object"> //Only copy object relations on the first level, if you need more, then override this behavior in ${object.@name}.java. if (depth == 1 && get${att.@fieldName?cap_first}() != null) { retVal.set${att.@fieldName?cap_first}(get${att.@fieldName?cap_first}().clone(MAX_DIRTY_LEVEL)); } <#elseif (att?node_name != "long" || !att.@parentClass[0]??)> retVal.set${att.@fieldName?cap_first}(get${att.@fieldName?cap_first}()); } catch (Exception e) { l.log(Level.SEVERE, "Failed to clone this ${object.@name} " + getId(), e); retVal = null; } return retVal; } /** When cloned, the master's id is kept here. This id is not persisted.*/ public Long cloneMasterId; <#if object.hasLazy == "true"> protected void fetchLazy() throws LazyException { //Set fetchScope at the beginning, otherwise you might get an infinite loop with get/set thinking it is still lazy fetchScope = redora.api.fetch.Scope.Form; try { <#if object.lazyScope[0]??> if (!isNew) { ${object.@name}Service service = ServiceFactory.${object.@name?uncap_first}Service(); Map _lazy = service.fetchLazy(id); ServiceFactory.close(service); <#list doc["/object/lazyScope/*"] as att> <#if att?node_type == "element"> if (_lazy.get(${object.@name}Fields.${att.@fieldName}.name()) != null) { ${att.@fieldName} = (${att.@className})_lazy.get(${object.@name}Fields.${att.@fieldName}.name()); } } <#list doc["/object/attributes/object[@lazy='true']"] as att> if (${att.@fieldName}Id != null) { ${att.@className}Service service = ServiceFactory.${att.@className?uncap_first}Service(); try { ${att.@fieldName} = service.findById(${att.@fieldName}Id, redora.api.fetch.Scope.Table); } catch (RedoraException e) { throw new LazyException("Can retrieve ${att.@fieldName} " + ${att.@fieldName}Id, e); } finally { ServiceFactory.close(service); } } } catch (ConnectException e) { throw new LazyException("Failed to get a connection to retrieve lazy fetched attributes for ${object.@name} " + id, e); } } <#if object.sorted == "true"> @Override public int compareTo(Object o) { return getSortOrder().compareTo(((${object.@name})o).getSortOrder()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy