src/core/net/sf/basedb/util/Diff3.java

Code
Comments
Other
Rev Date Author Line
886 07 Jul 05 nicklas 1 /*
886 07 Jul 05 nicklas 2   $Id$
886 07 Jul 05 nicklas 3
3675 16 Aug 07 jari 4   Copyright (C) 2005 Nicklas Nordborg
4889 06 Apr 09 nicklas 5   Copyright (C) 2006 Jari Häkkinen
886 07 Jul 05 nicklas 6
2304 22 May 06 jari 7   This file is part of BASE - BioArray Software Environment.
2304 22 May 06 jari 8   Available at http://base.thep.lu.se/
886 07 Jul 05 nicklas 9
886 07 Jul 05 nicklas 10   BASE is free software; you can redistribute it and/or
886 07 Jul 05 nicklas 11   modify it under the terms of the GNU General Public License
4479 05 Sep 08 jari 12   as published by the Free Software Foundation; either version 3
886 07 Jul 05 nicklas 13   of the License, or (at your option) any later version.
886 07 Jul 05 nicklas 14
886 07 Jul 05 nicklas 15   BASE is distributed in the hope that it will be useful,
886 07 Jul 05 nicklas 16   but WITHOUT ANY WARRANTY; without even the implied warranty of
886 07 Jul 05 nicklas 17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
886 07 Jul 05 nicklas 18   GNU General Public License for more details.
886 07 Jul 05 nicklas 19
886 07 Jul 05 nicklas 20   You should have received a copy of the GNU General Public License
4515 11 Sep 08 jari 21   along with BASE. If not, see <http://www.gnu.org/licenses/>.
886 07 Jul 05 nicklas 22 */
886 07 Jul 05 nicklas 23 package net.sf.basedb.util;
886 07 Jul 05 nicklas 24
886 07 Jul 05 nicklas 25 import net.sf.basedb.core.BasicItem;
886 07 Jul 05 nicklas 26 import net.sf.basedb.core.ItemModifiedException;
886 07 Jul 05 nicklas 27 import net.sf.basedb.core.InvalidDataException;
886 07 Jul 05 nicklas 28 import net.sf.basedb.core.InvalidUseOfNullException;
886 07 Jul 05 nicklas 29
886 07 Jul 05 nicklas 30 /**
886 07 Jul 05 nicklas 31   This class is helpful when a client application needs to implement long-running
886 07 Jul 05 nicklas 32   transactions and still be able to update items with as few clashes as possible.
886 07 Jul 05 nicklas 33   Using this class it is possible to avoid {@link ItemModifiedException}:s
886 07 Jul 05 nicklas 34   even when two or more users are modifying the same item at the same time. 
886 07 Jul 05 nicklas 35   The only requirement is that they don't change the same property to different 
886 07 Jul 05 nicklas 36   values. Here is how to use this class:
886 07 Jul 05 nicklas 37   <ul>
886 07 Jul 05 nicklas 38   <li>The <code>oldItem</code> is loaded and the user is presented with a
886 07 Jul 05 nicklas 39     screen to modify the properties of the item. The client application must 
886 07 Jul 05 nicklas 40     keep the item in memory while the user is doing the modifications.
886 07 Jul 05 nicklas 41   <li>When the user submits the changes the <code>newItem</code> is loaded.
888 07 Jul 05 nicklas 42     Both objects are passed to the {@link #Diff3(BasicItem, BasicItem)} constructor.
886 07 Jul 05 nicklas 43     The construcor checks if both objects are of the same version or not.
888 07 Jul 05 nicklas 44   <li>The client application uses the {@link #getValue(Object, Object, Object)} method to
886 07 Jul 05 nicklas 45     set the properties on the <code>newItem</code> object.
886 07 Jul 05 nicklas 46   </ul>
886 07 Jul 05 nicklas 47   
886 07 Jul 05 nicklas 48   <pre class="code">
886 07 Jul 05 nicklas 49 <b>edit.jsp</b>
886 07 Jul 05 nicklas 50 Label label = Label.getById(dbControl, labelId);
886 07 Jul 05 nicklas 51 sessionControl.setSessionSetting("LABEL", label);
886 07 Jul 05 nicklas 52
886 07 Jul 05 nicklas 53 <b>submit.jsp</b>
886 07 Jul 05 nicklas 54 Label oldLabel = (Label)sessionControl.getSessionSetting("LABEL");
886 07 Jul 05 nicklas 55 Label newLabel = Label.getById(dbControl, labelId);
886 07 Jul 05 nicklas 56 Diff3 d3 = new Diff3(oldLabel, newLabel);
886 07 Jul 05 nicklas 57 newLabel.setName(d3.getValue(oldLabel.getName(), newLabel.getName(), 
886 07 Jul 05 nicklas 58    request.getParameter("name")));
886 07 Jul 05 nicklas 59 // ... etc ...
886 07 Jul 05 nicklas 60 dbControl.commit();
886 07 Jul 05 nicklas 61 </pre>
886 07 Jul 05 nicklas 62
886 07 Jul 05 nicklas 63   Additional code to check for session timeouts and creating new items
886 07 Jul 05 nicklas 64   is also required.
886 07 Jul 05 nicklas 65
886 07 Jul 05 nicklas 66   @author Nicklas
886 07 Jul 05 nicklas 67   @version 2.0
886 07 Jul 05 nicklas 68   @base.modified $Date$
886 07 Jul 05 nicklas 69 */
886 07 Jul 05 nicklas 70 public class Diff3
886 07 Jul 05 nicklas 71 {
886 07 Jul 05 nicklas 72   private final boolean sameVersion;
886 07 Jul 05 nicklas 73   private final String what;
886 07 Jul 05 nicklas 74
886 07 Jul 05 nicklas 75   /**
886 07 Jul 05 nicklas 76     Create a new <code>Diff3</code> object to compare properties
886 07 Jul 05 nicklas 77     of the <code>oldItem</code> and <code>newItem</code>. Both
886 07 Jul 05 nicklas 78     objects mustn't be null and they must represent the same
886 07 Jul 05 nicklas 79     item in the database. For new objects, not yet in the database,
886 07 Jul 05 nicklas 80     both parameters must be the same instance.
886 07 Jul 05 nicklas 81     @param oldItem The "old" representation of the item
886 07 Jul 05 nicklas 82     @param newItem The "new" representation of the item
886 07 Jul 05 nicklas 83     @throws InvalidDataException If one of the parameters is null
886 07 Jul 05 nicklas 84       or they don't represent the same database item
886 07 Jul 05 nicklas 85   */
886 07 Jul 05 nicklas 86   public Diff3(BasicItem oldItem, BasicItem newItem)
886 07 Jul 05 nicklas 87     throws InvalidDataException
886 07 Jul 05 nicklas 88   {
886 07 Jul 05 nicklas 89     if (oldItem == null) throw new InvalidUseOfNullException("oldItem");
886 07 Jul 05 nicklas 90     if (newItem == null) throw new InvalidUseOfNullException("newItem");
886 07 Jul 05 nicklas 91     if (!oldItem.equals(newItem)) 
886 07 Jul 05 nicklas 92     {
886 07 Jul 05 nicklas 93       throw new InvalidDataException("oldItem '"+oldItem+"' is not the same item as newItem '"+newItem+"'");
886 07 Jul 05 nicklas 94     }
886 07 Jul 05 nicklas 95     sameVersion = oldItem.getVersion() == newItem.getVersion();
886 07 Jul 05 nicklas 96     what = newItem.toString();
886 07 Jul 05 nicklas 97   }
886 07 Jul 05 nicklas 98   
886 07 Jul 05 nicklas 99   /**
886 07 Jul 05 nicklas 100     Get the correct value to set on the <code>newItem</code> object.
886 07 Jul 05 nicklas 101     <ul>
886 07 Jul 05 nicklas 102     <li>If the old and new item have the same version 
886 07 Jul 05 nicklas 103       or if the <code>oldValue</code> is the same as the
886 07 Jul 05 nicklas 104       <code>newValue</code> the <code>requestValue</code> 
886 07 Jul 05 nicklas 105       is returned. This represents the case that no other
886 07 Jul 05 nicklas 106       user has modified the item, or it was modified but not
886 07 Jul 05 nicklas 107       this particular property.
886 07 Jul 05 nicklas 108     <li>If the old and request value are equal the <code>newValue</code>
886 07 Jul 05 nicklas 109       is returned. This represents the case that the other
886 07 Jul 05 nicklas 110       user has modified the property, but the current user hasn't.
886 07 Jul 05 nicklas 111     <li>If the new and request value are equal the <code>newValue</code>
886 07 Jul 05 nicklas 112       is returned. This represents the case that both users
886 07 Jul 05 nicklas 113       has modified the property and, fortunately, set it to the
886 07 Jul 05 nicklas 114       same value.
4026 30 Nov 07 martin 115     <li>Otherwise, it all three values are different, a
886 07 Jul 05 nicklas 116       {@link ItemModifiedException} is thrown.
886 07 Jul 05 nicklas 117     </ul>
886 07 Jul 05 nicklas 118     @param oldValue The value of the property on the old item
886 07 Jul 05 nicklas 119     @param newValue The value of the property on the new item
888 07 Jul 05 nicklas 120     @param requestValue The vale of the property the current user 
886 07 Jul 05 nicklas 121       has set on the edit screen
886 07 Jul 05 nicklas 122     @return The most appropriate value as described above
886 07 Jul 05 nicklas 123     @throws ItemModifiedException If all values are different
886 07 Jul 05 nicklas 124   */
886 07 Jul 05 nicklas 125   public <T> T getValue(T oldValue, T newValue, T requestValue)
886 07 Jul 05 nicklas 126     throws ItemModifiedException
886 07 Jul 05 nicklas 127   {
886 07 Jul 05 nicklas 128     if (sameVersion || isEqualOrNull(oldValue, newValue))
886 07 Jul 05 nicklas 129     {
886 07 Jul 05 nicklas 130       return requestValue;
886 07 Jul 05 nicklas 131     }
886 07 Jul 05 nicklas 132     else if (isEqualOrNull(oldValue, requestValue))
886 07 Jul 05 nicklas 133     {
886 07 Jul 05 nicklas 134       return newValue;
886 07 Jul 05 nicklas 135     }
886 07 Jul 05 nicklas 136     else if (isEqualOrNull(newValue, requestValue))
886 07 Jul 05 nicklas 137     {
886 07 Jul 05 nicklas 138       return newValue;
886 07 Jul 05 nicklas 139     }
886 07 Jul 05 nicklas 140     throw new ItemModifiedException(what);
886 07 Jul 05 nicklas 141   }
886 07 Jul 05 nicklas 142   
886 07 Jul 05 nicklas 143   /**
886 07 Jul 05 nicklas 144     Check if two objects are both null or equal as defined
886 07 Jul 05 nicklas 145     by the {@link Object#equals(Object)} method.
4026 30 Nov 07 martin 146      @param o1 Object to compare 
4026 30 Nov 07 martin 147      @param o2 Object to compare
4026 30 Nov 07 martin 148      @return TRUE if equal or null, FALSE otherwise.
886 07 Jul 05 nicklas 149   */
886 07 Jul 05 nicklas 150   public static boolean isEqualOrNull(Object o1, Object o2)
886 07 Jul 05 nicklas 151   {
886 07 Jul 05 nicklas 152     return (o1 == o2) || (o1 != null && o1.equals(o2));
886 07 Jul 05 nicklas 153   }
886 07 Jul 05 nicklas 154   
886 07 Jul 05 nicklas 155 }