Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
mplates.1.2.source-code.PojoServiceBase.ftl Maven / Gradle / Ivy
<#include "license.ftl">
<@license/>
<#assign object = doc.object>
package ${object.@package}.service.base;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
<#assign stream = "false">
<#list doc["/object/attributes/*"] as att>
<#if att?node_name == "html">
<#assign stream = "true">
<#elseif att?node_name == "string" && att.@maxlength[0]?number > 65000>
<#assign stream = "true">
<#if stream == "true">
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
<#if stream == "true">
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import redora.api.Persistable;
import redora.api.fetch.*;
import redora.exceptions.*;
import redora.service.*;
import ${object.@package}.model.*;
import ${object.@package}.model.fields.*;
import ${object.@package}.service.*;
<#list doc["/object/attributes/enum[@scope='global']"] as att>
import ${object.@package}.model.enums.${att.@class};
<#if object.trashcan == "true">
import redora.configuration.rdo.service.TrashService;
import static ${object.@package}.sql.${object.@name}SQL.*;
import static ${object.@package}.businessrules.${object.@name}BusinessRules.check;
import static java.util.logging.Level.FINE;
import static java.util.logging.Level.SEVERE;
import static redora.db.SQLParameter.*;
/**
* You can work with the pojo's using this service. For example if you create command line J2SE functionality
* or server side logic.
* If you want to use your data in a web application, you also might want to look at {@link ${object.@name}ServiceJSON}
* and {@link ${object.@package}.service.http.${object.@name}Servlet}.
* Whenever business rule logic needs to be checked, it will go through here. For example a web user wants to persist
* some data. He will post this for example as JSON to {@link ${object.@package}.service.http.${object.@name}Servlet}
* which in turn invokes {@link ${object.@name}ServiceJSON} which will serialize the JSON stream into a pojo
* and then will invoke the persist method of this service.
* @author Redora (www.redora.net)
*/
public class ${object.@name}ServiceBase extends ServiceBase {
static final transient Logger l = Logger.getLogger("${object.@package}.service.${object.@name}Service");
/**
* Don't use this directly but use the ServiceFactory instead:
*
* ${object.@name}Service() myService = ServiceFactory.${object.@name?uncap_first}();
* ... do stuff
* ServiceFactory.close(myService);
*
* Initializes ${object.@name}Service.
* @see ${object.@package}.service.ServiceFactory
*/
protected ${object.@name}ServiceBase() throws ConnectException {
super("${object.schema[0]!"default"}");
}
/**
* Chains this service object to another service object. The database connection
* and transaction is managed by the other service.
* @param chain (Mandatory) Service you want to make this service dependent on.
*/
protected ${object.@name}ServiceBase(@NotNull ServiceBase chain) {
super(chain, "${object.schema[0]!"default"}");
inTransaction = true; //Let the calling service handle the transaction
}
/**
* Simple finder to get ${object.@name} by it's id.
* @param id (Mandatory) The primary key.
* @param scope (Mandatory) The allowed fetch scope: Scope.Table, Scope.Form, Scope.List.
* @return The desired ${object.@name}
* @throws ObjectNotFoundException When there is no object in the DB with this Id.
*/
@NotNull
public ${object.@name} findById(@NotNull Long id, @NotNull Scope scope)
throws QueryException, CopyException, ObjectNotFoundException {
${object.@name} retVal = null;
String SQL;
switch (scope) {
case Table:
SQL = FIND_BY_ID_TABLE;
break;
case Form:
SQL = FIND_BY_ID_FORM;
break;
case List:
SQL = FIND_BY_ID_LIST;
break;
default:
throw new IllegalArgumentException("Illegal scope for this finder: " + scope);
}
SQL = prepare(SQL, id);
ResultSet rs = null;
try {
rs = sqlQuery(SQL);
if (rs.next()) {
retVal = new ${object.@name}(rs, 0, scope);
} else {
throw new ObjectNotFoundException("Could not find ${object.@name} " + id);
}
} catch(SQLException e) {
l.log(SEVERE, "Failed to run query " + SQL, e);
throw new QueryException("Failed to run query: " + SQL, e);
} finally {
close(rs);
}
return retVal;
}
/**
* Finds records by custom SQL. Custom queries should be defined in the queries section in the model.
* @param sql (Mandatory) The SQL statement you wish to use. See also ${object.@name}SQL.
* @param params (Optional) List of parameters. When omitted it is assumed there are no parameters.
* @param page (Mandatory) The Page strategy. Allowed scopes are: Scope.Table, Scope.Form, Scope.List, Scope.Lazy.
* @return Empty or filled list with ${object.@name}
*/
@NotNull
public List<${object.@name}> find(@NotNull String sql, @Nullable List params, @NotNull Page page)
throws QueryException, CopyException, PagingException {
List<${object.@name}> retVal = new ArrayList<${object.@name}>();
String SQL = sql;
if (params != null) {
for (Object param : params) {
SQL = prepare(SQL, param);
}
}
SQL = preparePage(SQL, page);
ResultSet rs = null;
try {
rs = sqlQuery(SQL);
while (rs.next()) {
retVal.add(new ${object.@name}(rs, 0, page.getScope()));
}
} catch(SQLException e) {
l.log(SEVERE, "Failed to run query: " + SQL, e);
throw new QueryException("Failed to run query: " + SQL, e);
} finally {
close(rs);
}
return retVal;
}
@NotNull
public List<${object.@name}> finder(DefaultFinder finder, Object param, Page page)
throws QueryException, CopyException, PagingException {
if (!(page.getScope() == Scope.List || page.getScope() == Scope.Table)) {
throw new PagingException("Illegal scope (" + page.getScope() + ") for this finder: " + finder);
}
String SQL = page.getScope() == Scope.Table ? finder.sqlTable : finder.sqlList;
if (param instanceof List) {
return find(page.getScope() == Scope.Table ? finder.sqlTable : finder.sqlList, (List)param, page);
} else if (finder != DefaultFinder.FindAll) {
SQL = prepare(SQL, param);
}
return find(SQL, null, page);
}
/**
* Finds All records
* @param page (Mandatory) The Page strategy. The allowed fetch scopes are: Scope.Table and Scope.List.
* @return Empty or filled list with ${object.@name}
*/
@NotNull
public List<${object.@name}> findAll(@NotNull Page page)
throws QueryException, CopyException, PagingException {
return finder(DefaultFinder.FindAll, null, page);
}
<#list doc["/object/attributes/*/finder"] as finder>
/**
* @param page (Mandatory) Allowed: Scope.Table, Scope.List.
* @return Empty or filled list
*/
@NotNull
public List<${object.@name}> ${finder.@name}(@NotNull <#if finder?parent?node_name == "set" || finder?parent?node_name == "object">Long<#else><#if finder?parent?node_name == "enum" && finder?parent.@scope == "local">${object.@name}.${finder?parent.@className} finder, @NotNull Page page)
throws QueryException, CopyException, PagingException {
if (!(page.getScope() == Scope.List || page.getScope() == Scope.Table)) {
throw new PagingException("Illegal scope: " + page.getScope());
}
List<${object.@name}> retVal = new ArrayList<${object.@name}>();
String SQL = page.getScope() == Scope.Table ? ${finder.@tableName} : ${finder.@listName};
<#if finder?parent?node_name == "object" || finder?parent?node_name == "long" || finder?parent?node_name == "integer" || finder?parent?node_name == "date" || finder?parent?node_name == "double">
SQL = prepare(SQL, finder);
<#elseif finder?parent?node_name == "string">
SQL = prepareDirty(SQL, finder);
<#elseif finder?parent?node_name == "enum">
SQL = prepare(SQL, finder.name());
SQL = preparePage(SQL, page);
ResultSet rs = null;
try {
rs = sqlQuery(SQL);
while (rs.next()) {
retVal.add(new ${object.@name}(rs, 0, page.getScope()));
}
} catch(SQLException e) {
l.log(SEVERE, "Failed to run query " + SQL, e);
throw new QueryException("Failed to run query: " + SQL, e);
} finally {
close(rs);
}
return retVal;
}
<#if finder?parent?node_name == "object" && object.trashcan == "true">
/**
* Trashes all ${object.@name}s without checking on business rules. This is usually invoked
* by the related parent which has already checked business rule violations.
* @param id (Mandatory) Related object id
*/
public void trashBy${finder?parent.@fieldName?cap_first}Id(@NotNull Long id, boolean undo, boolean asBatch) throws QueryException<#if finder?parent.@parentClass[0]??>, PersistException, CopyException {
String SQL = prepare(TRASH_BY_${finder?parent.@fieldName?upper_case}, !undo);
SQL = prepare(SQL, id);
execute(SQL);
}
<#if object.lazyScope[0]??>
/**
* Fetches all lazy=true attributes. Lazy relationships and objects are not fetched.
* This means the difference between Table and Form scope is fetched.
* This method does not exist if there are no lazy fetchable attributes for ${object.@name}.
* @param id Id of te lazy object
* @return Null or filled map with lazy objects
*/
@Nullable
public Map fetchLazy(@NotNull Long id) throws LazyException {
Map map = null;
String SQL = prepare(FETCH_LAZY_BY_ID, id);
ResultSet rs = null;
try {
rs = sqlQuery(SQL);
if (rs.next()) {
map = ${object.@name}Util.copyLazy(rs, 0);
} else {
throw new LazyException("Could not find ${object.@name} " + SQL);
}
} catch(SQLException e) {
l.log(SEVERE, "Failed to run query " + SQL, e);
throw new LazyException("Failed to run query: " + SQL, e);
} catch(CopyException e) {
l.log(SEVERE, "Failed to copy results " + SQL, e);
throw new LazyException("Failed to copy results " + SQL, e);
} finally {
close(rs);
}
return map;
}
<#list doc["/object/attributes/set[@multiplicity='n-to-m']"] as att>
/**
* Removes the relationship with ${att.@class} by deleting a record in the ${att.@relationTableName} table.
* @param ${att.@myName}Id (Mandatory) 'My' side of relationship
* @param ${att.@theirName}Id (Mandatory) 'Their' side of the relationship
*/
public void deleteRelationWith${att.@class}(@NotNull Long ${att.@myName}Id, @NotNull Long ${att.@theirName}Id
, boolean asBatch) throws QueryException {
String SQL = prepare(DELETE_${att.@relationTableName?upper_case}_RELATION, ${att.@myName}Id);
SQL = prepare(SQL, ${att.@theirName}Id);
execute(SQL);
}
<#if object.trashcan == "true">
/**
* Moves the relationship with ${att.@class} to the trash can.
* @param ${att.@myName}Id (Mandatory) 'My' side of relationship
* @param ${att.@theirName}Id (Mandatory) 'Their' side of the relationship
* @param undo True to undo it instead of trash
*/
protected void trashRelationWith${att.@class}(@NotNull Long ${att.@myName}Id
, @NotNull Long ${att.@theirName}Id, boolean asBatch, boolean undo)
throws QueryException {
String SQL = prepare(TRASH_${att.@relationTableName?upper_case}_RELATION, !undo);
SQL = prepare(SQL, ${att.@myName}Id);
SQL = prepare(SQL, ${att.@theirName}Id);
execute(SQL);
}
/**
* Moves all relationships with ${att.@class} to the trash can.
* @param ${att.@myName}Id (Mandatory) 'My' side of relationship
* @param undo True will undo all trashed relations
*/
protected void trashAllRelationsWith${att.@class}(@NotNull Long ${att.@myName}Id, boolean undo, boolean asBatch)
throws QueryException {
String SQL = prepare(TRASH_${att.@relationTableName?upper_case}_RELATION_BY_${att.@myName?upper_case}_ID, !undo);
SQL = prepare(SQL, ${att.@myName}Id);
execute(SQL);
}
/**
* Creates a relationship with {att.@class} by creating a record in the ${att.@relationTableName} table.
* @param ${att.@myName}Id (Mandatory) 'My' side of relationship
* @param ${att.@theirName}Id (Mandatory) 'Their' side of the relationship
<#if att.@sorted == "both" || att.@sorted == "them"> * @param sortOrder Position in the sorted relation
*/
public void connectTo${att.@class}(@NotNull Long ${att.@myName}Id, @NotNull Long ${att.@theirName}Id<#if att.@sorted == "both" || att.@sorted == "them">, int sortOrder, boolean asBatch)
throws QueryException, CopyException {
String SQL = prepare(INSERT_${att.@relationTableName?upper_case}_RELATION, ${att.@myName}Id);
SQL = prepare(SQL, ${att.@theirName}Id);
<#if att.@sorted == "both" || att.@sorted == "them">
SQL = prepare(SQL, sortOrder);
execute(SQL);
}
<#if att.@sorted == "both" || att.@sorted == "them">
/**
* Re-orders a sortable relationship with {att.@class} by updating the sortOrder in the ${att.@relationTableName} table.
* @param ${att.@myName}Id (Mandatory) 'My' side of relationship
* @param ${att.@theirName}Id (Mandatory) 'Their' side of the relationship
* @param sortOrder New position in the sorted relation
*/
public void reconnectTo${att.@class}(@NotNull Long ${att.@myName}Id, @NotNull Long ${att.@theirName}Id, int sortOrder)
throws QueryException, CopyException {
String SQL = prepare(UPDATE_${att.@relationTableName?upper_case}_RELATION, sortOrder);
SQL = prepare(SQL, ${att.@myName}Id);
SQL = prepare(SQL, ${att.@theirName}Id);
execute(SQL);
}
/**
* Count the connections in the relationship with {att.@class}.
* @param ${att.@myName}Id (Mandatory) 'Our' side object id
* @return 0 or more!
*/
public int countConnectionsTo${att.@class}(@NotNull Long ${att.@myName}Id)
throws PersistException, QueryException, CopyException {
String SQL = prepare(COUNT_${att.@relationTableName?upper_case}_RELATION, ${att.@myName}Id);
int retVal;
ResultSet rs = null;
try {
rs = sqlQuery(SQL);
rs.next();
retVal = rs.getInt(1);
} catch(SQLException e) {
l.log(SEVERE, "Failed to run query " + SQL, e);
throw new QueryException("Failed to run query: " + SQL, e);
} finally {
close(rs);
}
return retVal;
}
/**
* Inserts or updates a collection of ${object.@name}.
* Collections associated to ${object.@name} are persisted as well.
* JDBC batch update is used to improve performance.
* NOTE that this method assumes you already checked if given ${object.plural}
* have changed and if they did not violate any business rules.
* @param pojos List of pojo objects you want to persist
* @return Empty or filled list with violations. Note that (at least the unique
* key) is only evaluated in the database.
*/
@NotNull
public Set persist(@NotNull Collection<${object.@name}> pojos) throws RedoraException {
Set retVal = new HashSet();
boolean transact = !inTransaction;
if (transact) {
beginTransaction();
}
try {
for (${object.@name} pojo : pojos)
retVal.addAll(persist(pojo));
} catch (RedoraException e) {
if (transact) {
transact = false;
rollback();
}
throw e;
} finally {
if (transact)
if (retVal.isEmpty())
commit();
else
rollback();
}
return retVal;
}
/**
* Inserts or updates ${object.@name}. Collections associated to ${object.@name} are persisted as well.
* @param pojo (Mandatory) Object you want to persist
* @return Empty list when OK, else a list of violations.
*/
@NotNull
public Set persist(@NotNull ${object.@name} pojo) throws RedoraException {
if (!pojo.isDirty()) {
return new HashSet();
}
Set br = check(pojo, pojo.isNew ? BusinessRuleViolation.Action.Insert : BusinessRuleViolation.Action.Update);
if (!br.isEmpty()) {
return br;
}
return persist(pojo, false);
}
/**
* Persists the changes of ${object.@name} to the database and also any changed related children.
* Business rules are not checked, that is why this method is protected. However, unique key
* constrains are checked in the database, so this type of business rule is checked.
* When a unique key constraint is violated, the transaction is rolled back and a BusinessRuleViolation
* with the violating attribute is returned. If you have set up a transaction yourself (with service.beginTransaction()),
* you are supposed to rollback (or commit) yourself.
* The persist function 'knows' the changes in ${object.@name} because of the dirty set in this
* object. All the setters in ${object.@name} will set the object to dirty when they notice a change
* in value.
<#if doc["/object/attributes/set"][0]??>
* Persist will be performed in two actions. First it will persist the ${object.@name},
* using {@link #soloPersist(${object.@name})}. Then it will persist related children and parents
* using {@link #familyPersist(${object.@name}, boolean, boolean)}. The whole action is wrapped in a transaction and will be rolled back
* if somewhere something has failed.
* @see #familyPersist(${object.@name}, boolean, boolean)
* @see #soloPersist(${object.@name})
* @param asBatch Set to true if you want to execute the statements outside this method. You need to invoke ps.executeBatch() yourself.
* @return Empty when OK or filled with a unique key constraint violation
* @throws PersistException When the action through JDBC / DB has an unexpected problem.
*/
@NotNull
protected Set persist(@NotNull ${object.@name} pojo, boolean asBatch)
throws RedoraException {
l.log(FINE, "Updating {0}", pojo.getId());
if (pojo.fetchScope == Scope.List) {
throw new PersistException("Modification is not allowed, this object is fetched as Scope.List and cannot be persisted. Fetch the object with Table or Form scope instead.");
}
final boolean isNew = pojo.isNew;
Set retVal = null;
<#if doc["/object/attributes/set"][0]??>
boolean transact = !inTransaction; //only commit/rollback when you are not already in a transaction
if (transact) {
beginTransaction();
}
try {
retVal = soloPersist(pojo);
<#if doc["/object/attributes/set"][0]??>
if (retVal.isEmpty()) {
retVal = familyPersist(pojo, isNew, asBatch);
}
} catch (RedoraException e) {
if (transact) {
transact = false;
rollback();
}
throw e;
} finally {
if (transact) {
if (retVal != null && retVal.isEmpty()) {
commit();
} else {
rollback();
}
}
}
return retVal;
}
/**
* Persists ${object.@name} only. Ignores the children. Does not perform business rule
* violation checking. So, know what you are doing when using this.
* @param pojo Object you'd wish persisted
* @return Empty when OK, or filled with unique key violation.
*/
@NotNull
public Set soloPersist(@NotNull ${object.@name} pojo) throws RedoraException {
Set retVal = new HashSet();
if (!pojo.dirty.isEmpty() || pojo.isNew) {
String SQL;
if (pojo.isNew) {
pojo.dirty.put(${object.@name}Fields.creationDate, null);
pojo.creationDate = new Date((new Date().getTime()/1000)*1000); //Strip nanoseconds, they are not persisted in MySQL
StringBuilder sqlInsert = new StringBuilder("insert into `${object.@name}` (");
char comma = ' ';
for (${object.@name}Fields field : pojo.dirty.keySet()) {
sqlInsert.append(comma);
sqlInsert.append(field.name());
comma = ',';
}
sqlInsert.append(") values (");
comma = ' ';
for (int i = 0; i < pojo.dirty.size(); i++) {
sqlInsert.append(comma);
sqlInsert.append('?');
comma = ',';
}
sqlInsert.append(')');
SQL = sqlInsert.toString();
} else {
pojo.dirty.put(${object.@name}Fields.updateDate, pojo.updateDate);
pojo.updateDate = new Date((new Date().getTime()/1000)*1000); //Strip nanoseconds, they are not persisted in MySQL
StringBuilder sqlUpdate = new StringBuilder("update `${object.@name}` set ");
char comma = ' ';
for (${object.@name}Fields field : pojo.dirty.keySet()) {
sqlUpdate.append(comma);
sqlUpdate.append(field.name()).append("=?");
comma = ',';
}
sqlUpdate.append(" where id=?");
SQL = sqlUpdate.toString();
}
<#if stream == "true">
boolean usePreparedStatement = false;
//Determine if there is a streaming parameter. If yes, use PreparedStatement.
for (${object.@name}Fields field : pojo.dirty.keySet()) {
<#list doc["/object/attributes/*"] as att>
<#if att?node_name == "html">
if (field == ${object.@name}Fields.${att.@fieldName}) {
usePreparedStatement = true;
break;
}
<#elseif att?node_name == "string" && att.@maxlength[0]?number > 65000>
if (field == ${object.@name}Fields.${att.@fieldName}) {
usePreparedStatement = true;
break;
}
}
<#if stream == "true">
PreparedStatement ps = null;
int position = 1;
if (usePreparedStatement) {
try {
ps = st.con.con.prepareStatement(SQL, java.sql.Statement.RETURN_GENERATED_KEYS);
for (${object.@name}Fields field : pojo.dirty.keySet()) {
switch (field) {
case updateDate:
ps.setTimestamp(position++, new Timestamp(pojo.updateDate.getTime()));
break;
case creationDate:
ps.setTimestamp(position++, new Timestamp(pojo.creationDate.getTime()));
break;
<#list object.attributes?children as att>
<#if att?node_name != "set" && att?node_name != "object" && att?node_type == "element">
case ${att.@fieldName}:
<#if att.@notnull == "false">
if (pojo.${att.@fieldName} == null) {
ps.setNull(position++, ${object.@name}Fields.${att.@fieldName}.sqlType);
} else {
<#if att?node_name="boolean">
ps.setBoolean(position++, pojo.${att.@fieldName}.booleanValue());
<#elseif att?node_name == "date">
ps.setDate(position++, new java.sql.Date(pojo.${att.@fieldName}.getTime()));
<#elseif att?node_name == "datetime">
ps.setTimestamp(position++, new Timestamp(pojo.${att.@fieldName}.getTime()));
<#elseif att?node_name == "enum">
ps.setString(position++, pojo.${att.@fieldName}.name());
<#elseif att?node_name == "integer">
ps.setInt(position++, pojo.${att.@fieldName});
<#elseif att?node_name == "long">
ps.setLong(position++, pojo.${att.@fieldName});
<#elseif att?node_name == "double">
ps.setDouble(position++, pojo.${att.@fieldName});
<#elseif att?node_name == "string" || att?node_name == "html">
<#if att?node_name == "html" || att.@maxlength[0]?number > 65000>
ps.setBinaryStream(position++, org.apache.commons.io.IOUtils.toInputStream(pojo.${att.@fieldName},"UTF-8"));
<#else>
ps.setString(position++, pojo.${att.@fieldName});
<#else>
ERROR undefined type ${att?node_name}
<#if att.@notnull == "false">
}
break;
} //end switch
}
} catch (SQLException e) {
l.log(SEVERE, "Did not set field at position: " + position + " - " + SQL, e);
try {if (ps != null) ps.close();} catch (SQLException esql) {}
throw new PersistException("Did not set field at position: " + position + " - " + SQL, e);
} catch (IOException e) {
l.log(SEVERE, "Can't stream field at position: " + position + " - " + SQL, e);
try {if (ps != null) ps.close();} catch (SQLException esql) {}
throw new PersistException("Can't stream field at position: " + position + " - " + SQL, e);
}
} else {
for (${object.@name}Fields field : pojo.dirty.keySet()) {
switch (field) {
case updateDate:
SQL = prepareTime(SQL, pojo.updateDate);
break;
case creationDate:
SQL = prepareTime(SQL, pojo.creationDate);
break;
<#list object.attributes?children as att>
<#if att?node_name != "set" && att?node_name != "object" && att?node_type == "element" && (att?node_name != "string" || att.@maxlength[0]?number < 65001)>
case ${att.@fieldName}:
<#if att.@notnull == "false">
if (pojo.${att.@fieldName} == null) {
SQL = prepareNull(SQL);
} else {
<#if att?node_name="boolean" || att?node_name == "integer" || att?node_name == "long" || att?node_name == "date" || att?node_name == "double">
SQL = prepare(SQL, pojo.${att.@fieldName});
<#elseif att?node_name == "datetime">
SQL = prepareTime(SQL, pojo.${att.@fieldName});
<#elseif att?node_name == "enum">
SQL = prepare(SQL, pojo.${att.@fieldName}.name());
<#elseif att?node_name == "string">
SQL = prepareDirty(SQL, pojo.${att.@fieldName});
<#if att.@notnull == "false">
}
break;
} //switch
}
<#if stream == "true">
}
ResultSet rs = null;
try {
<#if stream == "true">
if (usePreparedStatement) {
if (!pojo.isNew) {
ps.setLong(position, pojo.getId()); //sets where id = ?
}
ps.execute();
if (ps.getWarnings() != null) {
throw new PersistException("${object.@name} was not persisted " + ps.getWarnings().getMessage());
}
if (pojo.isNew) {
rs = ps.getGeneratedKeys();
rs.next();
pojo.id = rs.getLong(1);
}
} else {
if (pojo.isNew) {
st.st.execute(SQL, java.sql.Statement.RETURN_GENERATED_KEYS);
if (st.st.getWarnings() != null) {
throw new PersistException("${object.@name} was not persisted " + st.st.getWarnings().getMessage());
}
rs = st.st.getGeneratedKeys();
rs.next();
pojo.id = rs.getLong(1);
} else {
SQL = prepare(SQL, pojo.getId());
execute(SQL);
}
<#if stream == "true">
}
pojo.dirty.clear();
pojo.isNew = false;
} catch (MySQLIntegrityConstraintViolationException e) {
int start = e.toString().indexOf("for key '");
if (start > 0) {
String indexName = e.toString().substring(start + 9);
indexName = indexName.substring(0, indexName.indexOf("'"));
retVal.add(new BusinessRuleViolation(
pojo, ${object.@name}Fields.valueOf(uniqueKeyAttribute("${object.@name}", indexName)), BusinessRuleViolation.StandardRule.UniqueKey.ruleId, pojo.getId() == null?BusinessRuleViolation.Action.Insert:BusinessRuleViolation.Action.Update)
);
} else {
retVal.add(new BusinessRuleViolation(
pojo, null, BusinessRuleViolation.StandardRule.UniqueKey.ruleId, pojo.getId() == null?BusinessRuleViolation.Action.Insert:BusinessRuleViolation.Action.Update)
);
}
} catch(SQLException e) {
l.log(SEVERE, "Failed to perform persist: " + SQL, e);
throw new PersistException("Failed to perform persist: " + SQL, e);
} finally {
close(rs);
<#if stream == "true">
try {if (ps != null) ps.close();} catch (SQLException esql) {}
}
}
return retVal;
}
<#if doc["/object/attributes/set"][0]??>
/**
* Goes through dirty children and parents, and persists them. Use only when
* you know what you are doing.
* @param pojo (Mandatory) Object from whom you wish to save the children
* @return Empty when OK, or filled with unique key constraints violations
*/
@NotNull
public Set familyPersist(@NotNull ${object.@name} pojo, boolean wasNew, boolean asBatch)
throws RedoraException {
Set retVal = new HashSet();
<#list object.attributes.set as att>
// ${att.@plural?cap_first} (${att.@multiplicity}) actions, sorted: ${att.@sorted}
<#if att.@multiplicity == "n-to-m">
if (pojo.${att.@fieldName}IsRetrieved()) {
if (!wasNew) {
for (${att.@class} delete : pojo.get${att.@plural?cap_first}().getRemovedObjects()) {
deleteRelationWith${att.@class}(pojo.getId(), delete.getId(), asBatch);
}
}
<#if att.@sorted == "both" || att.@sorted == "them">
int sort = 0;
for (${att.@class} list : pojo.get${att.@fieldName?cap_first}()) {
if (list.isNew || list.isDirty()) {
retVal.addAll(<#if att.@class != object.@name>new ${att.@class}Service(this).persist(list, asBatch));
}
if (pojo.get${att.@fieldName?cap_first}().getAddedObjects().contains(list)) {
<#if att.@sorted == "both" || att.@sorted == "them">
connectTo${att.@class}(pojo.getId(), list.getId(), sort, asBatch);
<#else>
connectTo${att.@class}(pojo.getId(), list.getId(), asBatch);
<#if att.@sorted == "both" || att.@sorted == "them">
} else if (pojo.get${att.@fieldName?cap_first}().hasShuffled()) {
reconnectTo${att.@class}(pojo.getId(), list.getId(), sort);
}
<#if att.@sorted == "both" || att.@sorted == "them">
sort++;
}
pojo.get${att.@plural?cap_first}().reset();
}
<#else>
<#assign finderName = att.@myName>
<#if att.@class == object.@name>
//pigs ear
<#assign finderName = att.@theirName>
if (pojo.${att.@fieldName}IsRetrieved()) {
if (!wasNew && !pojo.get${att.@fieldName?cap_first}().getRemovedObjects().isEmpty()) {
for (${att.@class} delete : pojo.get${att.@plural?cap_first}().getRemovedObjects()) {
<#if att.@class != object.@name>new ${att.@class}Service(this).delete(delete);
}
}
if (pojo.get${att.@plural?cap_first}().isDirty(new HashSet())) {
List<${att.@class}> update${att.@plural?cap_first} = new ArrayList<${att.@class}>();
for (${att.@class} child : pojo.get${att.@plural?cap_first}()) {
if (child.isDirty()) {
update${att.@plural?cap_first}.add(child);
child.set${finderName?cap_first}(pojo);
}
}
for (${att.@class} child : pojo.get${att.@plural?cap_first}().getAddedObjects()) {
if (!child.isDirty()) { //Dirty is already added before
update${att.@plural?cap_first}.add(child);
child.set${finderName?cap_first}(pojo);
}
}
if (!update${att.@plural?cap_first}.isEmpty()) {
retVal.addAll(<#if att.@class != object.@name>new ${att.@class}Service(this).persist(update${att.@plural?cap_first}));
}
pojo.get${att.@plural?cap_first}().reset();
}
}
return retVal;
}
/**
* Deletes ${object.@name}.
* Collections associated to ${object.@name} are deleted as well when cascade delete is indicated.
* @param pojo (Mandatory) ${object.@name} you want to delete.
* @return Empty when OK, or filled set with violated business rules
* @throws ObjectNotFoundException when ${object.@name} has no id (was never persisted).
*/
@NotNull
public Set delete(@NotNull ${object.@name} pojo) throws RedoraException {
if (pojo.getId() == null) {
throw new ObjectNotFoundException("You are trying to delete a ${object.@name} that is not in the database");
}
Set br = check(pojo, BusinessRuleViolation.Action.Delete);
if (br.isEmpty()) {
delete(pojo, false);
}
return br;
}
/** Deletes ${object.@name} without checking on business rule violations. */
protected void delete(${object.@name} pojo, boolean asBatch) throws QueryException {
l.log(FINE, "Deleting {0}", pojo.getId());
String SQL = prepare(DELETE, pojo.getId());
execute(SQL);
}
<#if object.trashcan == "true">
/**
* Finds trashed ${object.@name}s.
* @param ${object.@name?uncap_first}Id (Optional) if set only a specific trashed object is retrieved.
* @return Empty or filled list with results
*/
@NotNull
public List<${object.@name}> findTrash(@Nullable Long ${object.@name?uncap_first}Id)
throws QueryException, CopyException {
List<${object.@name}> retVal = new ArrayList<${object.@name}>();
String SQL = ${object.@name?uncap_first}Id == null ? FIND_TRASH : FIND_TRASH_BY_ID;
if (${object.@name?uncap_first}Id != null) {
SQL = prepare(SQL, ${object.@name?uncap_first}Id);
}
ResultSet rs = null;
try {
rs = sqlQuery(SQL);
while (rs.next()) {
retVal.add(new ${object.@name}(rs, 0, ${object.@name?uncap_first}Id == null ? Scope.Table : Scope.Form));
}
} catch(SQLException e) {
l.log(SEVERE, "Failed to find trash " + SQL, e);
throw new QueryException("Failed to find trash " + SQL, e);
} finally {
close(rs);
}
return retVal;
}
/**
* Trashes ${object.@name}.
* Collections associated to ${object.@name} are trashed as well when cascade delete is indicated.
* @param undoHash (Optional) When provided, ${object.@name} will be tashed with given hash, otherwise a new hash will be calculated and returned.
* @param pojo (Mandatory) The ${object.@name} you want to trash.
* @return Empty when OK, or set with violated business rules.
* @throws ObjectNotFoundException When ${object.@name} was not persisted.
*/
@NotNull
public Set trash(@Nullable String undoHash, @NotNull ${object.@name} pojo) throws RedoraException {
if (pojo.getId() == null) {
throw new ObjectNotFoundException("You are trying to delete a ${object.@name} that is not in the database");
}
Set br = check(pojo, BusinessRuleViolation.Action.Delete);
if (br.isEmpty()) {
TrashService.trash(undoHash, pojo.getId(), "${object.@name}");
trash(pojo, false, false);
}
return br;
}
/**
* Restores a trashed ${object.@name} and also restored possible trashed children.
* @param ${object.@name?uncap_first}Id (Mandatory) Id of to be retrieved object
* @throws QueryException When ${object.@name} was not found (or was untrashed before).
*/
public void undo(Long ${object.@name?uncap_first}Id) throws RedoraException {
List<${object.@name}> trash = findTrash(${object.@name?uncap_first}Id);
if (trash.isEmpty()) {
throw new QueryException("Could not find trashed ${object.@name}, maybe it was already undeleted.");
}
trash(trash.get(0), false, true);
TrashService.deleteTrash(trash.get(0).getId(), "${object.@name}");
}
/** Trashes ${object.@name} without checking on business rule violations. */
private void trash(${object.@name} pojo, boolean asBatch, boolean undo) throws RedoraException {
l.log(FINE, "Trashing {0}", pojo.getId());
String SQL = prepare(TRASH, !undo);
SQL = prepare(SQL, pojo.getId());
execute(SQL);
<#list object.attributes.set as att>
<#if att.@multiplicity == "n-to-m">
if (undo || !pojo.get${att.@plural?cap_first}().isEmpty()) {
//trashAllRelationsWith${att.@class}(pojo.getId(), undo, asBatch);
}
<#elseif att.@cascade == "true">
<#assign finderName = att.@myName>
<#if att.@class == object.@name>
<#assign finderName = att.@theirName>
if (undo || !pojo.get${att.@plural?cap_first}().isEmpty()) {
<#if att.@class != object.@name>new ${att.@class}Service(this).trashBy${finderName?cap_first}Id(pojo.getId(), undo, asBatch);
}
}
/**
* Simple test method. It will dump the results of findAll to System.out
* @param args Unused
* @throws RedoraException Passing on
*/
public static void main(String[] args) throws RedoraException {
${object.@name}Service _${object.@name?uncap_first}Service = ServiceFactory.${object.@name?uncap_first}Service();
for (${object.@name} testRecord : _${object.@name?uncap_first}Service.findAll(new Page(Scope.Table, Mode.Page, 100))) {
<#list object.tableScope?children as att>
<#if att?node_name != "object" && att?node_type == "element">
if (testRecord.${att.@fieldName} != null) {
System.out.print(testRecord.${att.@fieldName});
} else {
System.out.print("NULL");
}
System.out.print("-");
System.out.println();
}
ServiceFactory.close(_${object.@name?uncap_first}Service);
}
}