View Javadoc

1   package uk.ac.ebi.intenz.webapp.utilities;
2   
3   import java.sql.Connection;
4   import java.sql.SQLException;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.HashMap;
8   import java.util.List;
9   import java.util.Map;
10  
11  import javax.servlet.http.HttpSessionBindingEvent;
12  import javax.servlet.http.HttpSessionBindingListener;
13  
14  import org.apache.log4j.Logger;
15  import org.apache.struts.action.ActionMessages;
16  
17  import uk.ac.ebi.biobabel.util.collections.OperatorSet;
18  import uk.ac.ebi.intenz.domain.constants.EnzymeNameQualifierConstant;
19  import uk.ac.ebi.intenz.domain.constants.EnzymeNameTypeConstant;
20  import uk.ac.ebi.intenz.domain.constants.EnzymeSourceConstant;
21  import uk.ac.ebi.intenz.domain.constants.EnzymeViewConstant;
22  import uk.ac.ebi.intenz.domain.constants.Status;
23  import uk.ac.ebi.intenz.domain.constants.XrefDatabaseConstant;
24  import uk.ac.ebi.intenz.domain.enzyme.Cofactor;
25  import uk.ac.ebi.intenz.domain.enzyme.EnzymaticReactions;
26  import uk.ac.ebi.intenz.domain.enzyme.EnzymeComment;
27  import uk.ac.ebi.intenz.domain.enzyme.EnzymeCommissionNumber;
28  import uk.ac.ebi.intenz.domain.enzyme.EnzymeLink;
29  import uk.ac.ebi.intenz.domain.enzyme.EnzymeName;
30  import uk.ac.ebi.intenz.domain.exceptions.DomainException;
31  import uk.ac.ebi.intenz.domain.exceptions.EcException;
32  import uk.ac.ebi.intenz.domain.reference.Book;
33  import uk.ac.ebi.intenz.domain.reference.Journal;
34  import uk.ac.ebi.intenz.domain.reference.Patent;
35  import uk.ac.ebi.intenz.domain.reference.Reference;
36  import uk.ac.ebi.intenz.mapper.EnzymeCofactorMapper;
37  import uk.ac.ebi.intenz.mapper.EnzymeCommentMapper;
38  import uk.ac.ebi.intenz.mapper.EnzymeEntryMapper;
39  import uk.ac.ebi.intenz.mapper.EnzymeLinkMapper;
40  import uk.ac.ebi.intenz.mapper.EnzymeNameMapper;
41  import uk.ac.ebi.intenz.mapper.EnzymeReactionMapper;
42  import uk.ac.ebi.intenz.mapper.EnzymeReferenceMapper;
43  import uk.ac.ebi.intenz.webapp.dtos.CofactorDTO;
44  import uk.ac.ebi.intenz.webapp.dtos.CommentDTO;
45  import uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO;
46  import uk.ac.ebi.intenz.webapp.dtos.EnzymeLinkDTO;
47  import uk.ac.ebi.intenz.webapp.dtos.EnzymeNameDTO;
48  import uk.ac.ebi.intenz.webapp.dtos.ReactionDTO;
49  import uk.ac.ebi.intenz.webapp.dtos.ReferenceDTO;
50  import uk.ac.ebi.intenz.webapp.exceptions.CommitException;
51  import uk.ac.ebi.intenz.webapp.exceptions.DeregisterException;
52  import uk.ac.ebi.rhea.domain.Compound;
53  import uk.ac.ebi.rhea.domain.Database;
54  import uk.ac.ebi.rhea.domain.Reaction;
55  import uk.ac.ebi.rhea.mapper.MapperException;
56  import uk.ac.ebi.rhea.mapper.db.RheaCompoundDbReader;
57  
58  /**
59   * This is a simple <i>UnitOfWork</i> implementation to ease database updates.
60   * <p/>
61   * Before a requested enzyme is loaded into the session a copy of this instance is made by the
62   * {@link #register(uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO)} method and kept in memory.
63   * When the curator finished and pressed the 'submit' button, the enzyme instance modified
64   * by the curator will be compared to the copy created in the beginning. Usually only data that changed will then be
65   * stored (removed) in (from) the database (links are handled differently).<br/>
66   * For data stored in a list the comparison works as follows:
67   * <ol>
68   * <li>Data that has been removed from the list of the enzyme under development will also be removed from the copy's list.</li>
69   * <li>As long as data is available in the relevant list of the copy, data with the same list index will be compared,
70   * and in case of a difference the database will be updated.</li>
71   * <li>Finally the database will be populated with new data if the list of the enzyme under development still contains
72   * items.</li>
73   * </ol>
74   *
75   * @author Michael Darsow
76   * @version $Revision: 1.6 $ $Date: 2008/04/23 14:20:13 $
77   */
78  public class UnitOfWork implements HttpSessionBindingListener {
79  
80  	/**
81  	 * This class member is used to give registered objects a unique Unit of Work ID.
82  	 * Both, the original object and the copy will share this ID. This allows to retreive the correct copy in the
83  	 * {@link UnitOfWork#commit(uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO, java.sql.Connection)} phase.
84  	 */
85  	public static int UOW_ID = 0;
86  
87  	/**
88  	 * The logger instance is currently only used to provide some information during the
89  	 * {@link UnitOfWork#register(uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO)} and
90  	 * {@link UnitOfWork#commit(uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO, java.sql.Connection)} phases.
91  	 */
92  	private static final Logger LOGGER = Logger.getLogger(UnitOfWork.class.getName());
93  
94  	/**
95  	 * The EnzymeDTO instance the curator is working on.
96  	 */
97  	private Map<Integer, EnzymeDTO> enzymesUnderDevelopment;
98  	
99  	EnzymeReactionMapper enzymeReactionMapper;
100 
101 	EnzymeEntryMapper enzymeEntryMapper;
102 
103 	/**
104 	 * Initialises <code>enzymesUnderDevelopment</code>.
105 	 * @deprecated 
106 	 */
107 	public UnitOfWork() {
108 		this(new EnzymeReactionMapper());
109 	}
110 	
111 	public UnitOfWork(EnzymeReactionMapper enzymeReactionMapper){
112 		this(enzymeReactionMapper, new EnzymeEntryMapper(enzymeReactionMapper));
113 	}
114 	
115 	public UnitOfWork(EnzymeReactionMapper enzymeReactionMapper,
116 			EnzymeEntryMapper enzymeEntryMapper){
117 		this.enzymeReactionMapper = enzymeReactionMapper;
118 		this.enzymeEntryMapper = enzymeEntryMapper;
119 		enzymesUnderDevelopment = new HashMap<Integer, EnzymeDTO>();
120 	}
121 	
122 	@Override
123 	protected void finalize() throws Throwable {
124 		enzymeEntryMapper.close();
125 		enzymeReactionMapper.close();
126 	}
127 
128 	/**
129 	 * Creates and stores a copy of the given {@link uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO} instance.
130 	 *
131 	 * @param enzymeUnderDevelopment The current enzyme entry instance.
132 	 */
133 	public void register(EnzymeDTO enzymeUnderDevelopment) {
134 		if (enzymeUnderDevelopment == null) throw new NullPointerException("Parameter 'enzymeUnderDevelopment' must not be null.");
135 		final Integer uowId = new Integer(UOW_ID);
136 		final EnzymeDTO enzymeCopy = new EnzymeDTO(enzymeUnderDevelopment);
137 		enzymesUnderDevelopment.put(uowId, enzymeCopy);
138 		enzymeUnderDevelopment.setUowId(uowId);
139 		UOW_ID++;
140 		LOGGER.info("EC " + enzymeUnderDevelopment.getEc() + " has been registered in the UoW.");
141 	}
142 
143 	/**
144 	 * Compares the given enzyme entry to the copy stored in {@link #register(uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO)}.
145 	 * <p/>
146 	 * Changes will be transferred to the database.
147 	 * <p/>
148 	 * Data which is stored in lists will simply be reloaded at the moment.
149 	 * <p/>
150 	 * If a new enzyme has been submitted this method will insert the entry into the database.
151 	 *
152 	 * @param enzymeUnderDevelopment The enzyme the curator has worked on.
153 	 * @param con                    A database connection used to perform the changes in the database.
154 	 * @throws EcException         if an invalid EC number has been used.
155 	 * @throws SQLException        if a database error occurs.
156 	 * @throws DomainException     if a domain error occurs.
157 	 * @throws CommitException if there is some data integrity threat
158 	 * @throws NumberFormatException 
159 	 * @throws DeregisterException if an object does not exist in {@link UnitOfWork#enzymesUnderDevelopment}
160 	 *                             (list of registered objects).
161 	 */
162 	public void commit(EnzymeDTO enzymeUnderDevelopment, Connection con)
163 	throws EcException, SQLException, DomainException, NumberFormatException, CommitException {
164 		if (enzymeUnderDevelopment == null) throw new NullPointerException("Parameter 'enzymeUnderDevelopment' must not be null.");
165 		if (con == null) throw new NullPointerException("Parameter 'con' must not be null.");
166 
167 		LOGGER.info("EC " + enzymeUnderDevelopment.getEc() + " is being committed ...");
168 
169 		// Insert new enzymes.
170 		if (enzymeUnderDevelopment.getId() == null || enzymeUnderDevelopment.getId().equals("")) {
171 			insertEnzymeEntry(enzymeUnderDevelopment, con);
172 			LOGGER.info("... commit completed.");
173 			return;
174 		}
175 
176 		EnzymeDTO copy = (EnzymeDTO) enzymesUnderDevelopment.remove(enzymeUnderDevelopment.getUowId()); // also remove instance from the list of registered objects
177 		if (copy == null) throw new DeregisterException(ActionMessages.GLOBAL_MESSAGE, "errors.application.uow.deregister");
178 
179 		compareCoreData(enzymeUnderDevelopment, copy, con);
180 		reloadNames(enzymeUnderDevelopment.getCommonNames(),
181 				new Long(enzymeUnderDevelopment.getId()),
182 				Status.fromCode(enzymeUnderDevelopment.getStatusCode()),
183 				EnzymeNameTypeConstant.COMMON_NAME, con);
184 		if (enzymeUnderDevelopment.isActive()){
185 			reloadReactions(enzymeUnderDevelopment.getReactionDtos(),
186 					new Long(enzymeUnderDevelopment.getId()),
187 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
188 			compareSystematicName(enzymeUnderDevelopment, copy, con);
189 			reloadNames(enzymeUnderDevelopment.getSynonyms(),
190 					new Long(enzymeUnderDevelopment.getId()),
191 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()),
192 					EnzymeNameTypeConstant.OTHER_NAME, con);
193 			reloadCofactors(enzymeUnderDevelopment.getCofactors(),
194 					new Long(enzymeUnderDevelopment.getId()),
195 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
196 			reloadLinks(enzymeUnderDevelopment, con);
197 			reloadComments(enzymeUnderDevelopment.getComments(),
198 					new Long(enzymeUnderDevelopment.getId()),
199 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
200 			reloadReferences(enzymeUnderDevelopment.getReferences(),
201 					new Long(enzymeUnderDevelopment.getId()),
202 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()),
203 					EnzymeSourceConstant.valueOf(enzymeUnderDevelopment.getSource()), con);
204 		}
205 		LOGGER.info("... commit completed.");
206 	}
207 
208 	/**
209 	 * Compares the core data of the two {@link uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO} instances and updates the table
210 	 * <b><code>ENZYME</code></b> if any difference exists.
211 	 * <p/>
212 	 * 'Core' data comprises:
213 	 * <ul>
214 	 * <li>EC number</li>
215 	 * <li>status code</li>
216 	 * <li>source</li>
217 	 * <li>note</li>
218 	 * <li>history line</li>
219 	 * </ul>
220 	 *
221 	 * @param enzymeUnderDevelopment The enzyme the curator has worked on.
222 	 * @param copy                   The copy created in {@link #register(uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO)}.
223 	 * @param con                    A database connection used to perform the changes in the database.
224 	 * @throws EcException  if an invalid EC number has been used.
225 	 * @throws SQLException if a database error occurs.
226 	 */
227 	private void compareCoreData(EnzymeDTO enzymeUnderDevelopment, EnzymeDTO copy, Connection con)
228 	throws EcException, SQLException {
229 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
230 		assert copy != null : "Parameter 'copy' must not be null.";
231 		assert con != null : "Parameter 'con' must not be null.";
232 		boolean update = false;
233 
234 		if (!enzymeUnderDevelopment.getEc().equals(copy.getEc())) update = true;
235 		if (!update && !enzymeUnderDevelopment.getStatusCode().equals(copy.getStatusCode())) update = true;
236 		if (!update && !enzymeUnderDevelopment.getSource().equals(copy.getSource())) update = true;
237 		if (!update && !enzymeUnderDevelopment.getNote().equals(copy.getNote())) update = true;
238 		if (!update && !enzymeUnderDevelopment.getHistoryLine().equals(copy.getHistoryLine())) update = true;
239 
240 		// Update as soon as an element og the core date changed.
241 		if (update) {
242 			enzymeEntryMapper.update(new Long(enzymeUnderDevelopment.getId()),
243 					EnzymeCommissionNumber.valueOf(enzymeUnderDevelopment.getEc()),
244 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()),
245 					EnzymeSourceConstant.valueOf(enzymeUnderDevelopment.getSource()),
246 					enzymeUnderDevelopment.getNote(),
247 					enzymeUnderDevelopment.getHistoryLine(),
248 					enzymeUnderDevelopment.isActive(),
249 					con);
250 		}
251 	}
252 
253 	private void reloadReactions(List<ReactionDTO> reactions, Long enzymeId, Status status, Connection con)
254 	throws SQLException {
255 		assert reactions != null : "Parameter 'reactions' must not be null.";
256 		assert enzymeId != null : "Parameter 'enzymeId' must not be null.";
257 		assert status != null : "Parameter 'status' must not be null.";
258 		assert con != null : "Parameter 'con' must not be null.";
259 		EnzymaticReactions er = new EnzymaticReactions();
260 		for (ReactionDTO reactionDTO : reactions) {
261 			er.add(getReactionObject(reactionDTO), reactionDTO.getView(),
262 					Boolean.parseBoolean(reactionDTO.getIubmb()));
263 		}
264 		enzymeReactionMapper.update(enzymeId, er, con);
265 	}
266 
267 	private void reloadNames(List<?> names, Long enzymeId, Status status, EnzymeNameTypeConstant type,
268 			Connection con) throws SQLException {
269 		assert names != null : "Parameter 'names' must not be null.";
270 		assert enzymeId != null : "Parameter 'enzymeId' must not be null.";
271 		assert status != null : "Parameter 'status' must not be null.";
272 		assert type != null : "Parameter 'type' must not be null.";
273 		assert con != null : "Parameter 'con' must not be null.";
274 		List<EnzymeName> enzymeNames = new ArrayList<EnzymeName>();
275 		for (int iii = 0; iii < names.size(); iii++) {
276 			enzymeNames.add(getEnzymeNameObject((EnzymeNameDTO) names.get(iii)));
277 		}
278 		//if (enzymeNames.size() > 0) {
279 		EnzymeNameMapper enzymeNameMapper = new EnzymeNameMapper();
280 		enzymeNameMapper.reload(enzymeNames, enzymeId, type, status, con);
281 		// }
282 	}
283 
284 	/**
285 	 * Compares the systematic names of the two enzyme DTO objects and updates the name in the database if it changed.
286 	 *
287 	 * @param enzymeUnderDevelopment The enzyme the curator has worked on.
288 	 * @param copy                   The copy created in {@link #register(uk.ac.ebi.intenz.webapp.dtos.EnzymeDTO)}.
289 	 * @param con                    A database connection used to perform the changes in the database.
290 	 * @throws SQLException if a database error occurs.
291 	 */
292 	private void compareSystematicName(EnzymeDTO enzymeUnderDevelopment, EnzymeDTO copy, Connection con) throws SQLException {
293 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
294 		assert copy != null : "Parameter 'copy' must not be null.";
295 		assert con != null : "Parameter 'con' must not be null.";
296 		if (!enzymeUnderDevelopment.getSystematicName().getXmlName().equals(copy.getSystematicName().getXmlName()) ||
297 				!enzymeUnderDevelopment.getSystematicName().getView().equals(copy.getSystematicName().getView()) ||
298 				!enzymeUnderDevelopment.getStatusCode().equals(copy.getStatusCode())) {
299 			EnzymeNameMapper enzymeNameMapper = new EnzymeNameMapper();
300 			EnzymeName enzymeName = EnzymeName.getSystematicNameInstance(enzymeUnderDevelopment.getSystematicName().getXmlName(),
301 					EnzymeSourceConstant.valueOf(enzymeUnderDevelopment.getSource()),
302 					EnzymeViewConstant.valueOf(enzymeUnderDevelopment.getSystematicName().getView()));
303 			if (copy.getSystematicName().getXmlName().equals("")){
304 				// There was no systematic name in the database
305 				enzymeNameMapper.insert(enzymeName, new Long(enzymeUnderDevelopment.getId()),
306 						Status.fromCode(enzymeUnderDevelopment.getStatusCode()), 1, con);
307 			} else {
308 				enzymeNameMapper.update(enzymeName, new Long(enzymeUnderDevelopment.getId()),
309 						Status.fromCode(enzymeUnderDevelopment.getStatusCode()), 1, con);
310 			}
311 		}
312 	}
313 
314 	private void reloadCofactors(List<CofactorDTO> cofactors, Long enzymeId, Status status, Connection con)
315 	throws SQLException, CommitException {
316 		assert cofactors != null : "Parameter 'names' must not be null.";
317 		assert enzymeId != null : "Parameter 'enzymeId' must not be null.";
318 		assert status != null : "Parameter 'status' must not be null.";
319 		assert con != null : "Parameter 'con' must not be null.";
320 		Collection<Object> enzymeCofactors = new ArrayList<Object>();
321 		for (int iii = 0; iii < cofactors.size(); iii++) {
322 			enzymeCofactors.add(getCofactorObject(cofactors.get(iii), con));
323 		}
324 		if (cofactors.size() != enzymeCofactors.size()){
325 			// some cofactor lost!
326 			LOGGER.error("Error while parsing cofactors!");
327 			throw new CommitException("Error while parsing cofactors!");
328 		}
329 		EnzymeCofactorMapper enzymeCofactorMapper = new EnzymeCofactorMapper();
330 		enzymeCofactorMapper.reload(enzymeCofactors, enzymeId, status, con);
331 
332 	}
333 
334 	/**
335 	 * Stores the given list of links (incl. UniProt links) after deleting all existing links.
336 	 *
337 	 * @param enzymeUnderDevelopment The enzyme DTO containing the list of links.
338 	 * @param con                    A database connection used to perform the changes in the database.
339 	 * @throws SQLException if a database error occurs.
340 	 */
341 	private void reloadLinks(EnzymeDTO enzymeUnderDevelopment, Connection con) throws SQLException, DomainException {
342 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
343 		assert con != null : "Parameter 'con' must not be null.";
344 		List<EnzymeLink> links = getEnzymeLinkObjects(enzymeUnderDevelopment.getLinks(), enzymeUnderDevelopment.getUniProtLinks());
345 		EnzymeLinkMapper enzymeLinkMapper = new EnzymeLinkMapper();
346 		enzymeLinkMapper.reloadLinks(links, new Long(enzymeUnderDevelopment.getId()),
347 				Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
348 	}
349 
350 	private void reloadComments(List<?> comments, Long enzymeId, Status status, Connection con)
351 	throws SQLException {
352 		assert comments != null : "Parameter 'names' must not be null.";
353 		assert enzymeId != null : "Parameter 'enzymeId' must not be null.";
354 		assert status != null : "Parameter 'status' must not be null.";
355 		assert con != null : "Parameter 'con' must not be null.";
356 		List<EnzymeComment> enzymeComments = new ArrayList<EnzymeComment>();
357 		for (int iii = 0; iii < comments.size(); iii++) {
358 			enzymeComments.add(getEnzymeCommentObject((CommentDTO) comments.get(iii)));
359 		}
360 
361 		EnzymeCommentMapper enzymeCommentMapper = new EnzymeCommentMapper();
362 		enzymeCommentMapper.reload(enzymeComments, enzymeId, status, con);
363 
364 	}
365 
366 	private void reloadReferences(List<?> references, Long enzymeId, Status status,
367 			EnzymeSourceConstant source, Connection con) throws SQLException {
368 		assert references != null : "Parameter 'names' must not be null.";
369 		assert enzymeId != null : "Parameter 'enzymeId' must not be null.";
370 		assert status != null : "Parameter 'status' must not be null.";
371 		assert con != null : "Parameter 'con' must not be null.";
372 		List<Reference> enzymeReferences = new ArrayList<Reference>();
373 		for (int iii = 0; iii < references.size(); iii++) {
374 			enzymeReferences.add(getReferenceObject((ReferenceDTO) references.get(iii)));
375 		}
376 
377 		//if (enzymeReferences.size() > 0) {
378 		EnzymeReferenceMapper enzymeReferenceMapper = new EnzymeReferenceMapper();
379 		enzymeReferenceMapper.reload(enzymeReferences, enzymeId, status, con);
380 		//}
381 	}
382 
383 
384 	// --------------------- Insert methods ----------------------------
385 
386 	/**
387 	 * Inserts the given enzyme information into the database.
388 	 *
389 	 * @param enzymeUnderDevelopment The new enzyme entry to be loaded into the database.
390 	 * @param con                    A database connection used to perform the changes in the database.
391 	 */
392 	private void insertEnzymeEntry(EnzymeDTO enzymeUnderDevelopment, Connection con)
393 	throws SQLException, EcException, DomainException {
394 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
395 		assert con != null : "Parameter 'con' must not be null.";
396 		insertCoreData(enzymeUnderDevelopment, con);
397 		insertNames(enzymeUnderDevelopment, con);
398 		if (enzymeUnderDevelopment.isActive()){
399 			insertReactions(enzymeUnderDevelopment, con);
400 			insertCofactors(enzymeUnderDevelopment, con);
401 			insertLinks(enzymeUnderDevelopment, con);
402 			insertComments(enzymeUnderDevelopment, con);
403 			insertReferences(enzymeUnderDevelopment, con);
404 		}
405 	}
406 
407 	/**
408 	 * Inserts the enzyem's core data (see <code>TABLE enzymes</code>) into the database and assigns a new enzyme ID.
409 	 *
410 	 * @param enzymeUnderDevelopment The new enzyme entry.
411 	 * @param con                    A database connection used to perform the changes in the database.
412 	 * @throws SQLException if a database error occurs.
413 	 * @throws EcException  if an invalid EC number has been used.
414 	 */
415 	private void insertCoreData(EnzymeDTO enzymeUnderDevelopment, Connection con)
416 	throws SQLException, EcException {
417 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
418 		assert con != null : "Parameter 'con' must not be null.";
419 		Long newEnzymeId = enzymeEntryMapper.findNextEnzymeId(con);
420 		enzymeUnderDevelopment.setId(newEnzymeId.toString());
421 		enzymeEntryMapper.insert(newEnzymeId, EnzymeCommissionNumber.valueOf(enzymeUnderDevelopment.getEc()),
422 				Status.fromCode(enzymeUnderDevelopment.getStatusCode()),
423 				EnzymeSourceConstant.valueOf(enzymeUnderDevelopment.getSource()),
424 				enzymeUnderDevelopment.getNote(),
425 				enzymeUnderDevelopment.getHistoryLine(),
426 				enzymeUnderDevelopment.isActive(), con);
427 	}
428 
429 	/**
430 	 * Inserts the new enzyme's names (common name, synonyms and systematic name).
431 	 *
432 	 * @param enzymeUnderDevelopment The new enzyme entry.
433 	 * @param con                    A database connection used to perform the changes in the database.
434 	 */
435 	private void insertNames(EnzymeDTO enzymeUnderDevelopment, Connection con) throws SQLException {
436 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
437 		assert con != null : "Parameter 'con' must not be null.";
438 		EnzymeNameMapper enzymeNameMapper = new EnzymeNameMapper();
439 		List<EnzymeName> enzymeNames = new ArrayList<EnzymeName>();
440 		List<?> commonNames = enzymeUnderDevelopment.getCommonNames();
441 		for (int iii = 0; iii < commonNames.size(); iii++) {
442 			enzymeNames.add(getEnzymeNameObject((EnzymeNameDTO) commonNames.get(iii)));
443 		}
444 		List<?> synonyms = enzymeUnderDevelopment.getSynonyms();
445 		for (int iii = 0; iii < synonyms.size(); iii++) {
446 			enzymeNames.add(getEnzymeNameObject((EnzymeNameDTO) synonyms.get(iii)));
447 		}
448 		if(enzymeUnderDevelopment.getSystematicName() != null &&
449 				!enzymeUnderDevelopment.getSystematicName().getXmlName().equals(""))
450 			enzymeNames.add(getEnzymeNameObject(enzymeUnderDevelopment.getSystematicName()));
451 		enzymeNameMapper.insertNames(enzymeNames, new Long(enzymeUnderDevelopment.getId()),
452 				Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
453 
454 	}
455 
456 	/**
457 	 * Inserts the new enzyme's reactions.
458 	 *
459 	 * @param enzymeUnderDevelopment The new enzyme entry.
460 	 * @param con                    A database connection used to perform the changes in the database.
461 	 */
462 	private void insertReactions(EnzymeDTO enzymeUnderDevelopment, Connection con) throws SQLException {
463 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
464 		assert con != null : "Parameter 'con' must not be null.";
465 		EnzymaticReactions er = new EnzymaticReactions();
466 		for (ReactionDTO reactionDTO : enzymeUnderDevelopment.getReactionDtos()) {
467 			er.add(getReactionObject(reactionDTO), reactionDTO.getView(),
468 					Boolean.parseBoolean(reactionDTO.getIubmb()));
469 		}
470 
471 		if (er.size() > 0) {
472 			enzymeReactionMapper.insert(er, new Long(enzymeUnderDevelopment.getId()), con);
473 		}
474 	}
475 
476 	/**
477 	 * Inserts the new enzyme's cofactors.
478 	 *
479 	 * @param enzymeUnderDevelopment The new enzyme entry.
480 	 * @param con                    A database connection used to perform the changes in the database.
481 	 */
482 	private void insertCofactors(EnzymeDTO enzymeUnderDevelopment, Connection con) throws SQLException {
483 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
484 		assert con != null : "Parameter 'con' must not be null.";
485 		List<Object> enzymeCofactors = new ArrayList<Object>();
486 		List<CofactorDTO> cofactors = enzymeUnderDevelopment.getCofactors();
487 		for (int iii = 0; iii < cofactors.size(); iii++) {
488 			enzymeCofactors.add(getCofactorObject(cofactors.get(iii), con));
489 		}
490 
491 		if (enzymeCofactors.size() > 0) {
492 			EnzymeCofactorMapper enzymeCofactorMapper = new EnzymeCofactorMapper();
493 			enzymeCofactorMapper.insert(enzymeCofactors, new Long(enzymeUnderDevelopment.getId()),
494 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
495 		}
496 	}
497 
498 	/**
499 	 * Inserts the new enzyme's links.
500 	 *
501 	 * @param enzymeUnderDevelopment The new enzyme entry.
502 	 * @param con                    A database connection used to perform the changes in the database.
503 	 */
504 	private void insertLinks(EnzymeDTO enzymeUnderDevelopment, Connection con) throws SQLException, DomainException {
505 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
506 		assert con != null : "Parameter 'con' must not be null.";
507 		List<EnzymeLink> enzymeLinks = getEnzymeLinkObjects(enzymeUnderDevelopment.getLinks(), enzymeUnderDevelopment.getUniProtLinks());
508 		if (enzymeLinks.size() > 0) {
509 			EnzymeLinkMapper enzymeLinkMapper = new EnzymeLinkMapper();
510 			enzymeLinkMapper.insert(enzymeLinks, new Long(enzymeUnderDevelopment.getId()),
511 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
512 		}
513 	}
514 
515 	/**
516 	 * Inserts the new enzyme's comments.
517 	 *
518 	 * @param enzymeUnderDevelopment The new enzyme entry.
519 	 * @param con                    A database connection used to perform the changes in the database.
520 	 */
521 	private void insertComments(EnzymeDTO enzymeUnderDevelopment, Connection con) throws SQLException {
522 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
523 		assert con != null : "Parameter 'con' must not be null.";
524 		List<EnzymeComment> enzymeComments = new ArrayList<EnzymeComment>();
525 		List<?> comments = enzymeUnderDevelopment.getComments();
526 		for (int iii = 0; iii < comments.size(); iii++) {
527 			enzymeComments.add(getEnzymeCommentObject((CommentDTO) comments.get(iii)));
528 		}
529 
530 		if (enzymeComments.size() > 0) {
531 			EnzymeCommentMapper enzymeCommentMapper = new EnzymeCommentMapper();
532 			enzymeCommentMapper.insert(enzymeComments, new Long(enzymeUnderDevelopment.getId()),
533 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
534 		}
535 	}
536 
537 	/**
538 	 * Inserts the new enzyme's references.
539 	 *
540 	 * @param enzymeUnderDevelopment The new enzyme entry.
541 	 * @param con                    A database connection used to perform the changes in the database.
542 	 */
543 	private void insertReferences(EnzymeDTO enzymeUnderDevelopment, Connection con) throws SQLException {
544 		assert enzymeUnderDevelopment != null : "Parameter 'enzymeUnderDevelopment' must not be null.";
545 		assert con != null : "Parameter 'con' must not be null.";
546 		List<Reference> enzymeReferences = new ArrayList<Reference>();
547 		List<?> references = enzymeUnderDevelopment.getReferences();
548 		for (int iii = 0; iii < references.size(); iii++) {
549 			enzymeReferences.add(getReferenceObject((ReferenceDTO) references.get(iii)));
550 		}
551 
552 		if (enzymeReferences.size() > 0) {
553 			EnzymeReferenceMapper enzymeReferenceMapper = new EnzymeReferenceMapper();
554 			enzymeReferenceMapper.insert(enzymeReferences, new Long(enzymeUnderDevelopment.getId()),
555 					Status.fromCode(enzymeUnderDevelopment.getStatusCode()), con);
556 		}
557 	}
558 
559 	// ---------------------- Get domain objects --------------------------------
560 
561 	/**
562 	 * Creates a {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeName} object using a
563 	 * {@link uk.ac.ebi.intenz.webapp.dtos.EnzymeNameDTO} object stored in the enzyme DTO.
564 	 *
565 	 * @param enzymeNameDTO The {@link uk.ac.ebi.intenz.webapp.dtos.EnzymeNameDTO} used to create a
566 	 *                      {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeName} object.
567 	 * @return an instance of {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeName}.
568 	 */
569 	public EnzymeName getEnzymeNameObject(EnzymeNameDTO enzymeNameDTO) {
570 		assert enzymeNameDTO != null : "Parameter 'enzymeNameDTO' must not be null.";
571 		if (enzymeNameDTO.getType().equals(EnzymeNameTypeConstant.COMMON_NAME.toString()))
572 			return EnzymeName.getCommonNameInstance(enzymeNameDTO.getXmlName(),
573 					EnzymeSourceConstant.valueOf(enzymeNameDTO.getSource()),
574 					EnzymeViewConstant.valueOf(enzymeNameDTO.getView()));
575 		if (enzymeNameDTO.getType().equals(EnzymeNameTypeConstant.SYSTEMATIC_NAME.toString()))
576 			return EnzymeName.getSystematicNameInstance(enzymeNameDTO.getXmlName(),
577 					EnzymeSourceConstant.valueOf(enzymeNameDTO.getSource()),
578 					EnzymeViewConstant.valueOf(enzymeNameDTO.getView()));
579 		return EnzymeName.getSynonymInstance(enzymeNameDTO.getXmlName(), EnzymeNameQualifierConstant.valueOf(enzymeNameDTO.getQualifier()),
580 				EnzymeSourceConstant.valueOf(enzymeNameDTO.getSource()),
581 				EnzymeViewConstant.valueOf(enzymeNameDTO.getView()));
582 	}
583 
584 	/**
585 	 * Creates a {@link uk.ac.ebi.rhea.domain.Reaction} object using a
586 	 * {@link uk.ac.ebi.intenz.webapp.dtos.ReactionDTO} object stored in the enzyme DTO.
587 	 *
588 	 * @param reactionDTO The {@link uk.ac.ebi.intenz.webapp.dtos.ReactionDTO} used to create a
589 	 *                    {@link uk.ac.ebi.intenz.domain.enzyme.Reaction} object.
590 	 * @return an instance of {@link uk.ac.ebi.intenz.domain.enzyme.Reaction}.
591 	 */
592 	private Reaction getReactionObject(ReactionDTO reactionDTO) {
593 		assert reactionDTO != null : "Parameter 'reactionDTO' must not be null.";
594 		Reaction reaction = new Reaction(reactionDTO.getId(), reactionDTO.getXmlTextualRepresentation(),
595 				Database.valueOf(reactionDTO.getSource()));
596 		reaction.setStatus(uk.ac.ebi.rhea.domain.Status.valueOf(reactionDTO.getStatus()));
597 		return reaction;
598 	}
599 
600 	/**
601 	 * Creates a {@link uk.ac.ebi.intenz.domain.enzyme.Cofactor} object using a
602 	 * {@link uk.ac.ebi.intenz.webapp.dtos.CofactorDTO} object stored in the enzyme DTO.
603 	 *
604 	 * @param cofactorDTO The {@link uk.ac.ebi.intenz.webapp.dtos.CofactorDTO} used to create a
605 	 *                    {@link uk.ac.ebi.intenz.domain.enzyme.Cofactor} object.
606 	 * @return an instance of {@link uk.ac.ebi.intenz.domain.enzyme.Cofactor}.
607 	 */
608 	private Object getCofactorObject(final CofactorDTO cofactorDTO, final Connection con) {
609 		assert cofactorDTO != null : "Parameter 'cofactorDTO' must not be null.";
610 		Object o = null;
611 		if (cofactorDTO.getCompoundId().indexOf(' ') > -1){ // we have an OperatorSet
612 			OperatorSet.ObjectBuilder builder = new OperatorSet.ObjectBuilder(){
613 				public Object parse(String s) throws Exception {
614 					Long compoundId = Long.valueOf(s);
615 					Compound compound = new RheaCompoundDbReader(con).find(compoundId);
616 					return Cofactor.valueOf(compound, EnzymeSourceConstant.valueOf(cofactorDTO.getSource()),
617 							EnzymeViewConstant.valueOf(cofactorDTO.getView()));
618 				}
619 			};
620 			try {
621                 String[] operators = new String[Cofactor.Operators.values().length];
622                 for (int i = 0; i < operators.length; i++){
623                     operators[i] = Cofactor.Operators.values()[i].getCode();
624                 }
625 				o = OperatorSet.parse(cofactorDTO.getCompoundId(), operators, builder);
626 			} catch (Exception e) {
627 				LOGGER.error(e.getMessage(), e);
628 			}
629 		} else {
630 			Compound compound = Compound.valueOf(Long.valueOf(cofactorDTO.getCompoundId()),
631 					cofactorDTO.getXmlCofactorValue(), null, 0, null, null, null, null);
632 			o = Cofactor.valueOf(compound, EnzymeSourceConstant.valueOf(cofactorDTO.getSource()),
633 					EnzymeViewConstant.valueOf(cofactorDTO.getView()));
634 		}
635 		return o;
636 	}
637 
638 	/**
639 	 * Creates {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeLink} objects using
640 	 * {@link uk.ac.ebi.intenz.webapp.dtos.EnzymeLinkDTO} objects stored in the enzyme DTO.
641 	 *
642 	 * @param links        The {@link uk.ac.ebi.intenz.webapp.dtos.EnzymeLinkDTO} objects used to create
643 	 *                     {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeLink} objects. Contains all links except
644 	 *                     Uniprot links.
645 	 * @param uniprotLinks UniProt {@link uk.ac.ebi.intenz.webapp.dtos.EnzymeLinkDTO} objects also used to create
646 	 *                     {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeLink} objects.
647 	 * @return List {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeLink} objects.
648 	 */
649 	private List<EnzymeLink> getEnzymeLinkObjects(List<?> links, List<?> uniprotLinks) throws DomainException {
650 		assert links != null : "Parameter 'links' must not be null.";
651 		assert uniprotLinks != null : "Parameter 'uniprotLinks' must not be null.";
652 		List<EnzymeLink> enzymeLinks = new ArrayList<EnzymeLink>();
653 		for (int iii = 0; iii < links.size(); iii++) {
654 			EnzymeLinkDTO enzymeLinkDTO = (EnzymeLinkDTO) links.get(iii);
655 			EnzymeLink enzymeLink = EnzymeLink.valueOf(XrefDatabaseConstant.valueOf(enzymeLinkDTO.getDatabaseCode()),
656 					enzymeLinkDTO.getUrl(), enzymeLinkDTO.getAccession(),
657 					enzymeLinkDTO.getName(),
658 					EnzymeSourceConstant.valueOf(enzymeLinkDTO.getSource()),
659 					EnzymeViewConstant.valueOf(enzymeLinkDTO.getView()),
660 					enzymeLinkDTO.getDataComment());
661 			enzymeLinks.add(enzymeLink);
662 		}
663 		for (int iii = 0; iii < uniprotLinks.size(); iii++) {
664 			EnzymeLinkDTO enzymeLinkDTO = (EnzymeLinkDTO) uniprotLinks.get(iii);
665 			EnzymeLink enzymeLink = EnzymeLink.valueOf(XrefDatabaseConstant.valueOf(enzymeLinkDTO.getDatabaseCode()),
666 					enzymeLinkDTO.getUrl(), enzymeLinkDTO.getAccession(),
667 					enzymeLinkDTO.getName(),
668 					EnzymeSourceConstant.valueOf(enzymeLinkDTO.getSource()),
669 					EnzymeViewConstant.valueOf(enzymeLinkDTO.getView()),
670 					enzymeLinkDTO.getDataComment());
671 			enzymeLinks.add(enzymeLink);
672 		}
673 		return enzymeLinks;
674 	}
675 
676 	/**
677 	 * Creates a {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeComment} object using a
678 	 * {@link uk.ac.ebi.intenz.webapp.dtos.CommentDTO} object stored in the enzyme DTO.
679 	 *
680 	 * @param commentDTO The {@link uk.ac.ebi.intenz.webapp.dtos.CommentDTO} object used to create a
681 	 *                   {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeComment} object.
682 	 * @return an instance of {@link uk.ac.ebi.intenz.domain.enzyme.EnzymeComment}.
683 	 */
684 	private EnzymeComment getEnzymeCommentObject(CommentDTO commentDTO) {
685 		assert commentDTO != null : "Parameter 'commentDTO' must not be null.";
686 		return new EnzymeComment(commentDTO.getXmlComment(), EnzymeSourceConstant.valueOf(commentDTO.getSource()),
687 				EnzymeViewConstant.valueOf(commentDTO.getView()));
688 	}
689 
690 	/**
691 	 * Creates a {@link uk.ac.ebi.intenz.domain.reference.Journal},
692 	 * {@link uk.ac.ebi.intenz.domain.reference.Book} or
693 	 * {@link uk.ac.ebi.intenz.domain.reference.Patent} object using a
694 	 * {@link uk.ac.ebi.intenz.webapp.dtos.ReferenceDTO} object stored in the enzyme DTO.
695 	 *
696 	 * @param referenceDTO The {@link uk.ac.ebi.intenz.webapp.dtos.ReferenceDTO} object used to create a
697 	 *                     {@link uk.ac.ebi.intenz.domain.reference.Reference} object.
698 	 * @return an instance of {@link uk.ac.ebi.intenz.domain.reference.Journal},
699 	 *         {@link uk.ac.ebi.intenz.domain.reference.Book} or
700 	 *         {@link uk.ac.ebi.intenz.domain.reference.Patent}.
701 	 */
702 	private Reference getReferenceObject(ReferenceDTO referenceDTO) {
703 		assert referenceDTO != null : "Parameter 'referenceDTO' must not be null.";
704 		Long pubId = null;
705 		if(!referenceDTO.getPubId().equals("")) {
706 			pubId = new Long(referenceDTO.getPubId());
707 		}
708 		if (referenceDTO.getType().equals("J")) {
709 			return new Journal(pubId, referenceDTO.getXmlAuthors(), referenceDTO.getXmlTitle(),
710 					referenceDTO.getYear(), referenceDTO.getXmlPubName(), referenceDTO.getFirstPage(),
711 					referenceDTO.getLastPage(), referenceDTO.getVolume(), referenceDTO.getPubMedId(),
712 					referenceDTO.getMedlineId(), EnzymeViewConstant.valueOf(referenceDTO.getView()),
713 					EnzymeSourceConstant.valueOf(referenceDTO.getSource()));
714 		}
715 		if (referenceDTO.getType().equals("B")) {
716 			return new Book(pubId, referenceDTO.getXmlAuthors(), referenceDTO.getXmlTitle(),
717 					referenceDTO.getYear(), referenceDTO.getFirstPage(), referenceDTO.getLastPage(),
718 					referenceDTO.getXmlPubName(), referenceDTO.getEdition(), referenceDTO.getXmlEditor(),
719 					referenceDTO.getVolume(), referenceDTO.getXmlPublisher(), referenceDTO.getPublisherPlace(),
720 					EnzymeViewConstant.valueOf(referenceDTO.getView()),
721 					EnzymeSourceConstant.valueOf(referenceDTO.getSource()));
722 		}
723 		// N.B.: patent number is currently stored in the field pubMedId (TODO: change this).
724 		return new Patent(pubId, referenceDTO.getXmlAuthors(), referenceDTO.getXmlTitle(),
725 				referenceDTO.getYear(), referenceDTO.getPubMedId(),
726 				EnzymeViewConstant.valueOf(referenceDTO.getView()),
727 				EnzymeSourceConstant.valueOf(referenceDTO.getSource()));
728 	}
729 
730 	public void valueBound(HttpSessionBindingEvent arg0) {
731 		// no-op
732 	}
733 
734 	public void valueUnbound(HttpSessionBindingEvent arg0) {
735 		enzymeEntryMapper.close();
736 		try {
737 			enzymeReactionMapper.close();
738 		} catch (MapperException e) {
739 			LOGGER.error("While closing session", e);
740 		}
741 	}
742 
743 }