Save This Page
Home » jdo2-model-2.3-ea-src » org.apache.jdo.impl.model.jdo » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software 
   12    * distributed under the License is distributed on an "AS IS" BASIS, 
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
   14    * See the License for the specific language governing permissions and 
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.jdo.impl.model.jdo;
   19   
   20   import java.lang.reflect.Modifier;
   21   import java.util.Arrays;
   22   import java.util.List;
   23   
   24   import org.apache.jdo.impl.model.jdo.util.TypeSupport;
   25   import org.apache.jdo.model.ModelException;
   26   import org.apache.jdo.model.java.JavaField;
   27   import org.apache.jdo.model.java.JavaType;
   28   import org.apache.jdo.model.jdo.JDOArray;
   29   import org.apache.jdo.model.jdo.JDOClass;
   30   import org.apache.jdo.model.jdo.JDOCollection;
   31   import org.apache.jdo.model.jdo.JDOField;
   32   import org.apache.jdo.model.jdo.JDOMap;
   33   import org.apache.jdo.model.jdo.JDOReference;
   34   import org.apache.jdo.model.jdo.JDORelationship;
   35   import org.apache.jdo.model.jdo.NullValueTreatment;
   36   import org.apache.jdo.model.jdo.PersistenceModifier;
   37   import org.apache.jdo.util.I18NHelper;
   38   
   39   /**
   40    * An instance of this class represents the JDO metadata of a managed field 
   41    * of a persistence capable class. This dynamic implementation only
   42    * stores property values explicitly set by setter method. 
   43    * <p>
   44    * Please note, you cannot rely on the Java identity of the
   45    * JDORelationship instance returned by {@link #getRelationship}.  
   46    * The getter will always return a new Java Instance, unless the
   47    * relationship is explicitly set by the setter 
   48    * {@link #setRelationship(JDORelationship relationship)}.
   49    * <p>
   50    * TBD:
   51    * <ul>
   52    * <li> Change usage of POSSIBLY_PERSISTENT persistence-modifier as soon as 
   53    * the enhancer fully supports it.
   54    * <li> Property change support
   55    * </ul> 
   56    *
   57    * @author Michael Bouschen
   58    * @since 1.1
   59    * @version 2.0
   60    */
   61   public class JDOFieldImplDynamic
   62       extends JDOMemberImpl 
   63       implements JDOField
   64   {
   65       /** 
   66        * Property persistenceModifier. 
   67        * Default see {@link #getPersistenceModifier}. 
   68        */
   69       protected int persistenceModifier = PersistenceModifier.UNSPECIFIED;
   70       
   71       /** Property primaryKey. Defaults to <code>false</code>. */
   72       private boolean primaryKey = false;
   73       
   74       /** Property nullValueTreatment. Defaults to none. */
   75       private int nullValueTreatment = NullValueTreatment.NONE;
   76   
   77       /** Property defaultFetchGroup. Default see {@link #isDefaultFetchGroup}. */
   78       protected Boolean defaultFetchGroup;
   79   
   80       /** Property embedded. Default see {@link #isEmbedded}. */
   81       protected Boolean embedded;
   82   
   83       /** Property javaField. No default. */
   84       protected transient JavaField javaField;
   85   
   86       /** Property serializable. Defaults to <code>false</code>. */
   87       private boolean serializable = false;
   88   
   89       /** Property mappedByName. Defaults to <code>null</code>. */
   90       private String mappedByName = null;
   91   
   92       /** Relationship JDOField<->JDORelationship. */
   93       protected JDORelationship relationship;
   94       
   95       /** I18N support */
   96       protected final static I18NHelper msg =  
   97           I18NHelper.getInstance(JDOFieldImplDynamic.class);
   98   
   99       /** Constructor. */
  100       protected JDOFieldImplDynamic(String name, JDOClass declaringClass) {
  101           super(name, declaringClass);
  102       }
  103   
  104       /**
  105        * Get the persistence modifier of this JDOField.
  106        * @return the persistence modifier, one of 
  107        * {@link PersistenceModifier#NONE}, 
  108        * {@link PersistenceModifier#PERSISTENT},
  109        * {@link PersistenceModifier#TRANSACTIONAL}, or
  110        * {@link PersistenceModifier#POSSIBLY_PERSISTENT}.
  111        */
  112       public int getPersistenceModifier() {
  113           if (persistenceModifier != PersistenceModifier.UNSPECIFIED) {
  114               // return persistenceModifier, if explicitly set by the setter
  115               return persistenceModifier;
  116           }
  117           
  118           // not set => calculate
  119           int result = PersistenceModifier.UNSPECIFIED;
  120           JavaType type = getType();
  121           if (nameHasJDOPrefix()) {
  122               result = PersistenceModifier.NONE;
  123           }
  124           else if (type != null) {
  125               result = TypeSupport.isPersistenceFieldType(type) ?
  126                   PersistenceModifier.POSSIBLY_PERSISTENT : 
  127                   PersistenceModifier.NONE;
  128           }
  129   
  130           return result;
  131       }
  132   
  133       /** 
  134        * Set the persistence modifier for this JDOField.
  135        * @param persistenceModifier an integer indicating the persistence 
  136        * modifier, one of: {@link PersistenceModifier#UNSPECIFIED}, 
  137        * {@link PersistenceModifier#NONE}, 
  138        * {@link PersistenceModifier#PERSISTENT},
  139        * {@link PersistenceModifier#TRANSACTIONAL}, or
  140        * {@link PersistenceModifier#POSSIBLY_PERSISTENT}.
  141        */
  142       public void setPersistenceModifier (int persistenceModifier)
  143           throws ModelException {
  144           if (nameHasJDOPrefix() && 
  145               (persistenceModifier == PersistenceModifier.PERSISTENT ||
  146                persistenceModifier == PersistenceModifier.TRANSACTIONAL)) {
  147               throw new ModelException(
  148                   msg.msg("EXC_IllegalJDOPrefix", getName())); //NOI18N
  149           }
  150           this.persistenceModifier = persistenceModifier;
  151       }
  152       
  153       /** 
  154        * Determines whether this JDOField is a key field or not.  
  155        * @return <code>true</code> if the field is a key field, 
  156        * <code>false</code> otherwise
  157        */
  158       public boolean isPrimaryKey() {
  159           return primaryKey;
  160       }
  161   
  162       /** 
  163        * Set whether this JDOField is a key field or not.
  164        * @param primaryKey if <code>true</code>, the JDOField is marked 
  165        * as a key field; otherwise, it is not
  166        */
  167       public void setPrimaryKey(boolean primaryKey) {
  168           this.primaryKey = primaryKey;
  169       }
  170   
  171       /**
  172        * Gets the null value treatment indicator of this JDOField.
  173        * @return the null value treatment of this JDOField, one of 
  174        * {@link NullValueTreatment#NONE}, {@link NullValueTreatment#EXCEPTION} or
  175        * {@link NullValueTreatment#DEFAULT}
  176        */
  177       public int getNullValueTreatment() {
  178           return nullValueTreatment;
  179       }
  180   
  181       /**
  182        * Sets the null value treatment indicator for this JDOField.
  183        * @param nullValueTreatment an integer indicating the null 
  184        * value treatment, one of: {@link NullValueTreatment#NONE}, 
  185        * {@link NullValueTreatment#EXCEPTION} or 
  186        * {@link NullValueTreatment#DEFAULT}
  187        */
  188       public void setNullValueTreatment(int nullValueTreatment) {
  189           this.nullValueTreatment = nullValueTreatment;
  190       }
  191   
  192       /**
  193        * Determines whether this JDOField is part of the default fetch group or 
  194        * not.
  195        * @return <code>true</code> if the field is part of the default fetch 
  196        * group, <code>false</code> otherwise
  197        */
  198       public boolean isDefaultFetchGroup() {
  199           if (defaultFetchGroup != null) {
  200               // return dfg, if explicitly set by the setter
  201               return defaultFetchGroup.booleanValue();
  202           }
  203           
  204           // not set => calculate
  205           boolean dfg = false;
  206           if (isPrimaryKey()) {
  207               dfg = false;
  208           }
  209           else {
  210               JavaType type = getType();
  211               if ((type != null) && type.isValue()) {
  212                   dfg = true;
  213               }
  214           }
  215           
  216           return dfg;
  217       }
  218   
  219       /**
  220        * Set whether this JDOField is part of the default fetch group or not.
  221        * @param defaultFetchGroup if <code>true</code>, the JDOField is marked  
  222        * as beeing part of the default fetch group; otherwise, it is not
  223        */
  224       public void setDefaultFetchGroup(boolean defaultFetchGroup) {
  225           this.defaultFetchGroup = 
  226               defaultFetchGroup ? Boolean.TRUE : Boolean.FALSE;
  227       }
  228   
  229       /**
  230        * Determines whether the field should be stored if possible as part of
  231        * the instance instead of as its own instance in the datastore.
  232        * @return <code>true</code> if the field is stored as part of the instance;
  233        * <code>false</code> otherwise
  234        */
  235       public boolean isEmbedded() {
  236           if (embedded != null) {
  237               // return embedded, if explicitly set by the setter
  238               return embedded.booleanValue();
  239           }
  240           
  241           // not set => calculate
  242           boolean result = false;
  243           JavaType type = getType();
  244           if (type != null) {
  245               result = TypeSupport.isEmbeddedFieldType(type);
  246           }
  247           return result;
  248       }
  249   
  250       /**
  251        * Set whether the field should be stored if possible as part of
  252        * the instance instead of as its own instance in the datastore.
  253        * @param embedded <code>true</code> if the field is stored as part of the 
  254        * instance; <code>false</code> otherwise
  255        */
  256       public void setEmbedded(boolean embedded) {
  257           this.embedded = (embedded ? Boolean.TRUE : Boolean.FALSE);
  258       }
  259       
  260       /**
  261        * Get the corresponding JavaField representation for this JDOField.
  262        * @return the corresponding JavaField representation
  263        */
  264       public JavaField getJavaField() {
  265           if (javaField != null) {
  266               // return java field, if explicitly set by the setter
  267               return javaField;
  268           }
  269           
  270           // not set => calculate
  271           JavaType javaType = getDeclaringClass().getJavaType();
  272           return javaType.getJavaField(getName());
  273       }
  274   
  275       /**
  276        * Sets the corresponding Java field representation for this JDOField.
  277        * @param javaField the corresponding Java field representation
  278        */
  279       public void setJavaField (JavaField javaField) throws ModelException {
  280           this.javaField = javaField;
  281       }
  282       
  283       /**
  284        * Determines whether this JDOField is serializable or not.  
  285        * @return <code>true</code> if the field is serializable,
  286        * <code>false</code> otherwise
  287        */
  288       public boolean isSerializable() {
  289           return serializable;
  290       }
  291   
  292       /** 
  293        * Set whether this JDOField is serializable or not.
  294        * @param serializable if <code>true</code>, the JDOField is serializable;
  295        * otherwise, it is not
  296        * @exception ModelException if impossible
  297        */
  298       public void setSerializable(boolean serializable) throws ModelException {
  299           this.serializable = serializable;
  300       }
  301   
  302       /** 
  303        * Get the name of the field specified in a mappedBy attribute in the
  304        * metadata. The method returns <code>null</code> if the metadata for this
  305        * field does not specify the mappedBy attribute.  Note that this 
  306        * can be provided at the field level to help population of the model, 
  307        * but should only be specified on a field that has a corresponding
  308        * relationship.
  309        * @return the mappedBy field name if available; <code>null</code>
  310        * otherwise.
  311        */
  312       public String getMappedByName() {
  313           return mappedByName;
  314       }
  315   
  316       /**
  317        * Set the name of the field specified in a mappedBy attribute in the
  318        * metadata.  Note that this can be provided at the field level to 
  319        * help population of the model, but should only be specified on a 
  320        * field that has a corresponding relationship.
  321        * @param mappedByName the mappedBy field name.
  322        * @exception ModelException if impossible
  323        */
  324       public void setMappedByName(String mappedByName) throws ModelException {
  325           String oldMappedByName = this.mappedByName;
  326           this.mappedByName = mappedByName;
  327           UnresolvedRelationshipHelper info = getUnresolvedRelationshipHelper();
  328           if (oldMappedByName != null) {
  329               // remove old mappedByName from unresolved relationship helper
  330               info.remove(oldMappedByName, this);
  331           }
  332           if (mappedByName != null) {
  333               // update unresolved relationship helper
  334               info.register(mappedByName, this);
  335           }
  336       }
  337   
  338       /**
  339        * Get the relationship information for this JDOField. The method 
  340        * returns null if the field is not part of a relationship 
  341        * (e.g. it is a primitive type field).
  342        * @return relationship info of this JDOField or <code>null</code> if 
  343        * this JDOField is not a relationship
  344        */
  345       public JDORelationship getRelationship() {
  346           if (relationship != null) {
  347               // return relationship, if explicitly set by the setter
  348               return relationship;
  349           }
  350           
  351           // not set => calculate
  352   
  353           if (getPersistenceModifier() == PersistenceModifier.NONE)
  354               // field has persistence modifier none => cannot be a relationship
  355               return null;
  356                               
  357           // check the type if available
  358           JDORelationship rel = null;
  359           JavaType type = getType();
  360           if (type != null) {
  361               if (type.isValue() || TypeSupport.isValueArrayType(type)) {
  362                   // no relationship
  363                   rel = null;
  364               }
  365               else if (type.isJDOSupportedCollection()) {
  366                   rel = createJDOCollectionInternal();
  367               }
  368               else if (type.isJDOSupportedMap()) {
  369                   rel = createJDOMapInternal();
  370               }
  371               else if (type.isArray()) {
  372                   rel = createJDOArrayInternal();
  373               }
  374               else {
  375                   rel = createJDOReferenceInternal();
  376               }
  377           }
  378           return rel;
  379       }
  380   
  381       /**
  382        * Set the relationship information for this JDOField.
  383        * @param relationship the JDORelationship instance
  384        */
  385       public void setRelationship(JDORelationship relationship) 
  386           throws ModelException {
  387           JDORelationship old = this.relationship;
  388           if (old != null) {
  389               old.setInverseRelationship(null);
  390           }
  391           this.relationship = relationship;
  392       }
  393   
  394       /**
  395        * Creates and returns a new JDOReference instance. 
  396        * This method automatically binds the new JDOReference to this JDOField. 
  397        * The following holds true:
  398        * <ul>
  399        * <li> Method {@link #getRelationship} returns the new created instance
  400        * <li> <code>this.getRelationship().getDeclaringField() == this</code>
  401        * </ul> 
  402        * @return a new JDOReference instance bound to this JDOField
  403        * @exception ModelException if impossible
  404        */
  405       public JDOReference createJDOReference() throws ModelException {
  406           JDOReference ref = createJDOReferenceInternal();
  407           setRelationship(ref);
  408           return ref;
  409       }
  410   
  411       /**
  412        * Creates and returns a new JDOCollection instance. 
  413        * This method automatically binds the new JDOCollection to this JDOField. 
  414        * The following holds true:
  415        * <ul>
  416        * <li> Method {@link #getRelationship} returns the new created instance
  417        * <li> <code>this.getRelationship().getDeclaringField() == this</code>
  418        * </ul> 
  419        * @return a new JDOCollection instance bound to this JDOField
  420        * @exception ModelException if impossible
  421        */
  422       public JDOCollection createJDOCollection() throws ModelException {
  423           JDOCollection col = createJDOCollectionInternal();
  424           setRelationship(col);
  425           return col;
  426       }
  427   
  428       /**
  429        * Creates and returns a new JDOArray instance. 
  430        * This method automatically binds the new JDOArray to this JDOField. 
  431        * The following holds true:
  432        * <ul>
  433        * <li> Method {@link #getRelationship} returns the new created instance
  434        * <li> <code>this.getRelationship().getDeclaringField() == this</code>
  435        * </ul> 
  436        * @return a new JDOArray instance bound to this JDOField
  437        * @exception ModelException if impossible
  438        */
  439       public JDOArray createJDOArray() throws ModelException {
  440           JDOArray array = createJDOArrayInternal();
  441           setRelationship(array);
  442           return array;
  443       }
  444   
  445       /**
  446        * Creates and returns a new JDOMap instance. 
  447        * This method automatically binds the new JDOMap to this JDOField. 
  448        * The following holds true:
  449        * <ul>
  450        * <li> Method {@link #getRelationship} returns the new created instance
  451        * <li> <code>this.getRelationship().getDeclaringField() == this</code>
  452        * </ul> 
  453        * @return a new JDOMap instance bound to this JDOField
  454        * @exception ModelException if impossible
  455        */
  456       public JDOMap createJDOMap() throws ModelException {
  457           JDOMap map = createJDOMapInternal();
  458           setRelationship(map);
  459           return map;
  460       }
  461   
  462       /**
  463        * Convenience method to check the persistence modifier from this JDOField.
  464        * @return <code>true</code> if this field has the  
  465        * {@link PersistenceModifier#PERSISTENT} modifier; <code>false</code> 
  466        * otherwise
  467        */
  468       public boolean isPersistent() {
  469           switch (getPersistenceModifier()) {
  470           case PersistenceModifier.PERSISTENT:
  471               return true;
  472           case PersistenceModifier.POSSIBLY_PERSISTENT:
  473               // Enable assertion as soon as the enhancer sets the java modifier.
  474               //Assertion.affirm(javaModifier, 
  475               //                 msg.msg("ERR_MissingJavaModifier", 
  476               //                 getDeclaringClass().getName() + "." + getName()));
  477               int mod = getJavaField().getModifiers();
  478               return !(Modifier.isStatic(mod) || Modifier.isFinal(mod) || 
  479                        Modifier.isTransient(mod));
  480           }
  481           return false;
  482       }
  483   
  484       /**
  485        * Convenience method to check the persistence modifier from this JDOField.
  486        * @return <code>true</code> if this field has the  
  487        * {@link PersistenceModifier#TRANSACTIONAL} modifier; <code>false</code> 
  488        * otherwise
  489        */
  490       public boolean isTransactional() {
  491           return (getPersistenceModifier() == PersistenceModifier.TRANSACTIONAL);
  492       }
  493       
  494       /**
  495        * Convenience method to check the persistence modifier from this JDOField.
  496        * A field is a managed field, if it has the persistence-modifier 
  497        * {@link PersistenceModifier#PERSISTENT} or 
  498        * {@link PersistenceModifier#TRANSACTIONAL}.
  499        * @return <code>true</code> if this field is a managed field; 
  500        * <code>false</code> otherwise     
  501        */
  502       public boolean isManaged() {
  503           // For now treat POSSIBLY_PERSISTENT as PERSISTENT. This will be removed 
  504           // as soon as the enhancer fully supports POSSIBLY_PERSISTENT
  505           int persistenceModifier = getPersistenceModifier();
  506           return (persistenceModifier == PersistenceModifier.PERSISTENT) ||
  507                  (persistenceModifier == PersistenceModifier.POSSIBLY_PERSISTENT) || 
  508                  (persistenceModifier == PersistenceModifier.TRANSACTIONAL);
  509       }
  510   
  511       /**
  512        * Convenience method to check whether this field is a relationship field.
  513        * @return <code>true</code> if this field is a relationship;
  514        * <code>false</code> otherwise
  515        */
  516       public boolean isRelationship() {
  517           return getRelationship() != null;
  518       }
  519   
  520       /**
  521        * Convenience method to check whether this field represents a property.
  522        * @return <code>true</code> if this field represents a property; 
  523        * <code>false</code> otherwise
  524        */
  525       public boolean isProperty() {
  526           return false;
  527       }
  528   
  529       /**
  530        * Get the JavaType representation of the type of the field.
  531        * @return JavaType representation of the type of this field.
  532        */
  533       public JavaType getType() {
  534           JavaField field = getJavaField();
  535           return (field == null) ? null : field.getType();
  536       }
  537       
  538       /**
  539        * Returns the absolute field number of this JDOField.
  540        * @return the absolute field number
  541        */
  542       public int getFieldNumber() {
  543           int fieldNumber = getRelativeFieldNumber();
  544           if (fieldNumber > -1) {
  545               // >-1 denotes a managed field
  546               fieldNumber += getDeclaringClass().getInheritedManagedFieldCount();
  547           }
  548           return fieldNumber;
  549       }
  550   
  551       /**
  552        * Returns the relative field number of this JDOField.
  553        * @return the relative field number
  554        */
  555       public int getRelativeFieldNumber() {
  556           JDOField[] fields = getDeclaringClass().getDeclaredManagedFields();
  557           List fieldList = Arrays.asList(fields);
  558           return fieldList.indexOf(this);
  559       }
  560   
  561       //========= Internal helper methods ==========
  562   
  563       /**
  564        * Creates and returns a new JDOReference instance. 
  565        * This method automatically sets this JDOField as the declaring field of 
  566        * the returned instance.
  567        * @return a new JDOReference instance bound to this JDOField
  568        */
  569       protected JDOReference createJDOReferenceInternal() {
  570           JDOReferenceImplDynamic ref = new JDOReferenceImplDynamic();
  571           // update relationship JDORelationship->JDOField
  572           ref.setDeclaringField(this);
  573           return ref;
  574       }
  575   
  576       /**
  577        * Creates and returns a new JDOCollection instance. 
  578        * This method automatically this JDOField as the declaring field of 
  579        * the returned instance.
  580        * @return a new JDOCollection instance bound to this JDOField
  581        */
  582       protected JDOCollection createJDOCollectionInternal() {
  583           JDOCollectionImplDynamic collection = new JDOCollectionImplDynamic();
  584           // update relationship JDORelationship->JDOField
  585           collection.setDeclaringField(this);
  586           return collection;
  587       }
  588   
  589       /**
  590        * Creates and returns a new JDOArray instance. 
  591        * This method automatically this JDOField as the declaring field of 
  592        * the returned instance.
  593        * @return a new JDOArray instance bound to this JDOField
  594        */
  595       protected JDOArray createJDOArrayInternal() {
  596           JDOArrayImplDynamic array = new JDOArrayImplDynamic();
  597           // update relationship JDORelationship->JDOField
  598           array.setDeclaringField(this);
  599           return array;
  600       }
  601   
  602       /**
  603        * Creates and returns a new JDOMap instance. 
  604        * This method automatically this JDOField as the declaring field of 
  605        * the returned instance.
  606        * @return a new JDOMap instance bound to this JDOField
  607        */
  608       protected JDOMap createJDOMapInternal() {
  609           JDOMapImplDynamic map = new JDOMapImplDynamic();
  610           // update relationship JDORelationship->JDOField
  611           map.setDeclaringField(this);
  612           return map;
  613       }
  614   
  615       /**
  616        * Returns <code>true</code> if the name of this JDOField has the
  617        * prefix jdo. 
  618        * @return <code>true</code> if the name of this JDOField has the
  619        * prefix jdo; <code>false</code> otherwise.
  620        */
  621       private boolean nameHasJDOPrefix() {
  622           String name = getName();
  623           return (name != null) && name.startsWith("jdo"); //NOI18N
  624       }
  625   
  626       /** 
  627        * Returns the UnresolvedRelationshipHelper instance from the declaring
  628        * JDOModel instacne of the declaring JDOClass.
  629        * @return the current UnresolvedRelationshipHelper
  630        */
  631       UnresolvedRelationshipHelper getUnresolvedRelationshipHelper() {
  632           return ((JDOModelImplDynamic) getDeclaringClass().getDeclaringModel()).
  633               getUnresolvedRelationshipHelper();
  634       }
  635       
  636   }

Save This Page
Home » jdo2-model-2.3-ea-src » org.apache.jdo.impl.model.jdo » [javadoc | source]