/* * 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 Rodrigo Westrupp */ package com.caucho.amber.type; import com.caucho.amber.field.*; import com.caucho.amber.manager.AmberPersistenceUnit; import com.caucho.amber.table.AmberColumn; import com.caucho.amber.table.AmberTable; import com.caucho.config.ConfigException; import com.caucho.java.JavaWriter; import com.caucho.make.ClassDependency; import com.caucho.util.L10N; import com.caucho.vfs.PersistentDependency; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.logging.Logger; /** * Represents a stateful type: * embeddable, entity or mapped-superclass. */ abstract public class BeanType extends AbstractEnhancedType { private static final Logger log = Logger.getLogger(BeanType.class.getName()); private static final L10N L = new L10N(BeanType.class); private boolean _isFieldAccess; // fields declared on this class private ArrayList<AmberField> _selfFields = new ArrayList<AmberField>(); private volatile boolean _isConfigured; private ArrayList<PersistentDependency> _dependencies = new ArrayList<PersistentDependency>(); private HashMap<String,String> _completionFields = new HashMap<String,String>(); private AmberColumn _discriminator; public BeanType(AmberPersistenceUnit amberPersistenceUnit) { super(amberPersistenceUnit); } public boolean isEntity() { return false; } /** * Set true for field-access. */ public void setFieldAccess(boolean isFieldAccess) { _isFieldAccess = isFieldAccess; } /** * Set true for field-access. */ public boolean isFieldAccess() { return _isFieldAccess; } /** * Returns true for an embeddable */ public boolean isEmbeddable() { return false; } /** * Returns the discriminator. */ public AmberColumn getDiscriminator() { return _discriminator; } /** * Sets the discriminator. */ public void setDiscriminator(AmberColumn discriminator) { _discriminator = discriminator; } /** * Returns the java type. */ @Override public String getJavaTypeName() { return getInstanceClassName(); } /** * Adds a new field. */ public void addField(AmberField field) { _selfFields.add(field); Collections.sort(_selfFields, new AmberFieldCompare()); } /** * Returns the fields declared on this instance */ public ArrayList<AmberField> getSelfFields() { return _selfFields; } /** * Returns the fields. */ public ArrayList<AmberField> getFields() { return _selfFields; } /** * Returns the field with a given name. */ public AmberField getField(String name) { for (AmberField field : getFields()) { if (field.getName().equals(name)) return field; } return null; } /** * Sets the bean class. */ @Override public void setBeanClass(Class beanClass) { super.setBeanClass(beanClass); addDependency(_tBeanClass); } /** * Adds a dependency. */ public void addDependency(Class cl) { addDependency(new ClassDependency(cl)); } /** * Adds a dependency. */ public void addDependency(PersistentDependency depend) { if (! _dependencies.contains(depend)) _dependencies.add(depend); } /** * Gets the dependency. */ public ArrayList<PersistentDependency> getDependencies() { return _dependencies; } /** * Adds a new completion field. */ public void addCompletionField(String name) { _completionFields.put(name, name); } /** * Returns true if and only if it has the completion field. */ public boolean containsCompletionField(String completionField) { return _completionFields.containsKey(completionField); } /** * Remove all completion fields. */ public void removeAllCompletionFields() { _completionFields.clear(); } /** * Set true if configured. */ public boolean startConfigure() { synchronized (this) { if (_isConfigured) return false; _isConfigured = true; return true; } } /** * Initialize the type. */ @Override public void init() throws ConfigException { // jpa/0l14, jpa/0ge3 for (AmberField field : _selfFields) { // ejb/0602 if (getPersistenceUnit().isJPA()) { if (field instanceof ManyToOneField) ((ManyToOneField) field).init((EntityType) this); } } } /** * Converts the value. */ @Override public String generateCastFromObject(String value) { return "((" + getInstanceClassName() + ") " + value + ")"; } /** * Generates the select clause for a load. */ public void generateLoadSelect(StringBuilder sb, AmberTable table, String id, int loadGroup) { // jpa/0l14, jpa/0ge3 for (AmberField field : getFields()) { // jpa/0gg3 if (field.getLoadGroupIndex() == loadGroup) { String propSelect = field.generateLoadSelect(table, id); if (propSelect != null) { if (sb.length() > 0) sb.append(", "); sb.append(propSelect); } } } } /** * Generates a string to load the field. */ public int generateLoad(JavaWriter out, String rs, String indexVar, int index, int loadGroupIndex) throws IOException { if (getDiscriminator() != null) { EntityType parent = null; if (this instanceof EntityType) parent = ((EntityType) this).getParentType(); boolean isAbstractParent = getPersistenceUnit().isJPA() && (parent == null || Modifier.isAbstract(parent.getBeanClass().getModifiers())); if (loadGroupIndex == 0 || isAbstractParent) index++; } for (AmberField field : getFields()) { // jpa/0gg3 if (field.getLoadGroupIndex() == loadGroupIndex) index = field.generateLoad(out, rs, indexVar, index); } return index; } /** * Generates the select clause for a load. */ abstract public String generateLoadSelect(AmberTable table, String id); /** * Generates the select clause for a load. */ public String generateLoadSelect(AmberTable table, String id, int loadGroup) { StringBuilder sb = new StringBuilder(); generateLoadSelect(sb, table, id, loadGroup); if (sb.length() > 0) return sb.toString(); else return null; } /** * Returns the load mask generated on create. */ public void generatePrePersist(JavaWriter out) throws IOException { for (AmberField field : getFields()) { field.generatePrePersist(out); } } /** * Generates the foreign delete */ public void generateInvalidateForeign(JavaWriter out) throws IOException { for (AmberField field : getFields()) { field.generateInvalidateForeign(out); } } /** * Generates any expiration code. */ public void generateExpire(JavaWriter out) throws IOException { for (AmberField field : getFields()) { field.generateExpire(out); } } /** * Gets a matching getter. */ public Method getGetter(String name) { return getGetter(_tBeanClass, name); } /** * Gets a matching getter. */ public static Method getGetter(Class cl, String name) { Method []methods = cl.getMethods(); for (int i = 0; i < methods.length; i++) { Class []param = methods[i].getParameterTypes(); String methodName = methods[i].getName(); if (name.equals(methodName) && param.length == 0) return methods[i]; } cl = cl.getSuperclass(); if (cl != null) return getGetter(cl, name); else return null; } /** * Gets a matching getter. */ public static Field getField(Class cl, String name) { Field []fields = cl.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { if (name.equals(fields[i].getName())) return fields[i]; } cl = cl.getSuperclass(); if (cl != null) return getField(cl, name); else return null; } /** * Gets a matching getter. */ public static Method getSetter(Class cl, String name) { Method []methods = cl.getMethods(); for (int i = 0; i < methods.length; i++) { Class []param = methods[i].getParameterTypes(); String methodName = methods[i].getName(); if (name.equals(methodName) && param.length == 1) return methods[i]; } cl = cl.getSuperclass(); if (cl != null) return getSetter(cl, name); else return null; } /** * Returns the load mask generated on create. */ public long getCreateLoadMask(int group) { long mask = 0; for (AmberField field : getFields()) { mask |= field.getCreateLoadMask(group); } return mask; } }