Coverage Report - org.melati.poem.PersistentFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
PersistentFactory
75%
82/108
90%
40/44
7.833
 
 1  
 /*
 2  
  * $Source$
 3  
  * $Revision$
 4  
  *
 5  
  * Copyright (C) 2007 Tim Pizey
 6  
  *
 7  
  * Part of Melati (http://melati.org), a framework for the rapid
 8  
  * development of clean, maintainable web applications.
 9  
  *
 10  
  * Melati is free software; Permission is granted to copy, distribute
 11  
  * and/or modify this software under the terms either:
 12  
  *
 13  
  * a) the GNU General Public License as published by the Free Software
 14  
  *    Foundation; either version 2 of the License, or (at your option)
 15  
  *    any later version,
 16  
  *
 17  
  *    or
 18  
  *
 19  
  * b) any version of the Melati Software License, as published
 20  
  *    at http://melati.org
 21  
  *
 22  
  * You should have received a copy of the GNU General Public License and
 23  
  * the Melati Software License along with this program;
 24  
  * if not, write to the Free Software Foundation, Inc.,
 25  
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
 26  
  * GNU General Public License and visit http://melati.org to obtain the
 27  
  * Melati Software License.
 28  
  *
 29  
  * Feel free to contact the Developers of Melati (http://melati.org),
 30  
  * if you would like to work out a different arrangement than the options
 31  
  * outlined here.  It is our intention to allow Melati to be used by as
 32  
  * wide an audience as possible.
 33  
  *
 34  
  * This program is distributed in the hope that it will be useful,
 35  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 36  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 37  
  * GNU General Public License for more details.
 38  
  *
 39  
  * Contact details for copyright holder:
 40  
  *
 41  
  *     Tim Pizey <timp At paneris.org>
 42  
  *     http://paneris.org/~timp
 43  
  */
 44  
 package org.melati.poem;
 45  
 
 46  
 import java.lang.reflect.Method;
 47  
 import java.util.Enumeration;
 48  
 
 49  
 import org.melati.poem.util.ClassUtils;
 50  
 import org.melati.poem.util.StringUtils;
 51  
 
 52  
 /**
 53  
  * A factory for persisting pojos and recreating them.
 54  
  * 
 55  
  * @author timp
 56  
  * @since 14 Jun 2007
 57  
  * 
 58  
  */
 59  
 public final class PersistentFactory {
 60  
 
 61  
   /**
 62  
    * Disallow instantiation.
 63  
    */
 64  0
   private PersistentFactory() {
 65  0
   }
 66  
 
 67  
   /**
 68  
    * @param db
 69  
    *          database to look in
 70  
    * @param pojo
 71  
    *          the instance to create a Persistent from.
 72  
    * @return A new or existing persisted Persistent
 73  
    */
 74  
   public static Persistent fromInstance(Database db, Object pojo) {
 75  14
     System.err.println("fromInstance - looking for " + pojo.getClass().getName());
 76  13
     Table<?> table = null;
 77  13
     Persistent p = null;
 78  13
     if (pojo instanceof Persistent) {
 79  2
       if (((Persistent)pojo).troid() != null) { 
 80  1
         return (Persistent)pojo;
 81  
       } else {
 82  1
         p = populatedPersistent(((Persistent)pojo).getTable(), pojo);
 83  1
         p.makePersistent();
 84  1
         return p;
 85  
       }
 86  
     } else
 87  11
       table = TableFactory.fromInstance(db, pojo);
 88  10
     p = populatedPersistent(table, pojo);
 89  10
     Enumeration<?> candidates = table.selection(p);
 90  10
     while (candidates.hasMoreElements()) {
 91  2
       Persistent candidate = (Persistent)candidates.nextElement();
 92  2
       if (commonFieldsEqual(p, candidate)) { 
 93  2
         p = candidate;
 94  2
         System.err.println("Candidate: " + p);
 95  2
         break;
 96  
       } else 
 97  0
         System.err.println("Non Candidate: " + p);
 98  0
     }
 99  10
     if (p.getTroid() == null) {
 100  8
       System.err.println("About to persist : " + p);
 101  8
       p.makePersistent();
 102  8
       System.err.println("Have persisted : " + p);
 103  
     }
 104  10
     System.err.println("Returning : " + p);
 105  10
     return p;
 106  
   }
 107  
 
 108  
   private static boolean commonFieldsEqual(Persistent criterion, Persistent candidate) {
 109  2
     Enumeration<Column<?>> cols = criterion.getTable().columns();
 110  19
     while (cols.hasMoreElements()) { 
 111  17
       Column<?> col = (Column<?>)cols.nextElement();
 112  17
       if (col.isTroidColumn()) 
 113  2
         continue;
 114  15
       if (col.getRaw(criterion) != null && 
 115  10
                !col.getRaw(criterion).equals(col.getRaw(candidate))) { 
 116  0
         System.err.println("Reject");
 117  0
         return false;
 118  
       }
 119  15
     }
 120  2
     return true;
 121  
   }
 122  
 
 123  
   /**
 124  
    * @param table
 125  
    *          the Table the persisted pojo is to be stored in
 126  
    * @param pojo
 127  
    *          the object to populate the Persistent from
 128  
    * @return A floating Persistent with fields populated from the given pojo
 129  
    */
 130  
   public static Persistent populatedPersistent(Table<?> table, Object pojo) {
 131  11
     if (pojo instanceof Persistent) 
 132  1
       if (((Persistent)pojo).troid() != null)
 133  0
         return table.getObject(((Persistent)pojo).troid().intValue());
 134  
       else 
 135  1
         return ((Persistent)pojo);
 136  10
     Persistent p = table.newPersistent();
 137  10
     Class<?> c = pojo.getClass();
 138  10
     Enumeration<Column<?>> columns = table.columns();
 139  82
     while (columns.hasMoreElements()) {
 140  72
       Column<?> col = (Column<?>)columns.nextElement();
 141  72
       if(col.isTroidColumn()) continue;
 142  
       Method memberGetter;
 143  
       Object raw;
 144  
       try {
 145  62
         memberGetter = c.getMethod("get" + StringUtils.capitalised(col.getName()), 
 146  
                    new Class[] {});
 147  4
       } catch (NoSuchMethodException e) {
 148  
         try {
 149  4
           memberGetter = c.getMethod("is" + StringUtils.capitalised(col.getName()), 
 150  
                                      new Class[] {});
 151  0
         } catch (NoSuchMethodException e1) {
 152  0
           throw new AppBugPoemException(
 153  0
                   "No getter available for field " + col.getName() + 
 154  0
                   " on object of class " + pojo.getClass().getName(), e1);
 155  4
         }
 156  58
       } 
 157  
       try {
 158  62
         raw = memberGetter.invoke(pojo, new Object[] {});
 159  0
       } catch (Exception e) {
 160  0
         throw new AppBugPoemException(
 161  0
                 "Problem invoking getter on column  " + col.getName(), e);
 162  62
       }
 163  62
       if (raw != null) {
 164  
         try {
 165  41
           if (col.getType() instanceof PersistentReferencePoemType) {
 166  6
             p.setCooked(col.getName(), 
 167  3
                         PersistentFactory.fromInstance(table.getDatabase(), raw));
 168  
           } else {
 169  38
             p.setCooked(col.getName(), raw);
 170  
           }
 171  0
         } catch (TypeMismatchPoemException e) {
 172  0
           throw new AppBugPoemException("Problem setting value of Column "
 173  0
                   + col.getName(), e);
 174  41
         }
 175  
       }
 176  62
     }
 177  10
     return p;
 178  
   }
 179  
 
 180  
   /**
 181  
    * Reincarnate an object, populated from the store.
 182  
    * 
 183  
    * @param persistent
 184  
    *          the Persistent to read from
 185  
    * @param clazz
 186  
    *          the class to create a new, populated instance of
 187  
    * @return an instance of the given Class, populated from the given Persistent
 188  
    * @throws NoSuchMethodException
 189  
    */
 190  
   public static Object from(Persistent persistent, Class<?> clazz)
 191  
           throws NoSuchMethodException {
 192  
     Object it;
 193  
     try {
 194  3
       it = clazz.newInstance();
 195  0
     } catch (Exception e) {
 196  0
       throw new AppBugPoemException("Problem creating new instance of "
 197  0
               + clazz.getName(), e);
 198  3
     }
 199  3
     return populatedPojo(it, persistent);
 200  
   }
 201  
 
 202  
   private static Object populatedPojo(Object pojo, Persistent persistent) 
 203  
       throws NoSuchMethodException {
 204  3
     Enumeration<Column<?>> columns = persistent.getTable().columns();
 205  21
     while (columns.hasMoreElements()) {
 206  19
       Column<?> col = (Column<?>)columns.nextElement();
 207  19
       if(col.isTroidColumn() && !(pojo instanceof Persistent)) continue;
 208  16
       Object cooked = col.getCooked(persistent);
 209  16
       if (cooked != null) {
 210  11
         String setterName = "set" + StringUtils.capitalised(col.getName());
 211  11
         Method[] possibleSetters = ClassUtils.getOneArgumentMethods(pojo.getClass(), setterName);
 212  11
         if(possibleSetters.length == 0)
 213  1
             throw new NoSuchMethodException("No setter called " + setterName
 214  1
                     + " could be found " + "on Class " + pojo.getClass().getName());
 215  21
         for (int i = 0; i < possibleSetters.length; i++) {
 216  11
           if (col.getType() instanceof ReferencePoemType) {
 217  2
             Object newPojo = PersistentFactory.from((Persistent)cooked,
 218  1
                     possibleSetters[i].getParameterTypes()[0]);
 219  
             try {
 220  1
               possibleSetters[i].invoke(pojo, new Object[] { newPojo });
 221  0
             } catch (Exception e) {
 222  0
               throw new AppBugPoemException(
 223  0
                       "Problem setting value of Column " + col.getName(), e);
 224  1
             }
 225  1
           } else {
 226  
             try {
 227  10
               possibleSetters[i].invoke(pojo, new Object[] { cooked });
 228  0
             } catch (Exception e) {
 229  0
               throw new AppBugPoemException(
 230  0
                       "Problem setting value of Column " + col.getName(), e);
 231  10
             }
 232  
           }
 233  
         }
 234  
       }
 235  15
     }
 236  2
     return pojo;
 237  
   }
 238  
 
 239  
 
 240  
 }