Coverage Report - org.apache.ojb.broker.util.BrokerHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
BrokerHelper
N/A
N/A
3.318
 
 1  
 package org.apache.ojb.broker.util;
 2  
 
 3  
 /* Copyright 2002-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * 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  
 import java.sql.PreparedStatement;
 19  
 import java.sql.ResultSet;
 20  
 import java.sql.SQLException;
 21  
 import java.util.ArrayList;
 22  
 import java.util.Collection;
 23  
 import java.util.Iterator;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.StringTokenizer;
 27  
 
 28  
 import org.apache.commons.collections.CollectionUtils;
 29  
 import org.apache.commons.collections.iterators.ArrayIterator;
 30  
 import org.apache.commons.collections.map.ReferenceIdentityMap;
 31  
 import org.apache.ojb.broker.Identity;
 32  
 import org.apache.ojb.broker.ManageableCollection;
 33  
 import org.apache.ojb.broker.MtoNImplementor;
 34  
 import org.apache.ojb.broker.OJBRuntimeException;
 35  
 import org.apache.ojb.broker.PBKey;
 36  
 import org.apache.ojb.broker.PersistenceBrokerException;
 37  
 import org.apache.ojb.broker.accesslayer.StatementManagerIF;
 38  
 import org.apache.ojb.broker.accesslayer.sql.SqlExistStatement;
 39  
 import org.apache.ojb.broker.core.PersistenceBrokerImpl;
 40  
 import org.apache.ojb.broker.core.ValueContainer;
 41  
 import org.apache.ojb.broker.core.proxy.IndirectionHandler;
 42  
 import org.apache.ojb.broker.core.proxy.ProxyHelper;
 43  
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 44  
 import org.apache.ojb.broker.metadata.CollectionDescriptor;
 45  
 import org.apache.ojb.broker.metadata.FieldDescriptor;
 46  
 import org.apache.ojb.broker.metadata.FieldHelper;
 47  
 import org.apache.ojb.broker.metadata.MetadataException;
 48  
 import org.apache.ojb.broker.metadata.MetadataManager;
 49  
 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
 50  
 import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
 51  
 import org.apache.ojb.broker.platforms.Platform;
 52  
 import org.apache.ojb.broker.query.Criteria;
 53  
 import org.apache.ojb.broker.query.MtoNQuery;
 54  
 import org.apache.ojb.broker.query.Query;
 55  
 import org.apache.ojb.broker.query.QueryByCriteria;
 56  
 import org.apache.ojb.broker.query.QueryBySQL;
 57  
 import org.apache.ojb.broker.query.ReportQueryByCriteria;
 58  
 import org.apache.ojb.broker.query.ReportQueryByMtoNCriteria;
 59  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 60  
 import org.apache.ojb.broker.util.sequence.SequenceManagerException;
 61  
 
 62  
 /**
 63  
  * This class contains helper methods primarily used by the {@link org.apache.ojb.broker.PersistenceBroker}
 64  
  * implementation (e.g. contains methods to assign the the values of 'autoincrement' fields).
 65  
  * <br/>
 66  
  * Furthermore it was used to introduce new features related to {@link org.apache.ojb.broker.PersistenceBroker} - these
 67  
  * new features and services (if they stand the test of time) will be moved to separate services in future.
 68  
  *
 69  
  * @author <a href="mailto:armin@codeAuLait.de">Armin Waibel</a>
 70  
  * @version $Id: BrokerHelper.java,v 1.1 2007-08-24 22:17:36 ewestfal Exp $
 71  
  */
 72  
 public class BrokerHelper
 73  
 {
 74  
     public static final String REPOSITORY_NAME_SEPARATOR = "#";
 75  
     private PersistenceBrokerImpl m_broker;
 76  
 
 77  
     public BrokerHelper(PersistenceBrokerImpl broker)
 78  
     {
 79  
         this.m_broker = broker;
 80  
     }
 81  
 
 82  
     /**
 83  
      * splits up the name string and extract db url,
 84  
      * user name and password and build a new PBKey
 85  
      * instance - the token '#' is used to separate
 86  
      * the substrings.
 87  
      * @throws PersistenceBrokerException if given name was <code>null</code>
 88  
      */
 89  
     public static PBKey extractAllTokens(String name)
 90  
     {
 91  
         if(name == null)
 92  
         {
 93  
             throw new PersistenceBrokerException("Could not extract PBKey, given argument is 'null'");
 94  
         }
 95  
         String user = null;
 96  
         String passwd = null;
 97  
         StringTokenizer tok = new StringTokenizer(name, REPOSITORY_NAME_SEPARATOR);
 98  
         String dbName = tok.nextToken();
 99  
         if(tok.hasMoreTokens())
 100  
         {
 101  
             user = tok.nextToken();
 102  
             if(user != null && user.trim().equals(""))
 103  
             {
 104  
                 user = null;
 105  
             }
 106  
         }
 107  
         if(tok.hasMoreTokens())
 108  
         {
 109  
             if(user != null)
 110  
                 passwd = tok.nextToken();
 111  
         }
 112  
         if(user != null && passwd == null)
 113  
         {
 114  
             passwd = "";
 115  
         }
 116  
         return new PBKey(dbName, user, passwd);
 117  
     }
 118  
 
 119  
     /**
 120  
      * Check if the user of the given PBKey was <code>null</code>, if so we try to
 121  
      * get user/password from the jdbc-connection-descriptor matching the given
 122  
      * PBKey.getAlias().
 123  
      */
 124  
     public static PBKey crossCheckPBKey(PBKey key)
 125  
     {
 126  
         if(key.getUser() == null)
 127  
         {
 128  
             PBKey defKey = MetadataManager.getInstance().connectionRepository().getStandardPBKeyForJcdAlias(key.getAlias());
 129  
             if(defKey != null)
 130  
             {
 131  
                 return defKey;
 132  
             }
 133  
         }
 134  
         return key;
 135  
     }
 136  
 
 137  
     /**
 138  
      * Answer the real ClassDescriptor for anObj
 139  
      * ie. aCld may be an Interface of anObj, so the cld for anObj is returned
 140  
      */
 141  
     private ClassDescriptor getRealClassDescriptor(ClassDescriptor aCld, Object anObj)
 142  
     {
 143  
         ClassDescriptor result;
 144  
 
 145  
         if(aCld.getClassOfObject() == ProxyHelper.getRealClass(anObj))
 146  
         {
 147  
             result = aCld;
 148  
         }
 149  
         else
 150  
         {
 151  
             result = aCld.getRepository().getDescriptorFor(anObj.getClass());
 152  
         }
 153  
 
 154  
         return result;
 155  
     }
 156  
 
 157  
     /**
 158  
      * Returns an Array with an Objects PK VALUES if convertToSql is true, any
 159  
      * associated java-to-sql conversions are applied. If the Object is a Proxy
 160  
      * or a VirtualProxy NO conversion is necessary.
 161  
      *
 162  
      * @param objectOrProxy
 163  
      * @param convertToSql
 164  
      * @return Object[]
 165  
      * @throws PersistenceBrokerException
 166  
      */
 167  
     public ValueContainer[] getKeyValues(ClassDescriptor cld, Object objectOrProxy, boolean convertToSql) throws PersistenceBrokerException
 168  
     {
 169  
         IndirectionHandler handler = ProxyHelper.getIndirectionHandler(objectOrProxy);
 170  
 
 171  
         if(handler != null)
 172  
         {
 173  
             return getKeyValues(cld, handler.getIdentity(), convertToSql);  //BRJ: convert Identity
 174  
         }
 175  
         else
 176  
         {
 177  
             ClassDescriptor realCld = getRealClassDescriptor(cld, objectOrProxy);
 178  
             return getValuesForObject(realCld.getPkFields(), objectOrProxy, convertToSql);
 179  
         }
 180  
     }
 181  
 
 182  
     /**
 183  
      * Return primary key values of given Identity object.
 184  
      *
 185  
      * @param cld
 186  
      * @param oid
 187  
      * @return Object[]
 188  
      * @throws PersistenceBrokerException
 189  
      */
 190  
     public ValueContainer[] getKeyValues(ClassDescriptor cld, Identity oid) throws PersistenceBrokerException
 191  
     {
 192  
         return getKeyValues(cld, oid, true);
 193  
     }
 194  
 
 195  
     /**
 196  
      * Return key Values of an Identity
 197  
      * @param cld
 198  
      * @param oid
 199  
      * @param convertToSql
 200  
      * @return Object[]
 201  
      * @throws PersistenceBrokerException
 202  
      */
 203  
     public ValueContainer[] getKeyValues(ClassDescriptor cld, Identity oid, boolean convertToSql) throws PersistenceBrokerException
 204  
     {
 205  
         FieldDescriptor[] pkFields = cld.getPkFields();
 206  
         ValueContainer[] result = new ValueContainer[pkFields.length];
 207  
         Object[] pkValues = oid.getPrimaryKeyValues();
 208  
 
 209  
         try
 210  
         {
 211  
             for(int i = 0; i < result.length; i++)
 212  
             {
 213  
                 FieldDescriptor fd = pkFields[i];
 214  
                 Object cv = pkValues[i];
 215  
                 if(convertToSql)
 216  
                 {
 217  
                     // BRJ : apply type and value mapping
 218  
                     cv = fd.getFieldConversion().javaToSql(cv);
 219  
                 }
 220  
                 result[i] = new ValueContainer(cv, fd.getJdbcType());
 221  
             }
 222  
         }
 223  
         catch(Exception e)
 224  
         {
 225  
             throw new PersistenceBrokerException("Can't generate primary key values for given Identity " + oid, e);
 226  
         }
 227  
         return result;
 228  
     }
 229  
 
 230  
     /**
 231  
      * returns an Array with an Objects PK VALUES, with any java-to-sql
 232  
      * FieldConversion applied. If the Object is a Proxy or a VirtualProxy NO
 233  
      * conversion is necessary.
 234  
      *
 235  
      * @param objectOrProxy
 236  
      * @return Object[]
 237  
      * @throws PersistenceBrokerException
 238  
      */
 239  
     public ValueContainer[] getKeyValues(ClassDescriptor cld, Object objectOrProxy) throws PersistenceBrokerException
 240  
     {
 241  
         return getKeyValues(cld, objectOrProxy, true);
 242  
     }
 243  
 
 244  
     /**
 245  
      * Decide if the given object value represents 'null'.<br/>
 246  
      *
 247  
      * - If given value is 'null' itself, true will be returned<br/>
 248  
      *
 249  
      * - If given value is instance of Number with value 0 and the field-descriptor
 250  
      * represents a primitive field, true will be returned<br/>
 251  
      *
 252  
      * - If given value is instance of String with length 0 and the field-descriptor
 253  
      * is a primary key, true will be returned<br/>
 254  
      */
 255  
     public boolean representsNull(FieldDescriptor fld, Object aValue)
 256  
     {
 257  
         if(aValue == null) return true;
 258  
 
 259  
         boolean result = false;
 260  
         if(((aValue instanceof Number) && (((Number) aValue).longValue() == 0)))
 261  
         {
 262  
             Class type = fld.getPersistentField().getType();
 263  
             /*
 264  
             AnonymousPersistentFields will *always* have a null type according to the
 265  
             javadoc comments in AnonymousPersistentField.getType() and never represents
 266  
             a primitve java field with value 0, thus we return always 'false' in this case.
 267  
             (If the value object is null, the first check above return true)
 268  
             */
 269  
             if(type != null)
 270  
             {
 271  
                 result = type.isPrimitive();
 272  
             }
 273  
         }
 274  
         // TODO: Do we need this check?? String could be nullified, why should we assume
 275  
         // it's 'null' on empty string?
 276  
         else if((aValue instanceof String) && (((String) aValue).length() == 0))
 277  
         {
 278  
             result = fld.isPrimaryKey();
 279  
         }
 280  
         return result;
 281  
     }
 282  
 
 283  
     /**
 284  
      * Detect if the given object has a PK field represents a 'null' value.
 285  
      */
 286  
     public boolean hasNullPKField(ClassDescriptor cld, Object obj)
 287  
     {
 288  
         FieldDescriptor[] fields = cld.getPkFields();
 289  
         boolean hasNull = false;
 290  
         // an unmaterialized proxy object can never have nullified PK's
 291  
         IndirectionHandler handler = ProxyHelper.getIndirectionHandler(obj);
 292  
         if(handler == null || handler.alreadyMaterialized())
 293  
         {
 294  
             if(handler != null) obj = handler.getRealSubject();
 295  
             FieldDescriptor fld;
 296  
             for(int i = 0; i < fields.length; i++)
 297  
             {
 298  
                 fld = fields[i];
 299  
                 hasNull = representsNull(fld, fld.getPersistentField().get(obj));
 300  
                 if(hasNull) break;
 301  
             }
 302  
         }
 303  
         return hasNull;
 304  
     }
 305  
 
 306  
     /**
 307  
      * Set an autoincremented value in given object field that has already
 308  
      * had a field conversion run on it, if an value for the given field is
 309  
      * already set, it will be overridden - no further checks are done.
 310  
      * <p>
 311  
      * The data type of the value that is returned by this method is
 312  
      * compatible with the java-world.  The return value has <b>NOT</b>
 313  
      * been run through a field conversion and converted to a corresponding
 314  
      * sql-type.
 315  
      *
 316  
      * @return the autoincremented value set on given object
 317  
      * @throws PersistenceBrokerException if there is an erros accessing obj field values
 318  
      */
 319  
     private Object setAutoIncrementValue(FieldDescriptor fd, Object obj)
 320  
     {
 321  
         PersistentField f = fd.getPersistentField();
 322  
         try
 323  
         {
 324  
             // lookup SeqMan for a value matching db column an
 325  
             Object result = m_broker.serviceSequenceManager().getUniqueValue(fd);
 326  
             // reflect autoincrement value back into object
 327  
             f.set(obj, result);
 328  
             return result;
 329  
         }
 330  
         catch(MetadataException e)
 331  
         {
 332  
             throw new PersistenceBrokerException(
 333  
                     "Error while trying to autoincrement field " + f.getDeclaringClass() + "#" + f.getName(),
 334  
                     e);
 335  
         }
 336  
         catch(SequenceManagerException e)
 337  
         {
 338  
             throw new PersistenceBrokerException("Could not get key value", e);
 339  
         }
 340  
     }
 341  
 
 342  
     /**
 343  
      * Get the values of the fields for an obj
 344  
      * Autoincrement values are automatically set.
 345  
      * @param fields
 346  
      * @param obj
 347  
      * @throws PersistenceBrokerException
 348  
      */
 349  
     public ValueContainer[] getValuesForObject(FieldDescriptor[] fields, Object obj, boolean convertToSql, boolean assignAutoincrement) throws PersistenceBrokerException
 350  
     {
 351  
         ValueContainer[] result = new ValueContainer[fields.length];
 352  
 
 353  
         for(int i = 0; i < fields.length; i++)
 354  
         {
 355  
             FieldDescriptor fd = fields[i];
 356  
             Object cv = fd.getPersistentField().get(obj);
 357  
 
 358  
             /*
 359  
             handle autoincrement attributes if
 360  
             - is a autoincrement field
 361  
             - field represents a 'null' value, is nullified
 362  
             and generate a new value
 363  
             */
 364  
             if(assignAutoincrement && fd.isAutoIncrement() && representsNull(fd, cv))
 365  
             {
 366  
                 /*
 367  
                 setAutoIncrementValue returns a value that is
 368  
                 properly typed for the java-world.  This value
 369  
                 needs to be converted to it's corresponding
 370  
                 sql type so that the entire result array contains
 371  
                 objects that are properly typed for sql.
 372  
                 */
 373  
                 cv = setAutoIncrementValue(fd, obj);
 374  
             }
 375  
             if(convertToSql)
 376  
             {
 377  
                 // apply type and value conversion
 378  
                 cv = fd.getFieldConversion().javaToSql(cv);
 379  
             }
 380  
             // create ValueContainer
 381  
             result[i] = new ValueContainer(cv, fd.getJdbcType());
 382  
         }
 383  
         return result;
 384  
     }
 385  
 
 386  
     public ValueContainer[] getValuesForObject(FieldDescriptor[] fields, Object obj, boolean convertToSql) throws PersistenceBrokerException
 387  
     {
 388  
         return getValuesForObject(fields, obj, convertToSql, false);
 389  
     }
 390  
 
 391  
     /**
 392  
      * Returns an array containing values for all non PK field READ/WRITE attributes of the object
 393  
      * based on the specified {@link org.apache.ojb.broker.metadata.ClassDescriptor}.
 394  
      * <br/>
 395  
      * NOTE: This method doesn't do any checks on the specified {@link org.apache.ojb.broker.metadata.ClassDescriptor}
 396  
      * the caller is reponsible to pass a valid descriptor.
 397  
      *
 398  
      * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} to extract the RW-fields
 399  
      * @param obj The object with target fields to extract.
 400  
      * @throws MetadataException if there is an erros accessing obj field values
 401  
      */
 402  
     public ValueContainer[] getNonKeyRwValues(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
 403  
     {
 404  
         return getValuesForObject(cld.getNonPkRwFields(), obj, true);
 405  
     }
 406  
 
 407  
     /**
 408  
      * Returns an array containing values for all READ/WRITE attributes of the object
 409  
      * based on the specified {@link org.apache.ojb.broker.metadata.ClassDescriptor}.
 410  
      * <br/>
 411  
      * NOTE: This method doesn't do any checks on the specified {@link org.apache.ojb.broker.metadata.ClassDescriptor}
 412  
      * the caller is reponsible to pass a valid descriptor.
 413  
      *
 414  
      * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} to extract the RW-fields
 415  
      * @param obj The object with target fields to extract.
 416  
      * @throws MetadataException if there is an erros accessing obj field values
 417  
      */
 418  
     public ValueContainer[] getAllRwValues(ClassDescriptor cld, Object obj) throws PersistenceBrokerException
 419  
     {
 420  
         return getValuesForObject(cld.getAllRwFields(), obj, true);
 421  
     }
 422  
 
 423  
     /**
 424  
      * Extract an value array of the given {@link ValueContainer} array.
 425  
      * @param containers
 426  
      * @return An object array
 427  
      */
 428  
     public Object[] extractValueArray(ValueContainer[] containers)
 429  
     {
 430  
         Object[] result = new Object[containers.length];
 431  
         for(int i = 0; i < containers.length; i++)
 432  
         {
 433  
             result[i] = containers[i].getValue();
 434  
         }
 435  
         return result;
 436  
     }
 437  
 
 438  
     /**
 439  
      * returns true if the primary key fields are valid for store, else false.
 440  
      * PK fields are valid if each of them is either an OJB managed
 441  
      * attribute (autoincrement or locking) or if it contains
 442  
      * a valid non-null value
 443  
      * @param fieldDescriptors the array of PK fielddescriptors
 444  
      * @param pkValues the array of PK values
 445  
      * @return boolean
 446  
      */
 447  
     public boolean assertValidPksForStore(FieldDescriptor[] fieldDescriptors, Object[] pkValues)
 448  
     {
 449  
         int fieldDescriptorSize = fieldDescriptors.length;
 450  
         for(int i = 0; i < fieldDescriptorSize; i++)
 451  
         {
 452  
             FieldDescriptor fld = fieldDescriptors[i];
 453  
             /**
 454  
              * a pk field is valid if it is either managed by OJB
 455  
              * (autoincrement or locking) or if it does contain a
 456  
              * valid non-null value.
 457  
              */
 458  
             if(!(fld.isAutoIncrement()
 459  
                     || fld.isLocking()
 460  
                     || !representsNull(fld, pkValues[i])))
 461  
             {
 462  
                 return false;
 463  
             }
 464  
         }
 465  
         return true;
 466  
     }
 467  
 
 468  
     /**
 469  
      * returns true if the primary key fields are valid for delete, else false.
 470  
      * PK fields are valid if each of them contains a valid non-null value
 471  
      * @param cld the ClassDescriptor
 472  
      * @param obj the object
 473  
      * @return boolean
 474  
      */
 475  
     public boolean assertValidPkForDelete(ClassDescriptor cld, Object obj)
 476  
     {
 477  
         if(!ProxyHelper.isProxy(obj))
 478  
         {
 479  
             FieldDescriptor fieldDescriptors[] = cld.getPkFields();
 480  
             int fieldDescriptorSize = fieldDescriptors.length;
 481  
             for(int i = 0; i < fieldDescriptorSize; i++)
 482  
             {
 483  
                 FieldDescriptor fd = fieldDescriptors[i];
 484  
                 Object pkValue = fd.getPersistentField().get(obj);
 485  
                 if (representsNull(fd, pkValue))
 486  
                 {
 487  
                     return false;
 488  
                 }
 489  
             }
 490  
         }
 491  
         return true;
 492  
     }
 493  
 
 494  
     /**
 495  
      * Build a Count-Query based on aQuery
 496  
      * @param aQuery
 497  
      * @return The count query
 498  
      */
 499  
     public Query getCountQuery(Query aQuery)
 500  
     {
 501  
         if(aQuery instanceof QueryBySQL)
 502  
         {
 503  
             return getQueryBySqlCount((QueryBySQL) aQuery);
 504  
         }
 505  
         else if(aQuery instanceof ReportQueryByCriteria)
 506  
         {
 507  
             return getReportQueryByCriteriaCount((ReportQueryByCriteria) aQuery);
 508  
         }
 509  
         else
 510  
         {
 511  
             return getQueryByCriteriaCount((QueryByCriteria) aQuery);
 512  
         }
 513  
     }
 514  
 
 515  
     /**
 516  
      * Create a Count-Query for QueryBySQL
 517  
      *
 518  
      * @param aQuery
 519  
      * @return The count query
 520  
      */
 521  
     private Query getQueryBySqlCount(QueryBySQL aQuery)
 522  
     {
 523  
         String countSql = aQuery.getSql();
 524  
 
 525  
         int fromPos = countSql.toUpperCase().indexOf(" FROM ");
 526  
         if(fromPos >= 0)
 527  
         {
 528  
             countSql = "select count(*)" + countSql.substring(fromPos);
 529  
         }
 530  
 
 531  
         int orderPos = countSql.toUpperCase().indexOf(" ORDER BY ");
 532  
         if(orderPos >= 0)
 533  
         {
 534  
             countSql = countSql.substring(0, orderPos);
 535  
         }
 536  
 
 537  
         return new QueryBySQL(aQuery.getSearchClass(), countSql);
 538  
     }
 539  
 
 540  
     /**
 541  
      * Create a Count-Query for QueryByCriteria
 542  
      */
 543  
     private Query getQueryByCriteriaCount(QueryByCriteria aQuery)
 544  
     {
 545  
         Class                 searchClass = aQuery.getSearchClass();
 546  
         ReportQueryByCriteria countQuery  = null;
 547  
         Criteria              countCrit   = null;
 548  
         String[]              columns     = new String[1];
 549  
 
 550  
         // BRJ: copied Criteria without groupby, orderby, and prefetched relationships
 551  
         if (aQuery.getCriteria() != null)
 552  
         {
 553  
             countCrit = aQuery.getCriteria().copy(false, false, false);
 554  
         }
 555  
 
 556  
         if (aQuery.isDistinct())
 557  
         {
 558  
             // BRJ: Count distinct is dbms dependent
 559  
             // hsql/sapdb: select count (distinct(person_id || project_id)) from person_project
 560  
             // mysql: select count (distinct person_id,project_id) from person_project
 561  
             // [tomdz]
 562  
             // Some databases have no support for multi-column count distinct (e.g. Derby)
 563  
             // Here we use a SELECT count(*) FROM (SELECT DISTINCT ...) instead 
 564  
             //
 565  
             // concatenation of pk-columns is a simple way to obtain a single column
 566  
             // but concatenation is also dbms dependent:
 567  
             //
 568  
             // SELECT count(distinct concat(row1, row2, row3)) mysql
 569  
             // SELECT count(distinct (row1 || row2 || row3)) ansi
 570  
             // SELECT count(distinct (row1 + row2 + row3)) ms sql-server
 571  
 
 572  
             FieldDescriptor[] pkFields   = m_broker.getClassDescriptor(searchClass).getPkFields();
 573  
             String[]          keyColumns = new String[pkFields.length];
 574  
 
 575  
             if (pkFields.length > 1)
 576  
             {
 577  
                 // TODO: Use ColumnName. This is a temporary solution because
 578  
                 // we cannot yet resolve multiple columns in the same attribute.
 579  
                 for (int idx = 0; idx < pkFields.length; idx++)
 580  
                 {
 581  
                     keyColumns[idx] = pkFields[idx].getColumnName();
 582  
                 }
 583  
             }
 584  
             else
 585  
             {
 586  
                 for (int idx = 0; idx < pkFields.length; idx++)
 587  
                 {
 588  
                     keyColumns[idx] = pkFields[idx].getAttributeName();
 589  
                 }
 590  
             }
 591  
             // [tomdz]
 592  
             // TODO: Add support for databases that do not support COUNT DISTINCT over multiple columns
 593  
 //            if (getPlatform().supportsMultiColumnCountDistinct())
 594  
 //            {
 595  
 //                columns[0] = "count(distinct " + getPlatform().concatenate(keyColumns) + ")";
 596  
 //            }
 597  
 //            else
 598  
 //            {
 599  
 //                columns = keyColumns;
 600  
 //            }
 601  
 
 602  
             columns[0] = "count(distinct " + getPlatform().concatenate(keyColumns) + ")";
 603  
         }
 604  
         else
 605  
         {
 606  
             columns[0] = "count(*)";
 607  
         }
 608  
 
 609  
         // BRJ: we have to preserve indirection table !
 610  
         if (aQuery instanceof MtoNQuery)
 611  
         {
 612  
             MtoNQuery                 mnQuery       = (MtoNQuery)aQuery;
 613  
             ReportQueryByMtoNCriteria mnReportQuery = new ReportQueryByMtoNCriteria(searchClass, columns, countCrit);
 614  
 
 615  
             mnReportQuery.setIndirectionTable(mnQuery.getIndirectionTable());
 616  
             countQuery = mnReportQuery;
 617  
         }
 618  
         else
 619  
         {
 620  
             countQuery = new ReportQueryByCriteria(searchClass, columns, countCrit);
 621  
         }
 622  
 
 623  
         // BRJ: we have to preserve outer-join-settings (by Andr� Markwalder)
 624  
         for (Iterator outerJoinPath = aQuery.getOuterJoinPaths().iterator(); outerJoinPath.hasNext();)
 625  
         {
 626  
             String path = (String) outerJoinPath.next();
 627  
 
 628  
             if (aQuery.isPathOuterJoin(path))
 629  
             {
 630  
                 countQuery.setPathOuterJoin(path);
 631  
             }
 632  
         }
 633  
 
 634  
         //BRJ: add orderBy Columns asJoinAttributes
 635  
         List orderBy = aQuery.getOrderBy();
 636  
 
 637  
         if ((orderBy != null) && !orderBy.isEmpty())
 638  
         {
 639  
             String[] joinAttributes = new String[orderBy.size()];
 640  
 
 641  
             for (int idx = 0; idx < orderBy.size(); idx++)
 642  
             {
 643  
                 joinAttributes[idx] = ((FieldHelper)orderBy.get(idx)).name;
 644  
             }
 645  
             countQuery.setJoinAttributes(joinAttributes);
 646  
         }
 647  
 
 648  
         // [tomdz]
 649  
         // TODO:
 650  
         // For those databases that do not support COUNT DISTINCT over multiple columns
 651  
         // we wrap the normal SELECT DISTINCT that we just created, into a SELECT count(*)
 652  
         // For this however we need a report query that gets its data from a sub query instead
 653  
         // of a table (target class)
 654  
 //        if (aQuery.isDistinct() && !getPlatform().supportsMultiColumnCountDistinct())
 655  
 //        {
 656  
 //        }
 657  
 
 658  
         return countQuery;
 659  
     }
 660  
 
 661  
     /**
 662  
      * Create a Count-Query for ReportQueryByCriteria
 663  
      */
 664  
     private Query getReportQueryByCriteriaCount(ReportQueryByCriteria aQuery)
 665  
     {
 666  
         ReportQueryByCriteria countQuery = (ReportQueryByCriteria) getQueryByCriteriaCount(aQuery);
 667  
 
 668  
         // BRJ: keep the original columns to build the Join
 669  
         countQuery.setJoinAttributes(aQuery.getAttributes());
 670  
 
 671  
         // BRJ: we have to preserve groupby information
 672  
         Iterator iter = aQuery.getGroupBy().iterator();
 673  
         while(iter.hasNext())
 674  
         {
 675  
             countQuery.addGroupBy((FieldHelper) iter.next());
 676  
         }
 677  
 
 678  
         return countQuery;
 679  
     }
 680  
 
 681  
     /**
 682  
      * answer the platform
 683  
      *
 684  
      * @return the platform
 685  
      */
 686  
     private Platform getPlatform()
 687  
     {
 688  
         return m_broker.serviceSqlGenerator().getPlatform();
 689  
     }
 690  
 
 691  
 
 692  
     /*
 693  
     NOTE: use weak key references to allow reclaiming
 694  
     of no longer used ClassDescriptor instances
 695  
     */
 696  
     private Map sqlSelectMap = new ReferenceIdentityMap(ReferenceIdentityMap.WEAK, ReferenceIdentityMap.HARD);
 697  
     /**
 698  
      * TODO: This method should be moved to {@link org.apache.ojb.broker.accesslayer.JdbcAccess}
 699  
      * before 1.1 release.
 700  
      *
 701  
      * This method checks if the requested object can be
 702  
      * found in database (without object materialization).
 703  
      *
 704  
      * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the
 705  
      * object/{@link org.apache.ojb.broker.Identity} to check.
 706  
      * @param obj The <em>object</em> to check.
 707  
      * @param oid The associated {@link org.apache.ojb.broker.Identity}.
 708  
      * {@link org.apache.ojb.broker.Identity} of the object
 709  
      * @return Return <em>true</em> if the object is already persisted, <em>false</em> if the object is transient.
 710  
      */
 711  
     public boolean doesExist(ClassDescriptor cld, Identity oid, Object obj)
 712  
     {
 713  
         boolean result = false;
 714  
         String sql = (String) sqlSelectMap.get(cld);
 715  
         if(sql == null)
 716  
         {
 717  
             sql = new SqlExistStatement(cld, LoggerFactory.getDefaultLogger()).getStatement();
 718  
             sqlSelectMap.put(cld, sql);
 719  
         }
 720  
         ValueContainer[] pkValues;
 721  
         if(oid == null)
 722  
         {
 723  
             pkValues = getKeyValues(cld, obj, true);
 724  
         }
 725  
         else
 726  
         {
 727  
             pkValues = getKeyValues(cld, oid);
 728  
         }
 729  
         StatementManagerIF sm = m_broker.serviceStatementManager();
 730  
         PreparedStatement stmt = null;
 731  
         ResultSet rs = null;
 732  
         try
 733  
         {
 734  
             stmt = sm.getPreparedStatement(cld, sql, false, 1, false);
 735  
             sm.bindValues(stmt, pkValues, 1);
 736  
             rs = stmt.executeQuery();
 737  
             result = rs.next();
 738  
         }
 739  
         catch(SQLException e)
 740  
         {
 741  
             throw ExceptionHelper.generateException("[BrokerHelper#doesExist] Can't check if specified" +
 742  
                     " object is already persisted", e, sql, cld, pkValues, null, obj);
 743  
         }
 744  
         finally
 745  
         {
 746  
             sm.closeResources(stmt, rs);
 747  
         }
 748  
 
 749  
         return result;
 750  
     }
 751  
 
 752  
     /**
 753  
      * This method concatenate the main object with all reference
 754  
      * objects (1:1, 1:n and m:n) by hand. This method is needed when
 755  
      * in the reference metadata definitions the auto-xxx setting was disabled.
 756  
      * More info see OJB doc.
 757  
      */
 758  
     public void link(Object obj, boolean insert)
 759  
     {
 760  
         linkOrUnlink(true, obj, insert);
 761  
     }
 762  
 
 763  
     /**
 764  
      * Unlink all references from this object.
 765  
      * More info see OJB doc.
 766  
      * @param obj Object with reference
 767  
      */
 768  
     public void unlink(Object obj)
 769  
     {
 770  
         linkOrUnlink(false, obj, false);
 771  
     }
 772  
 
 773  
     private void linkOrUnlink(boolean doLink, Object obj, boolean insert)
 774  
     {
 775  
         ClassDescriptor cld = m_broker.getDescriptorRepository().getDescriptorFor(obj.getClass());
 776  
 
 777  
         if (cld.getObjectReferenceDescriptors().size() > 0)
 778  
         {
 779  
             // never returns null, thus we can direct call iterator
 780  
             Iterator descriptors = cld.getObjectReferenceDescriptors().iterator();
 781  
             while (descriptors.hasNext())
 782  
             {
 783  
                 ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptors.next();
 784  
                 linkOrUnlinkOneToOne(doLink, obj, ord, insert);
 785  
             }
 786  
         }
 787  
         if (cld.getCollectionDescriptors().size() > 0)
 788  
         {
 789  
             // never returns null, thus we can direct call iterator
 790  
             Iterator descriptors = cld.getCollectionDescriptors().iterator();
 791  
             while (descriptors.hasNext())
 792  
             {
 793  
                 CollectionDescriptor cod = (CollectionDescriptor) descriptors.next();
 794  
                 linkOrUnlinkXToMany(doLink, obj, cod, insert);
 795  
             }
 796  
         }
 797  
     }
 798  
 
 799  
     /**
 800  
      * This method concatenate the main object and the specified reference
 801  
      * object (1:1 reference a referenced object, 1:n and m:n reference a
 802  
      * collection of referenced objects) by hand. This method is needed when
 803  
      * in the reference metadata definitions the auto-xxx setting was disabled.
 804  
      * More info see OJB doc.
 805  
      *
 806  
      * @param obj Object with reference
 807  
      * @param ord the ObjectReferenceDescriptor of the reference
 808  
      * @param insert flag signals insert operation
 809  
      */
 810  
     public void link(Object obj, ObjectReferenceDescriptor ord, boolean insert)
 811  
     {
 812  
        linkOrUnlink(true, obj, ord, insert);
 813  
     }
 814  
 
 815  
     /**
 816  
      * This method concatenate the main object and the specified reference
 817  
      * object (1:1 reference a referenced object, 1:n and m:n reference a
 818  
      * collection of referenced objects) by hand. This method is needed when
 819  
      * in the reference metadata definitions the auto-xxx setting was disabled.
 820  
      * More info see OJB doc.
 821  
      *
 822  
      * @param obj Object with reference
 823  
      * @param attributeName field name of the reference
 824  
      * @param insert flag signals insert operation
 825  
      * @return true if the specified reference was found and linking was successful
 826  
      */
 827  
     public boolean link(Object obj, String attributeName, boolean insert)
 828  
     {
 829  
        return linkOrUnlink(true, obj, attributeName, insert);
 830  
     }
 831  
 
 832  
     /**
 833  
      * This method concatenate the main object and the specified reference
 834  
      * object (1:1 reference a referenced object, 1:n and m:n reference a
 835  
      * collection of referenced objects) by hand. This method is needed when
 836  
      * in the reference metadata definitions the auto-xxx setting was disabled.
 837  
      * More info see OJB doc.
 838  
      *
 839  
      * @param obj Object with reference
 840  
      * @param attributeName field name of the reference
 841  
      * @param reference The referenced object
 842  
      * @param insert flag signals insert operation
 843  
      * @return true if the specified reference was found and linking was successful
 844  
      */
 845  
     public boolean link(Object obj, String attributeName, Object reference, boolean insert)
 846  
     {
 847  
         ClassDescriptor cld = m_broker.getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(obj));
 848  
         ObjectReferenceDescriptor ord;
 849  
         boolean match = false;
 850  
         // first look for reference then for collection
 851  
         ord = cld.getObjectReferenceDescriptorByName(attributeName);
 852  
         if (ord != null)
 853  
         {
 854  
             linkOrUnlinkOneToOne(true, obj, ord, insert);
 855  
             match = true;
 856  
         }
 857  
         else
 858  
         {
 859  
             CollectionDescriptor cod = cld.getCollectionDescriptorByName(attributeName);
 860  
             if (cod != null)
 861  
             {
 862  
                 linkOrUnlinkXToMany(true, obj, cod, insert);
 863  
                 match = true;
 864  
             }
 865  
         }
 866  
         return match;
 867  
     }
 868  
 
 869  
     /**
 870  
      * Unlink the specified reference object.
 871  
      * More info see OJB doc.
 872  
      * @param source The source object with the specified reference field.
 873  
      * @param attributeName The field name of the reference to unlink.
 874  
      * @param target The referenced object to unlink.
 875  
      */
 876  
     public boolean unlink(Object source, String attributeName, Object target)
 877  
     {
 878  
         return linkOrUnlink(false, source, attributeName, false);
 879  
     }
 880  
 
 881  
     /**
 882  
      * Unlink all referenced objects of the specified field.
 883  
      * More info see OJB doc.
 884  
      * @param source The source object with the specified reference.
 885  
      * @param attributeName The field name of the reference to unlink.
 886  
      */
 887  
     public boolean unlink(Object source, String attributeName)
 888  
     {
 889  
         return linkOrUnlink(false, source, attributeName, false);
 890  
     }
 891  
 
 892  
     /**
 893  
      * Unlink the specified reference from this object.
 894  
      * More info see OJB doc.
 895  
      *
 896  
      * @param obj Object with reference
 897  
      * @param ord the ObjectReferenceDescriptor of the reference
 898  
      * @param insert flag signals insert operation
 899  
      */
 900  
     public void unlink(Object obj, ObjectReferenceDescriptor ord, boolean insert)
 901  
     {
 902  
        linkOrUnlink(false, obj, ord, insert);
 903  
     }
 904  
 
 905  
     private boolean linkOrUnlink(boolean doLink, Object obj, String attributeName, boolean insert)
 906  
     {
 907  
         boolean match = false;
 908  
         ClassDescriptor cld = m_broker.getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(obj));
 909  
         ObjectReferenceDescriptor ord;
 910  
 
 911  
         // first look for reference then for collection
 912  
         ord = cld.getObjectReferenceDescriptorByName(attributeName);
 913  
         if (ord != null)
 914  
         {
 915  
             linkOrUnlinkOneToOne(doLink, obj, ord, insert);
 916  
             match = true;
 917  
         }
 918  
         else
 919  
         {
 920  
             CollectionDescriptor cod = cld.getCollectionDescriptorByName(attributeName);
 921  
             if (cod != null)
 922  
             {
 923  
                 linkOrUnlinkXToMany(doLink, obj, cod, insert);
 924  
                 match = true;
 925  
             }
 926  
         }
 927  
 
 928  
         return match;
 929  
     }
 930  
 
 931  
     private void linkOrUnlink(boolean doLink, Object obj, ObjectReferenceDescriptor ord, boolean insert)
 932  
     {
 933  
         if (ord instanceof CollectionDescriptor)
 934  
         {
 935  
             linkOrUnlinkXToMany(doLink, obj, (CollectionDescriptor) ord, insert);
 936  
         }
 937  
         else
 938  
         {
 939  
             linkOrUnlinkOneToOne(doLink, obj, ord, insert);
 940  
         }
 941  
     }
 942  
 
 943  
     private void linkOrUnlinkXToMany(boolean doLink, Object obj, CollectionDescriptor cod, boolean insert)
 944  
     {
 945  
         if (doLink)
 946  
         {
 947  
             if (cod.isMtoNRelation())
 948  
             {
 949  
                 m_broker.linkMtoN(obj, cod, insert);
 950  
             }
 951  
             else
 952  
             {
 953  
                 m_broker.linkOneToMany(obj, cod, insert);
 954  
             }
 955  
         }
 956  
         else
 957  
         {
 958  
             m_broker.unlinkXtoN(obj, cod);
 959  
         }
 960  
     }
 961  
 
 962  
     private void linkOrUnlinkOneToOne(boolean doLink, Object obj, ObjectReferenceDescriptor ord, boolean insert)
 963  
     {
 964  
         /*
 965  
         arminw: we need the class-descriptor where the reference is declared, thus we ask the
 966  
         reference-descriptor for this, instead of using the class-descriptor of the specified
 967  
         object. If the reference was declared within an interface (should never happen) we
 968  
         only can use the descriptor of the real class.
 969  
         */
 970  
         ClassDescriptor cld = ord.getClassDescriptor();
 971  
         if(cld.isInterface())
 972  
         {
 973  
             cld = m_broker.getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(obj));
 974  
         }
 975  
 
 976  
         if (doLink)
 977  
         {
 978  
             m_broker.linkOneToOne(obj, cld, ord, insert);
 979  
         }
 980  
         else
 981  
         {
 982  
             m_broker.unlinkFK(obj, cld, ord);
 983  
             // in 1:1 relation we have to set relation to null
 984  
             ord.getPersistentField().set(obj, null);
 985  
         }
 986  
     }
 987  
 
 988  
     /**
 989  
      * Unlink a bunch of 1:n or m:n objects.
 990  
      *
 991  
      * @param source The source object with reference.
 992  
      * @param cds The {@link org.apache.ojb.broker.metadata.CollectionDescriptor} of the relation.
 993  
      * @param referencesToUnlink List of referenced objects to unlink.
 994  
      */
 995  
     public void unlink(Object source, CollectionDescriptor cds, List referencesToUnlink)
 996  
     {
 997  
         for(int i = 0; i < referencesToUnlink.size(); i++)
 998  
         {
 999  
             unlink(source, cds, referencesToUnlink.get(i));
 1000  
         }
 1001  
     }
 1002  
 
 1003  
     /**
 1004  
      * Unlink a single 1:n or m:n object.
 1005  
      *
 1006  
      * @param source The source object with reference.
 1007  
      * @param cds The {@link org.apache.ojb.broker.metadata.CollectionDescriptor} of the relation.
 1008  
      * @param referenceToUnlink The referenced object to link.
 1009  
      */
 1010  
     public void unlink(Object source, CollectionDescriptor cds, Object referenceToUnlink)
 1011  
     {
 1012  
         if(cds.isMtoNRelation())
 1013  
         {
 1014  
             m_broker.deleteMtoNImplementor(new MtoNImplementor(cds, source, referenceToUnlink));
 1015  
         }
 1016  
         else
 1017  
         {
 1018  
             ClassDescriptor cld = m_broker.getClassDescriptor(referenceToUnlink.getClass());
 1019  
             m_broker.unlinkFK(referenceToUnlink, cld, cds);
 1020  
         }
 1021  
     }
 1022  
 
 1023  
     /**
 1024  
      * Link a bunch of 1:n or m:n objects.
 1025  
      *
 1026  
      * @param source The source object with reference.
 1027  
      * @param cds The {@link org.apache.ojb.broker.metadata.CollectionDescriptor} of the relation.
 1028  
      * @param referencesToLink List of referenced objects to link.
 1029  
      */
 1030  
     public void link(Object source, CollectionDescriptor cds, List referencesToLink)
 1031  
     {
 1032  
         for(int i = 0; i < referencesToLink.size(); i++)
 1033  
         {
 1034  
             link(source, cds, referencesToLink.get(i));
 1035  
         }
 1036  
     }
 1037  
 
 1038  
     /**
 1039  
      * Link a single 1:n or m:n object.
 1040  
      *
 1041  
      * @param source The source object with the declared reference.
 1042  
      * @param cds The {@link org.apache.ojb.broker.metadata.CollectionDescriptor} of the relation declared in source object.
 1043  
      * @param referenceToLink The referenced object to link.
 1044  
      */
 1045  
     public void link(Object source, CollectionDescriptor cds, Object referenceToLink)
 1046  
     {
 1047  
         if(cds.isMtoNRelation())
 1048  
         {
 1049  
             m_broker.addMtoNImplementor(new MtoNImplementor(cds, source, referenceToLink));
 1050  
         }
 1051  
         else
 1052  
         {
 1053  
             ClassDescriptor cld = m_broker.getClassDescriptor(referenceToLink.getClass());
 1054  
             m_broker.link(referenceToLink, cld, cds, source, false);
 1055  
         }
 1056  
     }
 1057  
 
 1058  
     /**
 1059  
      * Returns an Iterator instance for {@link java.util.Collection}, object Array or
 1060  
      * {@link org.apache.ojb.broker.ManageableCollection} instances.
 1061  
      *
 1062  
      * @param collectionOrArray a none <em>null</em> object of type {@link java.util.Collection},
 1063  
      * Array or {@link org.apache.ojb.broker.ManageableCollection}.
 1064  
      * @return Iterator able to handle given collection object
 1065  
      */
 1066  
     public static Iterator getCollectionIterator(Object collectionOrArray)
 1067  
     {
 1068  
         Iterator colIterator;
 1069  
         if (collectionOrArray instanceof ManageableCollection)
 1070  
         {
 1071  
             colIterator = ((ManageableCollection) collectionOrArray).ojbIterator();
 1072  
         }
 1073  
         else if (collectionOrArray instanceof Collection)
 1074  
         {
 1075  
             colIterator = ((Collection) collectionOrArray).iterator();
 1076  
         }
 1077  
         else if (collectionOrArray.getClass().isArray())
 1078  
         {
 1079  
             colIterator = new ArrayIterator(collectionOrArray);
 1080  
         }
 1081  
         else
 1082  
         {
 1083  
             throw new OJBRuntimeException( "Given object collection of type '"
 1084  
                     + (collectionOrArray != null ? collectionOrArray.getClass().toString() : "null")
 1085  
                 + "' can not be managed by OJB. Use Array, Collection or ManageableCollection instead!");
 1086  
         }
 1087  
         return colIterator;
 1088  
     }
 1089  
 
 1090  
     /**
 1091  
      * Returns an object array for {@link java.util.Collection}, array or
 1092  
      * {@link org.apache.ojb.broker.ManageableCollection} instances.
 1093  
      *
 1094  
      * @param collectionOrArray a none <em>null</em> object of type {@link java.util.Collection},
 1095  
      * Array or {@link org.apache.ojb.broker.ManageableCollection}.
 1096  
      * @return Object array able to handle given collection or array object
 1097  
      */
 1098  
     public static Object[] getCollectionArray(Object collectionOrArray)
 1099  
     {
 1100  
         Object[] result;
 1101  
         if (collectionOrArray instanceof Collection)
 1102  
         {
 1103  
             result = ((Collection) collectionOrArray).toArray();
 1104  
         }
 1105  
         else if (collectionOrArray instanceof ManageableCollection)
 1106  
         {
 1107  
             Collection newCol = new ArrayList();
 1108  
             CollectionUtils.addAll(newCol, ((ManageableCollection) collectionOrArray).ojbIterator());
 1109  
             result = newCol.toArray();
 1110  
         }
 1111  
         else if (collectionOrArray.getClass().isArray())
 1112  
         {
 1113  
             result = (Object[]) collectionOrArray;
 1114  
         }
 1115  
         else
 1116  
         {
 1117  
             throw new OJBRuntimeException( "Given object collection of type '"
 1118  
                     + (collectionOrArray != null ? collectionOrArray.getClass().toString() : "null")
 1119  
                 + "' can not be managed by OJB. Use Array, Collection or ManageableCollection instead!");
 1120  
         }
 1121  
         return result;
 1122  
     }
 1123  
 
 1124  
     /**
 1125  
      * Returns <em>true</em> if one or more anonymous FK fields are used.
 1126  
      * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the main object.
 1127  
      * @param rds The {@link org.apache.ojb.broker.metadata.ObjectReferenceDescriptor} of the referenced object.
 1128  
      * @return <em>true</em> if one or more anonymous FK fields are used for specified reference.
 1129  
      */
 1130  
     public static boolean hasAnonymousKeyReference(ClassDescriptor cld, ObjectReferenceDescriptor rds)
 1131  
     {
 1132  
         boolean result = false;
 1133  
         FieldDescriptor[] fkFields = rds.getForeignKeyFieldDescriptors(cld);
 1134  
         for(int i = 0; i < fkFields.length; i++)
 1135  
         {
 1136  
             FieldDescriptor fkField = fkFields[i];
 1137  
             if(fkField.isAnonymous())
 1138  
             {
 1139  
                 result = true;
 1140  
                 break;
 1141  
             }
 1142  
         }
 1143  
         return result;
 1144  
     }
 1145  
 
 1146  
 //    /**
 1147  
 //     * Use this method to extract the {@link org.apache.ojb.broker.metadata.ClassDescriptor} where
 1148  
 //     * the {@link org.apache.ojb.broker.metadata.ObjectReferenceDescriptor reference} is declared.
 1149  
 //     * It's possible that the reference is declared in a super-class.
 1150  
 //     * @param broker
 1151  
 //     * @param reference
 1152  
 //     * @param source
 1153  
 //     * @return
 1154  
 //     */
 1155  
 //    public static ClassDescriptor extractDescriptorForReference(PersistenceBroker broker, ObjectReferenceDescriptor reference, Object source)
 1156  
 //    {
 1157  
 //        /*
 1158  
 //        arminw: we need the class-descriptor where the reference is declared, thus we ask the
 1159  
 //        reference-descriptor for this, instead of using the class-descriptor of the specified
 1160  
 //        object. If the reference was declared within an interface (should never happen) we
 1161  
 //        only can use the descriptor of the real class.
 1162  
 //        */
 1163  
 //        ClassDescriptor cld = reference.getClassDescriptor();
 1164  
 //        if(cld.isInterface())
 1165  
 //        {
 1166  
 //            cld = broker.getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(source));
 1167  
 //        }
 1168  
 //        return cld;
 1169  
 //    }
 1170  
 
 1171  
 //    /**
 1172  
 //     * Returns a {@link java.util.List} instance of the specified object in method argument,
 1173  
 //     * in which the argument must be of type {@link java.util.Collection}, array or
 1174  
 //     * {@link org.apache.ojb.broker.ManageableCollection}.
 1175  
 //     *
 1176  
 //     * @param collectionOrArray a none <em>null</em> object of type {@link java.util.Collection},
 1177  
 //     * Array or {@link org.apache.ojb.broker.ManageableCollection}.
 1178  
 //     * @return Object array able to handle given collection or array object
 1179  
 //     */
 1180  
 //    public static List getCollectionList(Object collectionOrArray)
 1181  
 //    {
 1182  
 //        List result = null;
 1183  
 //        if (collectionOrArray instanceof Collection)
 1184  
 //        {
 1185  
 //            result = ((Collection) collectionOrArray).toArray();
 1186  
 //        }
 1187  
 //        else if (collectionOrArray instanceof ManageableCollection)
 1188  
 //        {
 1189  
 //            Collection newCol = new ArrayList();
 1190  
 //            CollectionUtils.addAll(newCol, ((ManageableCollection) collectionOrArray).ojbIterator());
 1191  
 //            result = newCol.toArray();
 1192  
 //        }
 1193  
 //        else if (collectionOrArray.getClass().isArray())
 1194  
 //        {
 1195  
 //            result = (Object[]) collectionOrArray;
 1196  
 //        }
 1197  
 //        else
 1198  
 //        {
 1199  
 //            throw new OJBRuntimeException( "Given object collection of type '"
 1200  
 //                    + (collectionOrArray != null ? collectionOrArray.getClass().toString() : "null")
 1201  
 //                + "' can not be managed by OJB. Use Array, Collection or ManageableCollection instead!");
 1202  
 //        }
 1203  
 //        return result;
 1204  
 //    }
 1205  
 }