/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.amber.gen;
import com.caucho.VersionFactory;
import com.caucho.amber.field.*;
import com.caucho.amber.table.AmberColumn;
import com.caucho.amber.table.AmberTable;
import com.caucho.amber.type.EntityType;
import com.caucho.amber.type.MappedSuperclassType;
import com.caucho.amber.type.EntityType;
import com.caucho.bytecode.*;
import com.caucho.java.JavaWriter;
import com.caucho.java.gen.ClassComponent;
import com.caucho.loader.Environment;
import com.caucho.util.L10N;
import com.caucho.vfs.PersistentDependency;
import javax.persistence.CascadeType;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
/**
* Generates the Java code for the wrapped object.
*/
abstract public class AmberMappedComponent extends ClassComponent {
private static final L10N L = new L10N(AmberMappedComponent.class);
String _baseClassName;
String _extClassName;
EntityType _entityType;
private ArrayList<PersistentDependency> _dependencies
= new ArrayList<PersistentDependency>();
public AmberMappedComponent()
{
}
/**
* Sets the bean info for the generator
*/
void setRelatedType(EntityType entityType)
{
_entityType = entityType;
_dependencies.addAll(entityType.getDependencies());
for (int i = 0; i < _dependencies.size(); i++)
Environment.addDependency(_dependencies.get(i));
}
public EntityType getEntityType()
{
return _entityType;
}
/**
* Sets the base class name
*/
public void setBaseClassName(String baseClassName)
{
_baseClassName = baseClassName;
}
/**
* Gets the base class name
*/
public String getBaseClassName()
{
return _baseClassName;
}
/**
* Sets the ext class name
*/
public void setExtClassName(String extClassName)
{
_extClassName = extClassName;
}
/**
* Sets the ext class name
*/
public String getClassName()
{
return _extClassName;
}
/**
* Get bean class name.
*/
public String getBeanClassName()
{
// return _entityType.getBeanClass().getName();
return _baseClassName;
}
/**
* Returns the dependencies.
*/
public ArrayList<PersistentDependency> getDependencies()
{
return _dependencies;
}
protected boolean isEntityParent()
{
EntityType parentType = getEntityType().getParentType();
// jpa/0gg0
return ((parentType != null) && parentType.isEntity());
}
/**
* Starts generation of the Java code
*/
@Override
public final void generate(JavaWriter out)
throws IOException
{
try {
EntityType parentType = getEntityType().getParentType();
generateHeader(out, isEntityParent());
generateInit(out);
HashSet<Object> completedSet = new HashSet<Object>();
generatePrologue(out, completedSet);
generateGetCacheEntity(out);
generateGetEntityType(out);
if (! isEntityParent())
generateGetEntityState(out);
generateIsLoaded(out);
generateIsDirty(out);
generateMatch(out);
generateFields(out);
generateMethods(out);
generateDetach(out, isEntityParent());
generateLoad(out, isEntityParent());
int min = 0;
if (isEntityParent())
min = getEntityType().getParentType().getLoadGroupIndex() + 1;
int max = getEntityType().getLoadGroupIndex();
for (int i = min; i <= max; i++)
generateLoadGroup(out, i);
generateResultSetLoad(out, isEntityParent());
generateSetQuery(out, isEntityParent());
generateMerge(out);
generateSetLoadMask(out);
generateMakePersistent(out);
generateCascadePersist(out);
generateCascadeRemove(out);
generateCreate(out);
generateDelete(out);
generateDeleteForeign(out);
generateFlush(out);
generateIncrementVersion(out);
generateAfterCommit(out, isEntityParent());
generateAfterRollback(out);
generateLoadKey(out);
generateHome(out);
// printDependList(out, _dependencies);
} catch (IOException e) {
throw e;
}
}
/**
* Generates the class header for the generated code.
*/
void generateHeader(JavaWriter out,
boolean isEntityParent)
throws IOException
{
out.println("/*");
out.println(" * Generated by Resin Amber");
out.println(" * " + VersionFactory.getVersion());
out.println(" */");
out.print("private static final java.util.logging.Logger __caucho_log = ");
out.println("java.util.logging.Logger.getLogger(\"" + getBeanClassName() + "\");");
// jpa/0ge3 if (! isEntityParent) {
if (_entityType.getParentType() == null) {
out.println();
out.println("protected transient com.caucho.amber.type.EntityType __caucho_home;");
out.println("public transient com.caucho.amber.entity.EntityItem __caucho_cacheItem;");
out.println("protected transient com.caucho.amber.manager.AmberConnection __caucho_session;");
out.println("protected transient com.caucho.amber.entity.EntityState __caucho_state = com.caucho.amber.entity.EntityState.TRANSIENT;");
// XXX: needs to generate load masks for groups in the subclasses,
// but the group numbering should not always start at zero.
int loadCount = _entityType.getLoadGroupIndex();
for (int i = 0; i <= loadCount / 64; i++) {
out.println("protected transient long __caucho_loadMask_" + i + ";");
}
int dirtyCount = _entityType.getDirtyIndex();
for (int i = 0; i <= dirtyCount / 64; i++) {
out.println("protected transient long __caucho_dirtyMask_" + i + ";");
out.println("protected transient long __caucho_updateMask_" + i + ";");
}
out.println("protected transient boolean __caucho_inc_version;");
}
}
/**
* Generates the init generated code.
*/
void generateInit(JavaWriter out)
throws IOException
{
if (isEntityParent())
return;
String className = getClassName();
int p = className.lastIndexOf('.');
if (p > 0)
className = className.substring(p + 1);
ArrayList<AmberField> fields = _entityType.getFields();
Class beanClass = _entityType.getBeanClass();
for (Constructor ctor : beanClass.getDeclaredConstructors()) {
out.println();
// XXX: s/b actual access type?
out.print("public ");
out.print(className);
out.print("(");
Class []args = ctor.getParameterTypes();
for (int i = 0; i < args.length; i++) {
if (i != 0)
out.print(", ");
out.printClass(args[i]);
out.print(" a" + i);
}
out.println(")");
out.println("{");
out.pushDepth();
out.print("super(");
for (int i = 0; i < args.length; i++) {
if (i != 0)
out.print(", ");
out.print("a" + i);
}
out.println(");");
// jpa/0l14
out.println("__caucho_state = com.caucho.amber.entity.EntityState.TRANSIENT;");
// jpa/0gh2: compound pk and constructor with arguments.
if (_entityType.getId() instanceof CompositeId) {
out.println("try {");
out.println(" __caucho_setPrimaryKey(__caucho_getPrimaryKey());");
out.println("} catch (Exception e) {");
out.println(" __caucho_log.fine(\"amber unable to set primary key within argument constructor \" + this.getClass().getName() + \"[PK: unknown]\");");
out.println("}");
}
for (AmberField field : fields) {
field.generatePostConstructor(out);
}
out.popDepth();
out.println("}");
}
Id id = _entityType.getId();
if (id == null && _entityType.isEntity())
throw new IllegalStateException(L.l("'{0}' is missing a key.",
_entityType.getName()));
boolean isAbstract
= Modifier.isAbstract(_entityType.getBeanClass().getModifiers());
out.println();
out.println("public void __caucho_setPrimaryKey(Object key)");
out.println("{");
out.pushDepth();
if (id != null && ! isAbstract)
id.generateSet(out, "super", id.generateCastFromObject("key"));
out.popDepth();
out.println("}");
out.println();
out.println("public Object __caucho_getPrimaryKey()");
out.println("{");
out.pushDepth();
out.println("try {");
out.pushDepth();
out.print("return ");
if (id == null || isAbstract)
out.print("null");
else
out.print(id.toObject(id.generateGet("super")));
out.println(";");
out.popDepth();
out.println("} catch (Exception e) {");
out.println(" throw new com.caucho.amber.AmberRuntimeException(e);");
out.println("}");
out.popDepth();
out.println("}");
out.println();
out.println("public void __caucho_setConnection(com.caucho.amber.manager.AmberConnection aConn)");
out.println("{");
out.println(" __caucho_session = aConn;");
out.println("}");
out.println();
out.println("public com.caucho.amber.manager.AmberConnection __caucho_getConnection()");
out.println("{");
out.println(" return __caucho_session;");
out.println("}");
generateExpire(out);
}
/**
* Generates the expire code.
*/
void generateExpire(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_expire()");
out.println("{");
out.pushDepth();
generateLogFine(out, " amber expire");
out.println();
int loadCount = _entityType.getLoadGroupIndex();
for (int i = 0; i <= loadCount / 64; i++) {
out.println("__caucho_loadMask_" + i + " = 0L;");
}
_entityType.generateExpire(out);
out.popDepth();
out.println("}");
}
/**
* Generates the isDirty code.
*/
void generateIsDirty(JavaWriter out)
throws IOException
{
out.println();
out.println("public boolean __caucho_isDirty()");
out.println("{");
out.pushDepth();
int dirtyCount = _entityType.getDirtyIndex();
for (int i = 0; i <= dirtyCount / 64; i++) {
out.println("if (__caucho_dirtyMask_" + i + " != 0L)");
out.println(" return true;");
out.println();
}
out.println("return false;");
out.popDepth();
out.println("}");
}
/**
* Generates the isLoaded code.
*/
void generateIsLoaded(JavaWriter out)
throws IOException
{
out.println();
out.println("public boolean __caucho_isLoaded()");
out.println("{");
out.pushDepth();
out.println("return __caucho_loadMask_0 != 0L;");
out.popDepth();
out.println("}");
}
/**
* Generates the match code.
*/
void generateMatch(JavaWriter out)
throws IOException
{
out.println();
out.println("public boolean __caucho_match(Class cl, Object key)");
out.println("{");
out.pushDepth();
/*
out.println("if (! (" + getBeanClassName() + ".class.isAssignableFrom(cl)))");
out.println(" return false;");
*/
out.println("if (" + getBeanClassName() + ".class != cl)");
out.println(" return false;");
out.println("else {");
out.pushDepth();
Id id = _entityType.getId();
// jpa/0gg0
if (id == null || Modifier.isAbstract(_entityType.getBeanClass().getModifiers())) {
// jpa/0ge6: MappedSuperclass
out.println("return true;");
out.popDepth();
out.println("}");
out.popDepth();
out.println("}");
return;
}
out.println("try {");
out.pushDepth();
id.generateMatch(out, id.generateCastFromObject("key"));
out.popDepth();
out.println("} catch (ClassCastException e) {");
out.println(" throw new IllegalArgumentException(\"Primary key type is incorrect: '\"+key.getClass().getName()+\"'\");");
out.println("}");
out.popDepth();
out.println("}");
out.popDepth();
out.println("}");
}
/**
* Generates the prologue.
*/
void generatePrologue(JavaWriter out, HashSet<Object> completedSet)
throws IOException
{
if (_entityType.getColumns() != null) {
for (AmberColumn column : _entityType.getColumns())
column.generatePrologue(out);
}
Id id = _entityType.getId();
boolean isAbstractParent
= (_entityType.getParentType() == null
|| ! _entityType.getParentType().isEntity());
// jpa/0m02
if (id != null) // && isAbstractParent)
id.generatePrologue(out, completedSet);
ArrayList<AmberField> fields = _entityType.getFields();
for (int i = 0; i < fields.size(); i++) {
AmberField prop = fields.get(i);
prop.generatePrologue(out, completedSet);
}
}
/**
* Generates the __caucho_getCacheEntity()
*/
void generateGetCacheEntity(JavaWriter out)
throws IOException
{
out.println();
out.println("public com.caucho.amber.entity.Entity __caucho_getCacheEntity()");
out.println("{");
out.pushDepth();
out.println("if (__caucho_cacheItem != null)");
out.println(" return __caucho_cacheItem.getEntity();");
out.println("else");
out.println(" return null;");
out.popDepth();
out.println("}");
out.println();
out.println("public com.caucho.amber.entity.EntityItem __caucho_getCacheItem()");
out.println("{");
out.pushDepth();
out.println("return __caucho_cacheItem;");
out.popDepth();
out.println("}");
out.println();
out.println("public void __caucho_setCacheItem(com.caucho.amber.entity.EntityItem cacheItem)");
out.println("{");
out.pushDepth();
out.println("__caucho_cacheItem = cacheItem;");
out.popDepth();
out.println("}");
}
/**
* Generates the entity type
*/
void generateGetEntityType(JavaWriter out)
throws IOException
{
out.println();
out.println("public com.caucho.amber.type.EntityType __caucho_getEntityType()");
out.println("{");
out.pushDepth();
out.println("return __caucho_home;");
out.popDepth();
out.println("}");
}
/**
* Generates the get entity state
*/
void generateGetEntityState(JavaWriter out)
throws IOException
{
out.println();
out.println("public com.caucho.amber.entity.EntityState __caucho_getEntityState()");
out.println("{");
out.pushDepth();
out.println("return __caucho_state;");
out.popDepth();
out.println("}");
out.println();
out.println("public void __caucho_setEntityState(com.caucho.amber.entity.EntityState state)");
out.println("{");
out.pushDepth();
out.println("__caucho_state = state;");
out.popDepth();
out.println("}");
}
/**
* Generates the fields.
*/
void generateFields(JavaWriter out)
throws IOException
{
if (_entityType.getId() != null) {
for (AmberField key : _entityType.getId().getKeys()) {
if (_entityType == key.getSourceType()) {
key.generateSuperGetterMethod(out);
key.generateSuperSetterMethod(out);
}
}
}
for (AmberField prop : _entityType.getFields()) {
if (_entityType == prop.getSourceType()) {
prop.generateSuperGetterMethod(out);
prop.generateSuperSetterMethod(out);
if (! (prop instanceof IdField)) {
prop.generateGetterMethod(out);
prop.generateSetterMethod(out);
}
}
}
}
/**
* Generates the stub methods (needed for EJB)
*/
void generateMethods(JavaWriter out)
throws IOException
{
for (StubMethod method : _entityType.getMethods()) {
method.generate(out);
}
}
/**
* Generates the load
*/
void generateLoad(JavaWriter out,
boolean isEntityParent)
throws IOException
{
// commented out: jpa/0l03
// if (_entityType.getParentType() != null)
// return;
if (! isEntityParent) {
out.println();
out.println("public boolean __caucho_makePersistent(com.caucho.amber.manager.AmberConnection aConn, com.caucho.amber.type.EntityType home)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
out.println("__caucho_session = aConn;");
out.println("if (home != null)");
out.println(" __caucho_home = home;");
// XXX: makePersistent is called in contexts other than the P_NON_TRANSACTIONAL one, so this setting is inappropriate
// out.println("__caucho_state = com.caucho.amber.entity.EntityState.P_NON_TRANSACTIONAL;");
int loadCount = _entityType.getLoadGroupIndex();
for (int i = 0; i <= loadCount / 64; i++) {
out.println("__caucho_loadMask_" + i + " = 0L;");
}
int dirtyCount = _entityType.getDirtyIndex();
for (int i = 0; i <= dirtyCount / 64; i++) {
out.println("__caucho_dirtyMask_" + i + " = 0L;");
out.println("__caucho_updateMask_" + i + " = 0L;");
}
out.println();
out.println("return true;");
out.popDepth();
out.println("}");
}
int index = _entityType.getLoadGroupIndex();
boolean hasLoad = (_entityType.getFields().size() > 0);
if (! isEntityParent) {
index = 0;
hasLoad = hasLoad || (_entityType.getId() != null);
}
// jpa/0l20
if (true || hasLoad || ! isEntityParent) {
out.println();
out.println("public void __caucho_retrieve_eager(com.caucho.amber.manager.AmberConnection aConn)");
out.println("{");
out.pushDepth();
generateRetrieveEager(out, _entityType);
out.popDepth();
out.println("}");
out.println();
out.println("public void __caucho_retrieve_self(com.caucho.amber.manager.AmberConnection aConn)");
out.println("{");
out.pushDepth();
generateRetrieveSelf(out, _entityType);
out.popDepth();
out.println("}");
}
}
private void generateRetrieveEager(JavaWriter out, EntityType entityType)
throws IOException
{
if (entityType == null || ! entityType.isEntity())
return;
int index = entityType.getLoadGroupIndex();
boolean hasLoad = (entityType.getFields().size() > 0);
EntityType parentType = entityType.getParentType();
if (parentType == null || ! parentType.isEntity()) {
index = 0;
hasLoad = true;
}
generateRetrieveEager(out, parentType);
if (hasLoad)
out.println("__caucho_load_" + index + "(aConn);");
}
private void generateRetrieveSelf(JavaWriter out, EntityType entityType)
throws IOException
{
if (entityType == null || ! entityType.isEntity())
return;
int index = entityType.getLoadGroupIndex();
boolean hasLoad = (entityType.getFields().size() > 0);
EntityType parentType = entityType.getParentType();
if (parentType != null && parentType.isEntity()) {
generateRetrieveSelf(out, parentType);
}
else {
index = 0;
hasLoad = true;
}
if (hasLoad) {
int group = index / 64;
long mask = (1L << (index % 64));
out.println("if ((__caucho_loadMask_" + group + " & " + mask + "L) == 0)");
out.println(" __caucho_load_select_" + index + "(aConn);");
}
}
/**
* Generates the detach
*/
void generateDetach(JavaWriter out,
boolean isEntityParent)
throws IOException
{
if (isEntityParent)
return;
out.println();
out.println("public void __caucho_detach()");
out.println("{");
out.pushDepth();
generateLogFinest(out, " amber detach");
out.println();
out.println("__caucho_session = null;");
for (AmberField field : _entityType.getFields())
field.generateDetach(out);
// jpa/0x00
// out.println("__caucho_home = null;");
out.println("__caucho_state = com.caucho.amber.entity.EntityState.TRANSIENT;");
out.popDepth();
out.println("}");
}
/**
* Generates the load group.
*/
void generateLoadGroup(JavaWriter out, int groupIndex)
throws IOException
{
if (_entityType.hasLoadGroup(groupIndex)) {
new LoadGroupGenerator(_extClassName,
_entityType,
groupIndex).generate(out);
}
}
/**
* Generates the load
*/
void generateResultSetLoad(JavaWriter out,
boolean isEntityParent)
throws IOException
{
if (isEntityParent)
return;
out.println();
out.println("public int __caucho_load(com.caucho.amber.manager.AmberConnection aConn, java.sql.ResultSet rs, int index)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
int index = _entityType.generateLoad(out, "rs", "index", 0, 0);
out.println("__caucho_loadMask_0 |= 1L;");
int dirtyCount = _entityType.getDirtyIndex();
for (int i = 0; i <= dirtyCount / 64; i++) {
out.println("__caucho_dirtyMask_" + i + " = 0;");
// ejb/0645
// out.println("__caucho_updateMask_" + i + " = 0;");
}
out.println();
/* jpa/0g43 - XA doesn't have a cache item
out.println("if (__caucho_cacheItem == null) {");
// the cache item does not have its state changed
out.println("}");
out.println("else ");
*/
out.println("if (__caucho_state.isTransactional()) {");
out.println("}");
out.println("else if (__caucho_session == null");
out.println(" || ! __caucho_session.isActiveTransaction()) {");
out.println(" __caucho_state = com.caucho.amber.entity.EntityState.P_NON_TRANSACTIONAL;");
out.println(" if (__caucho_cacheItem != null)");
out.println(" __caucho_cacheItem.save((com.caucho.amber.entity.Entity) this);");
out.println("}");
out.println("else {");
out.println(" __caucho_state = com.caucho.amber.entity.EntityState.P_TRANSACTIONAL;");
out.println("}");
if (_entityType.getHasLoadCallback()) {
out.println();
out.println("__caucho_load_callback();");
}
out.println("return " + index + ";");
out.popDepth();
out.println("}");
}
/**
* Generates the load
*/
void generateSetQuery(JavaWriter out,
boolean isEntityParent)
throws IOException
{
if (isEntityParent)
return;
out.println();
out.println("public void __caucho_setKey(java.sql.PreparedStatement pstmt, int index)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
// jpa/0gg0 vs jpa/06c5
if (! _entityType.isAbstractClass())
_entityType.generateSet(out, "pstmt", "index", "super");
out.popDepth();
out.println("}");
}
/**
* Generates the increment version
*/
void generateIncrementVersion(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_increment_version()");
out.println("{");
out.pushDepth();
VersionField version = _entityType.getVersionField();
if (version != null) {
out.println("if (__caucho_inc_version)");
out.println(" return;");
out.println();
out.println("__caucho_inc_version = true;");
version.generateIncrementVersion(out);
}
out.popDepth();
out.println("}");
}
/**
* Generates the flush
*/
void generateFlush(JavaWriter out)
throws IOException
{
}
/**
* Generates the update
*/
void generateFlushUpdate(JavaWriter out,
boolean isEntityParent)
throws IOException
{
out.println();
out.println("protected void __caucho_flushUpdate(long mask, com.caucho.amber.type.EntityType home)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
if (isEntityParent) {
out.println("super.__caucho_flushUpdate(mask, home.getParentType());");
}
out.println("String sql = home.generateUpdateSQL(mask);");
out.println("if (sql != null) {");
out.pushDepth();
out.println("java.sql.PreparedStatement pstmt = __caucho_session.prepareStatement(sql);");
out.println("int index = 1;");
ArrayList<AmberField> fields = _entityType.getFields();
for (int i = 0; i < fields.size(); i++) {
AmberField field = fields.get(i);
field.generateUpdate(out, "mask", "pstmt", "index");
}
out.println();
_entityType.getId().generateSet(out, "pstmt", "index");
out.println();
out.println("pstmt.executeUpdate();");
out.println();
generateLogFine(out, " amber update");
// println();
// println("pstmt.close();");
out.popDepth();
out.println("}");
out.popDepth();
out.println("}");
}
/**
* Generates the after-commit
*/
void generateAfterCommit(JavaWriter out,
boolean isEntityParent)
throws IOException
{
// XXX: needs to handle this with subclasses
// but there is an issue in the enhancer fixup
// removing the "super." call.
// if (_entityType.getParentType() != null) {
// out.println();
// out.println("public void __caucho_super_afterCommit()");
// out.println("{");
// out.println(" super.__caucho_afterCommit();");
// out.println("}");
// }
out.println();
out.println("public void __caucho_afterCommit()");
out.println("{");
out.pushDepth();
// ejb/06c9
out.println("com.caucho.amber.entity.EntityState state = __caucho_state;");
out.println();
out.println("__caucho_state = com.caucho.amber.entity.EntityState.P_NON_TRANSACTIONAL;");
out.println();
out.println("if (__caucho_session == null) {");
int dirtyCount = _entityType.getDirtyIndex();
for (int i = 0; i <= dirtyCount / 64; i++) {
out.println(" __caucho_updateMask_" + i + " = 0L;");
}
out.println(" return;");
out.println("}");
out.println();
// jpa/0h20, jpa/0l20, jpa/0l43
out.println("if (__caucho_cacheItem == null)");
out.println(" return;");
out.println();
// ejb/06c9
out.println("if (state.isDeleting())");
out.println(" return;");
out.println();
// ejb/06--, ejb/0a-- and jpa/0o04
int group = 0;
out.print(getClassName() + " item = (" + getClassName() + ")");
out.println("__caucho_cacheItem.getEntity();");
out.println("Object pk = __caucho_getPrimaryKey();");
out.println("item.__caucho_setPrimaryKey(pk);");
_entityType.generateCopyLoadObject(out, "item", "super", group);
out.println("item.__caucho_loadMask_" + group + " |= __caucho_loadMask_" + group + " & 1L;");
out.println("__caucho_session.getPersistenceUnit().updateCacheItem((com.caucho.amber.type.EntityType) __caucho_home.getRootType(), pk, __caucho_cacheItem);");
out.popDepth();
out.println("}");
}
/**
* Generates the after-rollback
*/
void generateAfterRollback(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_afterRollback()");
out.println("{");
out.pushDepth();
out.println("__caucho_state = com.caucho.amber.entity.EntityState.P_NON_TRANSACTIONAL;");
int loadCount = _entityType.getLoadGroupIndex();
for (int i = 0; i <= loadCount / 64; i++) {
out.println("__caucho_loadMask_" + i + " = 0L;");
}
int dirtyCount = _entityType.getDirtyIndex();
for (int i = 0; i <= dirtyCount / 64; i++) {
out.println("__caucho_dirtyMask_" + i + " = 0L;");
}
out.popDepth();
out.println("}");
}
String getDebug()
{
return "this";
}
/**
* Generates the update
*/
void generateCreate(JavaWriter out)
throws IOException
{
boolean isAbstract
= Modifier.isAbstract(_entityType.getBeanClass().getModifiers());
boolean isGeneratedValue = false;
// jpa/0gg0
if (_entityType.getId() != null && ! isAbstract) {
ArrayList<IdField> fields = _entityType.getId().getKeys();
IdField idField = fields.size() > 0 ? fields.get(0) : null;
boolean hasReturnGeneratedKeys = false;
try {
hasReturnGeneratedKeys = _entityType.getPersistenceUnit().hasReturnGeneratedKeys();
} catch (Exception e) {
// Meta-data exception which is acceptable or
// no data-source configured. The latter will
// be thrown on web.xml validation. (ejb/06m0)
}
if (idField != null && idField.isAutoGenerate())
isGeneratedValue = true;
if (! hasReturnGeneratedKeys &&
idField != null && idField.getType().isAutoIncrement()) {
out.println();
out.println("private static com.caucho.amber.field.Generator __caucho_id_gen;");
out.println("static {");
out.pushDepth();
out.println("com.caucho.amber.field.MaxGenerator gen = new com.caucho.amber.field.MaxGenerator();");
out.print("gen.setColumn(\"");
out.printJavaString(idField.getColumns().get(0).generateInsertName());
out.println("\");");
out.print("gen.setTable(\"");
out.printJavaString(_entityType.getName());
out.println("\");");
out.println("gen.init();");
out.popDepth();
out.println("}");
}
}
// jpa/0ga2
out.println();
out.println("public boolean __caucho_lazy_create(com.caucho.amber.manager.AmberConnection aConn, com.caucho.amber.type.EntityType home)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
int loadCount = 0;
// jpa/0ge2: MappedSuperclassType
if ((_entityType.getTable() == null) || (_entityType.getId() == null)) {
out.println("return false;");
out.popDepth();
out.println("}");
}
else {
out.println("if (__caucho_session != null)");
out.println(" return true;");
out.println();
// commented out: jpa/0h25
// out.println(" throw new com.caucho.amber.AmberException(\"object \" + " + getDebug() + " + \" is already persistent.\");");
out.println("__caucho_state = com.caucho.amber.entity.EntityState.P_PERSISTING;");
loadCount = _entityType.getLoadGroupIndex();
for (int i = 0; i <= loadCount / 64; i++) {
out.println("__caucho_loadMask_" + i + " = 0L;");
// XXX: jpa/0l21
EntityType parentType = _entityType;
do {
out.println("__caucho_loadMask_" + i + " |= " + parentType.getCreateLoadMask(i) + ";");
} while ((parentType = parentType.getParentType()) != null);
}
out.println();
out.println("__caucho_session = aConn;");
out.println("__caucho_home = home;");
_entityType.generatePrePersist(out);
//out.println();
//out.println("__caucho_home.prePersist(this);");
out.println();
// jpa/0r20
for (Method method : _entityType.getPrePersistCallbacks()) {
out.println(method.getName() + "();");
}
if (isGeneratedValue) {
// jpa/0g50: generated id needs to flush the insert statement at persist() time.
out.println("__caucho_create(aConn, home);");
}
else {
// jpa/0j5e: persist() is lazy but should cascade to add entities to the context.
//out.println();
//out.println("__caucho_cascadePrePersist(aConn);");
out.println("__caucho_cascadePostPersist(aConn);");
}
out.println("__caucho_home.postPersist(this);");
for (Method method : _entityType.getPostPersistCallbacks()) {
out.println(method.getName() + "();");
}
out.println();
out.println("return true;");
out.popDepth();
out.println("}");
}
out.println();
out.println("public boolean __caucho_create(com.caucho.amber.manager.AmberConnection aConn, com.caucho.amber.type.EntityType home)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
// jpa/0ge2: MappedSuperclassType
if ((_entityType.getTable() == null) || (_entityType.getId() == null)) {
out.println("return false;");
out.popDepth();
out.println("}");
return;
}
out.println("if (__caucho_state != com.caucho.amber.entity.EntityState.P_PERSISTING)");
out.println(" return false;");
out.println();
out.println("__caucho_state = com.caucho.amber.entity.EntityState.P_PERSISTED;");
out.println();
out.println("__caucho_cascadePrePersist(aConn);");
int dirtyCount = _entityType.getDirtyIndex();
for (int i = 0; i <= dirtyCount / 64; i++) {
out.println("__caucho_dirtyMask_" + i + " = 0L;");
}
AmberTable table = _entityType.getTable();
String sql = null;
out.println("String sql;");
boolean isAutoInsert = false;
if (_entityType.getId() != null
&& ! isAbstract
&& _entityType.getId().isIdentityGenerator()) {
isAutoInsert = true;
}
out.println("int index = 1;");
_entityType.getId().generateCheckCreateKey(out);
out.println("java.sql.PreparedStatement pstmt;");
// jpa/0gg0, jpa/0gh0
if (isAutoInsert) {
out.println("if (__caucho_home.isIdentityGenerator()) {");
out.pushDepth();
out.print("sql = \"");
out.printJavaString(_entityType.generateAutoCreateSQL(table));
out.println("\";");
out.println("pstmt = aConn.prepareInsertStatement(sql, true);");
out.popDepth();
out.println("} else {");
out.pushDepth();
}
out.print("sql = \"");
out.printJavaString(_entityType.generateCreateSQL(table));
out.println("\";");
out.println("pstmt = aConn.prepareInsertStatement(sql, false);");
if (isAutoInsert) {
out.popDepth();
out.println("}");
}
_entityType.getId().generateSetInsert(out, "pstmt", "index");
_entityType.generateInsertSet(out, table, "pstmt", "index", "super");
out.println();
out.println("pstmt.executeUpdate();");
out.println();
_entityType.getId().generateSetGeneratedKeys(out, "pstmt");
EntityType parentType = _entityType;
do {
for (AmberTable subTable : parentType.getSecondaryTables()) {
sql = parentType.generateCreateSQL(subTable);
out.println();
out.print("sql = \"");
out.printJavaString(sql);
out.println("\";");
out.println("pstmt = aConn.prepareStatement(sql);");
out.println("index = 1;");
out.println();
parentType.getId().generateSetInsert(out, "pstmt", "index");
parentType.generateInsertSet(out, subTable, "pstmt", "index", "super");
out.println();
out.println("pstmt.executeUpdate();");
out.println();
parentType.getId().generateSetGeneratedKeys(out, "pstmt");
}
} while ((parentType = parentType.getParentType()) != null);
// println("pstmt.close();");
out.println("__caucho_cacheItem = new com.caucho.amber.entity.CacheableEntityItem(home.getHome(), new " + getClassName() + "());");
out.println(getClassName() + " cacheEntity = (" + getClassName() + ") __caucho_cacheItem.getEntity();");
out.println("cacheEntity.__caucho_home = home;");
Id id = _entityType.getId();
out.println("Object pk = null;");
if (! id.isEmbeddedId()) {
ArrayList<IdField> keys = id.getKeys();
for (IdField key : keys) {
String value;
if (keys.size() == 1)
value = key.getType().generateCastFromObject("(pk = __caucho_getPrimaryKey())");
else
value = key.generateGet("super");
out.println(key.generateSet("cacheEntity", value) + ";");
}
}
else {
// jpa/0gh0
id.generateCopy(out, "cacheEntity", "this");
// out.println("pk = __caucho_compound_key;");
// out.println(id.getEmbeddedIdField().generateStatementSet("cacheEntity", "__caucho_compound_key") + ";");
}
out.println("try {");
out.pushDepth();
// jpa/0o01
out.println("Object child;");
// jpa/0l21
for (int i = 0; i <= loadCount; i++) {
_entityType.generateCopyLoadObject(out, "cacheEntity", "super", i);
}
out.popDepth();
out.println("} catch (RuntimeException e) {");
out.println(" throw e;");
out.println("} catch (Exception e) {");
out.println(" throw new com.caucho.amber.AmberRuntimeException(e);");
out.println("}");
parentType = _entityType;
// jpa/0l21
for (int i = 0; i <= loadCount / 64; i++) {
out.println("cacheEntity.__caucho_loadMask_" + i + " = 0L;");
do {
out.println("cacheEntity.__caucho_loadMask_" + i + " |= " + parentType.getCreateLoadMask(i) + ";");
}
while ((parentType = parentType.getParentType()) != null);
}
out.println();
out.println("if (pk == null)");
out.println(" pk = __caucho_getPrimaryKey();");
// jpa/0i5e, jpa/1641
// caching entity must only occur after the commit completes to
// handle rollbacks and also so the cache doesn't have an
// item in the middle of a transaction
/*
out.println();
out.println("aConn.getPersistenceUnit().putEntity((com.caucho.amber.type.EntityType) __caucho_home.getRootType(),");
out.println(" pk, __caucho_cacheItem);");
*/
out.println();
generateLogFine(out, " amber create");
out.println();
out.println("return false;");
out.popDepth();
out.println("}");
}
/**
* Generates the delete
*/
void generateDelete(JavaWriter out)
throws IOException
{
}
/**
* Generates the foreign delete
*/
void generateDeleteForeign(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_invalidate_foreign(String table, Object key)");
out.println("{");
out.pushDepth();
_entityType.generateInvalidateForeign(out);
out.popDepth();
out.println("}");
}
/**
* Generates the create
*/
void generateMerge(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_mergeFrom(AmberConnection aConn,");
out.println(" Entity sourceEntity)");
out.println("{");
out.pushDepth();
out.println(getClassName() + " source = (" + getClassName() + ") sourceEntity;");
_entityType.generateMergeFrom(out, "this", "source");
// XXX: can't be right
/*
out.println();
out.println("try {");
out.pushDepth();
// jpa/1622
// out.println("targetEntity.__caucho_cascadePostPersist(aConn);");
out.popDepth();
out.println("} catch (java.sql.SQLException e) {");
out.println(" throw new com.caucho.amber.AmberRuntimeException(e);");
out.println("}");
*/
// jpa/1900
//generateLogFine(out, " merged");
out.popDepth();
out.println("}");
}
void generateSetLoadMask(JavaWriter out)
throws IOException
{
}
/**
* Generates the copy
*/
void generateMakePersistent(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_makePersistent(com.caucho.amber.manager.AmberConnection aConn,");
out.println(" com.caucho.amber.entity.EntityItem cacheItem)");
out.println("{");
out.pushDepth();
out.println(_extClassName + " entity = (" + _extClassName + ") cacheItem.getEntity();");
out.println("__caucho_home = entity.__caucho_home;");
out.println("if (__caucho_home == null) throw new NullPointerException();");
out.println("__caucho_cacheItem = cacheItem;");
// jpa/0ge6: MappedSuperclass
if (_entityType.getId() != null) {
_entityType.getId().generateCopy(out, "super", "entity");
}
out.println("__caucho_session = aConn;");
out.println("__caucho_state = com.caucho.amber.entity.EntityState.P_NON_TRANSACTIONAL;");
out.popDepth();
out.println("}");
}
/**
* Generates the cascade persist
*/
void generateCascadePersist(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_cascadePrePersist(com.caucho.amber.manager.AmberConnection aConn)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
// jpa/0i60
/*
out.println("if (__caucho_state == com.caucho.amber.entity.EntityState.P_TRANSACTIONAL)");
out.println(" __caucho_state = com.caucho.amber.entity.EntityState.P_PERSIST;");
*/
// out.println("if (aConn == null)");
// out.println(" throw new com.caucho.amber.AmberException(\"Null AmberConnection when object \" + " + getDebug() + " + \" is trying to cascade persist child objects.\");");
ArrayList<AmberField> fields = _entityType.getFields();
for (int i = 0; i < fields.size(); i++) {
AmberField field = fields.get(i);
if (field.isCascadable()) {
CascadableField cascadable = (CascadableField) field;
out.println();
cascadable.generatePreCascade(out, "aConn", CascadeType.PERSIST);
}
}
out.popDepth();
out.println("}");
out.println();
out.println("public void __caucho_cascadePostPersist(com.caucho.amber.manager.AmberConnection aConn)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
for (int i = 0; i < fields.size(); i++) {
AmberField field = fields.get(i);
if (field.isCascadable()) {
CascadableField cascadable = (CascadableField) field;
out.println();
cascadable.generatePostCascade(out, "aConn", CascadeType.PERSIST);
}
}
out.popDepth();
out.println("}");
}
/**
* Generates the cascade remove
*/
void generateCascadeRemove(JavaWriter out)
throws IOException
{
out.println();
out.println("public void __caucho_cascadePreRemove(com.caucho.amber.manager.AmberConnection aConn)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
ArrayList<AmberField> fields = _entityType.getFields();
for (int i = 0; i < fields.size(); i++) {
AmberField field = fields.get(i);
if (field.isCascadable()) {
CascadableField cascadable = (CascadableField) field;
out.println();
cascadable.generatePreCascade(out, "aConn", CascadeType.REMOVE);
}
}
out.popDepth();
out.println("}");
out.println();
out.println("public void __caucho_cascadePostRemove(com.caucho.amber.manager.AmberConnection aConn)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
for (int i = 0; i < fields.size(); i++) {
AmberField field = fields.get(i);
if (field.isCascadable()) {
CascadableField cascadable = (CascadableField) field;
out.println();
cascadable.generatePostCascade(out, "aConn", CascadeType.REMOVE);
}
}
out.popDepth();
out.println("}");
}
/**
* Generates the home methods
*/
void generateHome(JavaWriter out)
throws IOException
{
generateHomeFind(out);
boolean generateHomeNew = true;
// jpa/0ge2
if (_entityType instanceof MappedSuperclassType)
generateHomeNew = false;
/* XXX
if (_entityType instanceof SubEntityType) {
SubEntityType sub = (SubEntityType) _entityType;
// jpa/0ge2
if (! sub.isParentMappedSuperclass()) {
if (! sub.getParentType().isAbstractClass())
generateHomeNew = false;
}
}
*/
if (generateHomeNew) {
generateHomeNew(out);
generateHomeFindNew(out);
}
}
/**
* Generates the load key.
*/
void generateLoadKey(JavaWriter out)
throws IOException
{
out.println();
out.print("public Object __caucho_load_key(");
out.print("com.caucho.amber.manager.AmberConnection aConn,");
out.println("java.sql.ResultSet rs, int index)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
boolean isAbstract
= Modifier.isAbstract(_entityType.getBeanClass().getModifiers());
// jpa/0gg0
if (_entityType.getId() == null || isAbstract) {
// jpa/0ge6: MappedSuperclass
out.println("return null;");
out.popDepth();
out.println("}");
return;
}
out.print("return ");
int index = _entityType.getId().generateLoadForeign(out, "rs", "index", 0);
out.println(";");
out.popDepth();
out.println("}");
}
/**
* Generates the home methods
*/
void generateHomeFind(JavaWriter out)
throws IOException
{
out.println();
out.print("public com.caucho.amber.entity.EntityItem __caucho_home_find(");
out.print("com.caucho.amber.manager.AmberConnection aConn,");
out.print("com.caucho.amber.entity.AmberEntityHome home,");
out.println("java.sql.ResultSet rs, int index)");
out.println(" throws java.sql.SQLException");
out.println("{");
out.pushDepth();
boolean isAbstract
= Modifier.isAbstract(_entityType.getBeanClass().getModifiers());
if (_entityType.getId() == null || isAbstract) {
// jpa/0ge6: MappedSuperclass
out.println("return null;");
out.popDepth();
out.println("}");
return;
}
out.print("Object key = ");
int index = _entityType.getId().generateLoadForeign(out, "rs", "index", 0);
out.println(";");
if (_entityType.getDiscriminator() == null) {
out.println("return aConn.loadCacheItem(home.getJavaClass(), key, home);");
}
else {
out.println("String discriminator = rs.getString(index + " + index + ");");
out.println();
out.println("return home.findDiscriminatorEntityItem(aConn, key, discriminator);");
}
out.popDepth();
out.println("}");
}
void generateHomeNew(JavaWriter out)
throws IOException
{
out.println();
out.print("public com.caucho.amber.entity.Entity __caucho_home_new(");
out.print("com.caucho.amber.entity.AmberEntityHome home");
out.println(", Object key");
out.println(", AmberConnection aConn");
out.println(", EntityItem cacheItem");
out.println(")");
out.println("{");
out.pushDepth();
if (_entityType.isAbstractClass() || _entityType.getId() == null) {
out.println("return null;");
out.popDepth();
out.println("}");
return;
}
out.println(getClassName() + " entity = new " + getClassName() + "();");
out.println("entity.__caucho_home = home.getEntityType();");
out.println("entity.__caucho_setPrimaryKey(key);");
out.println("entity.__caucho_session = aConn;");
out.println("entity.__caucho_cacheItem = cacheItem;");
out.println("return entity;");
out.popDepth();
out.println("}");
}
void generateHomeFindNew(JavaWriter out)
throws IOException
{
EntityType parentType = _entityType.getParentType();
// jpa/0ge3
// jpa/0l32: find(SubBean.class, "2") would try to select the
// discriminator column from the "sub-table".
if (isEntityParent())
return;
out.println();
out.print("public com.caucho.amber.entity.Entity __caucho_home_find(");
out.print("com.caucho.amber.manager.AmberConnection aConn, ");
out.print("com.caucho.amber.entity.AmberEntityHome home, ");
out.println("Object key)");
out.println("{");
out.pushDepth();
AmberColumn discriminator = _entityType.getDiscriminator();
if (_entityType.isAbstractClass()
|| _entityType.getId() == null
|| discriminator == null) {
out.println("return __caucho_home_new(home, key, aConn, null);");
out.popDepth();
out.println("}");
return;
}
String rootTableName = _entityType.getRootTableName();
if (rootTableName == null)
rootTableName = "";
out.println("java.sql.ResultSet rs = null;");
out.println("java.sql.PreparedStatement pstmt = null;");
out.println("String sql = null;");
out.println();
out.println("try {");
out.pushDepth();
String keyType = _entityType.getId().getForeignTypeName();
String discriminatorVar = "discriminator";
out.println("String " + discriminatorVar + " = null;");
generateHomeNewLoading(out, discriminatorVar);
out.println("com.caucho.amber.entity.Entity entity = home.newDiscriminatorEntity(key, " + discriminatorVar + ");");
out.println("entity.__caucho_load(aConn, rs, 1);");
out.println("return entity;");
out.popDepth();
out.println("} catch (RuntimeException e) {");
out.println(" throw e;");
out.println("} catch (Exception e) {");
out.println(" throw new com.caucho.amber.AmberRuntimeException(e);");
out.println("} finally {");
/*
out.println(" if (rs != null)");
out.println(" rs.close();");
out.println(" if (pstmt != null)");
out.println(" aConn.closeStatement(sql);");
*/
out.println("}");
out.popDepth();
out.println("}");
}
/**
* Generates the loading for home_new
*/
void generateHomeNewLoading(JavaWriter out,
String discriminatorVar)
throws IOException
{
out.print("sql = \"select ");
EntityType parentType = _entityType;
/* XXX: jpa/0gg3
// jpa/0l32
if (_entityType.getDiscriminator() != null) {
while (parentType.getParentType() != null)
parentType = parentType.getParentType();
}
*/
out.printJavaString(parentType.generateLoadSelect("o"));
out.print(" from ");
/*
if (rootTableName == null)
out.print(_entityType.getTable().getName());
else
out.print(rootTableName);
*/
out.printJavaString(_entityType.getTable().getName());
out.print(" o where ");
// jpa/0s27
out.printJavaString((parentType.getId().generateMatchArgWhere("o")));
out.println("\";");
out.println("pstmt = aConn.prepareStatement(sql);");
String keyType = _entityType.getId().getForeignTypeName();
out.println(keyType + " " + "keyValue = (" + keyType + ") key;");
out.println("int index = 1;");
_entityType.getId().generateSetKey(out, "pstmt", "index", "keyValue");
out.println("rs = pstmt.executeQuery();");
out.println("if (rs.next()) {");
out.println(" " + discriminatorVar + " = rs.getString(1);"); // XXX:
out.println("}");
}
void generateCallbacks(JavaWriter out,
String object,
ArrayList<Method> callbacks)
throws IOException
{
if (callbacks.size() > 0) {
out.println();
for (Method method : callbacks) {
out.println(object + "." + method.getName() + "();");
}
}
}
protected void generateLogFine(JavaWriter out, String msg)
throws IOException
{
out.println("if (__caucho_log.isLoggable(java.util.logging.Level.FINE))");
out.print(" __caucho_log.fine(");
out.print("getClass().getName() + \"[\" + __caucho_getPrimaryKey() + \"]\"");
out.print(" + \"");
out.printJavaString(msg);
out.println("\");");
}
protected void generateLogFinest(JavaWriter out, String msg)
throws IOException
{
out.println("if (__caucho_log.isLoggable(java.util.logging.Level.FINEST))");
out.print(" __caucho_log.finest(");
out.print("getClass().getName() + \"[\" + __caucho_getPrimaryKey() + \"]\"");
out.print(" + \"");
out.printJavaString(msg);
out.println("\");");
}
}