886 |
07 Jul 05 |
nicklas |
1 |
/* |
886 |
07 Jul 05 |
nicklas |
$Id$ |
886 |
07 Jul 05 |
nicklas |
3 |
|
3675 |
16 Aug 07 |
jari |
Copyright (C) 2005 Nicklas Nordborg |
4889 |
06 Apr 09 |
nicklas |
Copyright (C) 2006 Jari Häkkinen |
886 |
07 Jul 05 |
nicklas |
6 |
|
2304 |
22 May 06 |
jari |
This file is part of BASE - BioArray Software Environment. |
2304 |
22 May 06 |
jari |
Available at http://base.thep.lu.se/ |
886 |
07 Jul 05 |
nicklas |
9 |
|
886 |
07 Jul 05 |
nicklas |
BASE is free software; you can redistribute it and/or |
886 |
07 Jul 05 |
nicklas |
modify it under the terms of the GNU General Public License |
4479 |
05 Sep 08 |
jari |
as published by the Free Software Foundation; either version 3 |
886 |
07 Jul 05 |
nicklas |
of the License, or (at your option) any later version. |
886 |
07 Jul 05 |
nicklas |
14 |
|
886 |
07 Jul 05 |
nicklas |
BASE is distributed in the hope that it will be useful, |
886 |
07 Jul 05 |
nicklas |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
886 |
07 Jul 05 |
nicklas |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
886 |
07 Jul 05 |
nicklas |
GNU General Public License for more details. |
886 |
07 Jul 05 |
nicklas |
19 |
|
886 |
07 Jul 05 |
nicklas |
You should have received a copy of the GNU General Public License |
4515 |
11 Sep 08 |
jari |
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 |
This class is helpful when a client application needs to implement long-running |
886 |
07 Jul 05 |
nicklas |
transactions and still be able to update items with as few clashes as possible. |
886 |
07 Jul 05 |
nicklas |
Using this class it is possible to avoid {@link ItemModifiedException}:s |
886 |
07 Jul 05 |
nicklas |
even when two or more users are modifying the same item at the same time. |
886 |
07 Jul 05 |
nicklas |
The only requirement is that they don't change the same property to different |
886 |
07 Jul 05 |
nicklas |
values. Here is how to use this class: |
886 |
07 Jul 05 |
nicklas |
<ul> |
886 |
07 Jul 05 |
nicklas |
<li>The <code>oldItem</code> is loaded and the user is presented with a |
886 |
07 Jul 05 |
nicklas |
screen to modify the properties of the item. The client application must |
886 |
07 Jul 05 |
nicklas |
keep the item in memory while the user is doing the modifications. |
886 |
07 Jul 05 |
nicklas |
<li>When the user submits the changes the <code>newItem</code> is loaded. |
888 |
07 Jul 05 |
nicklas |
Both objects are passed to the {@link #Diff3(BasicItem, BasicItem)} constructor. |
886 |
07 Jul 05 |
nicklas |
The construcor checks if both objects are of the same version or not. |
888 |
07 Jul 05 |
nicklas |
<li>The client application uses the {@link #getValue(Object, Object, Object)} method to |
886 |
07 Jul 05 |
nicklas |
set the properties on the <code>newItem</code> object. |
886 |
07 Jul 05 |
nicklas |
</ul> |
886 |
07 Jul 05 |
nicklas |
47 |
|
886 |
07 Jul 05 |
nicklas |
<pre class="code"> |
886 |
07 Jul 05 |
nicklas |
<b>edit.jsp</b> |
886 |
07 Jul 05 |
nicklas |
Label label = Label.getById(dbControl, labelId); |
886 |
07 Jul 05 |
nicklas |
sessionControl.setSessionSetting("LABEL", label); |
886 |
07 Jul 05 |
nicklas |
52 |
|
886 |
07 Jul 05 |
nicklas |
<b>submit.jsp</b> |
886 |
07 Jul 05 |
nicklas |
Label oldLabel = (Label)sessionControl.getSessionSetting("LABEL"); |
886 |
07 Jul 05 |
nicklas |
Label newLabel = Label.getById(dbControl, labelId); |
886 |
07 Jul 05 |
nicklas |
Diff3 d3 = new Diff3(oldLabel, newLabel); |
886 |
07 Jul 05 |
nicklas |
newLabel.setName(d3.getValue(oldLabel.getName(), newLabel.getName(), |
886 |
07 Jul 05 |
nicklas |
request.getParameter("name"))); |
886 |
07 Jul 05 |
nicklas |
// ... etc ... |
886 |
07 Jul 05 |
nicklas |
dbControl.commit(); |
886 |
07 Jul 05 |
nicklas |
</pre> |
886 |
07 Jul 05 |
nicklas |
62 |
|
886 |
07 Jul 05 |
nicklas |
Additional code to check for session timeouts and creating new items |
886 |
07 Jul 05 |
nicklas |
is also required. |
886 |
07 Jul 05 |
nicklas |
65 |
|
886 |
07 Jul 05 |
nicklas |
@author Nicklas |
886 |
07 Jul 05 |
nicklas |
@version 2.0 |
886 |
07 Jul 05 |
nicklas |
@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 |
Create a new <code>Diff3</code> object to compare properties |
886 |
07 Jul 05 |
nicklas |
of the <code>oldItem</code> and <code>newItem</code>. Both |
886 |
07 Jul 05 |
nicklas |
objects mustn't be null and they must represent the same |
886 |
07 Jul 05 |
nicklas |
item in the database. For new objects, not yet in the database, |
886 |
07 Jul 05 |
nicklas |
both parameters must be the same instance. |
886 |
07 Jul 05 |
nicklas |
@param oldItem The "old" representation of the item |
886 |
07 Jul 05 |
nicklas |
@param newItem The "new" representation of the item |
886 |
07 Jul 05 |
nicklas |
@throws InvalidDataException If one of the parameters is null |
886 |
07 Jul 05 |
nicklas |
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 |
Get the correct value to set on the <code>newItem</code> object. |
886 |
07 Jul 05 |
nicklas |
<ul> |
886 |
07 Jul 05 |
nicklas |
<li>If the old and new item have the same version |
886 |
07 Jul 05 |
nicklas |
or if the <code>oldValue</code> is the same as the |
886 |
07 Jul 05 |
nicklas |
<code>newValue</code> the <code>requestValue</code> |
886 |
07 Jul 05 |
nicklas |
is returned. This represents the case that no other |
886 |
07 Jul 05 |
nicklas |
user has modified the item, or it was modified but not |
886 |
07 Jul 05 |
nicklas |
this particular property. |
886 |
07 Jul 05 |
nicklas |
<li>If the old and request value are equal the <code>newValue</code> |
886 |
07 Jul 05 |
nicklas |
is returned. This represents the case that the other |
886 |
07 Jul 05 |
nicklas |
user has modified the property, but the current user hasn't. |
886 |
07 Jul 05 |
nicklas |
<li>If the new and request value are equal the <code>newValue</code> |
886 |
07 Jul 05 |
nicklas |
is returned. This represents the case that both users |
886 |
07 Jul 05 |
nicklas |
has modified the property and, fortunately, set it to the |
886 |
07 Jul 05 |
nicklas |
same value. |
4026 |
30 Nov 07 |
martin |
<li>Otherwise, it all three values are different, a |
886 |
07 Jul 05 |
nicklas |
{@link ItemModifiedException} is thrown. |
886 |
07 Jul 05 |
nicklas |
</ul> |
886 |
07 Jul 05 |
nicklas |
@param oldValue The value of the property on the old item |
886 |
07 Jul 05 |
nicklas |
@param newValue The value of the property on the new item |
888 |
07 Jul 05 |
nicklas |
@param requestValue The vale of the property the current user |
886 |
07 Jul 05 |
nicklas |
has set on the edit screen |
886 |
07 Jul 05 |
nicklas |
@return The most appropriate value as described above |
886 |
07 Jul 05 |
nicklas |
@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 |
Check if two objects are both null or equal as defined |
886 |
07 Jul 05 |
nicklas |
by the {@link Object#equals(Object)} method. |
4026 |
30 Nov 07 |
martin |
@param o1 Object to compare |
4026 |
30 Nov 07 |
martin |
@param o2 Object to compare |
4026 |
30 Nov 07 |
martin |
@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 |
} |