View Javadoc

1   package uk.ac.ebi.intenz.mapper;
2   
3   import java.io.IOException;
4   import java.sql.Connection;
5   import java.sql.PreparedStatement;
6   import java.sql.ResultSet;
7   import java.sql.SQLException;
8   
9   import org.apache.log4j.Logger;
10  
11  import uk.ac.ebi.intenz.domain.constants.EnzymeViewConstant;
12  import uk.ac.ebi.intenz.domain.enzyme.EnzymaticReactions;
13  import uk.ac.ebi.rhea.domain.Database;
14  import uk.ac.ebi.rhea.domain.Reaction;
15  import uk.ac.ebi.rhea.domain.Status;
16  import uk.ac.ebi.rhea.mapper.MapperException;
17  import uk.ac.ebi.rhea.mapper.db.RheaCompoundDbReader;
18  import uk.ac.ebi.rhea.mapper.db.RheaDbReader;
19  
20  /**
21   * Maps reaction information to the corresponding database table.
22   * <br>
23   * <b>IMPORTANT</b>: after using instances of this class, call the
24   * {@link #close()} method, otherwise the underlying Rhea mapper objects will
25   * keep their statements open.
26   * @author Michael Darsow,
27   * 		Rafael Alcántara
28   * @version $Revision: 1.6 $ $Date: 2009/05/26 14:59:09 $
29   */
30  public class EnzymeReactionMapper {
31  
32  	private static final Logger LOGGER =
33  		Logger.getLogger(EnzymeReactionMapper.class.getName());
34  	
35  	protected RheaDbReader rheaReader;
36  	
37    public EnzymeReactionMapper(){
38  	  try {
39  		rheaReader = new RheaDbReader(
40  		        new RheaCompoundDbReader((Connection) null));
41  	} catch (IOException e) {
42  		throw new RuntimeException(e);
43  	}
44    }
45  
46    private static final String SEL_COLS_FROM_TBLS =
47  	  "SELECT rm.reaction_id, rm.web_view, rm.order_in, rm.iubmb," +
48  	  " ir.equation, ir.source, ir.qualifiers, ir.status" +
49  	  " FROM reactions_map rm, intenz_reactions ir";
50  
51    private static final String FIND_STM =
52  	  SEL_COLS_FROM_TBLS +
53  	  " WHERE rm.enzyme_id = ? AND rm.reaction_id = ir.reaction_id" +
54  	  " ORDER BY rm.order_in";
55  
56    private static final String FIND_SIB_STM =
57  	  SEL_COLS_FROM_TBLS +
58  	" WHERE rm.enzyme_id = ? AND rm.reaction_id = ir.reaction_id" +
59  	" AND (rm.web_view  LIKE '%SIB%' OR rm.web_view = 'INTENZ')" +
60  	" ORDER BY rm.order_in";
61  
62    private static final String INSERT_STM =
63  	  "INSERT INTO reactions_map (reaction_id, enzyme_id, web_view, iubmb," +
64  	  " order_in) VALUES (?, ?, ?, ?, ?)";
65  
66    private static final String DELETE_ALL_STM =
67  	  "DELETE reactions_map WHERE enzyme_id = ?";
68  
69    /* Abstract reactions in old REACTIONS table */
70    
71  	private static final String SEL_ABSTRACT_COLS_FROM_TBLS =
72  		"SELECT equation, web_view, order_in, source, NULL reaction_id," +
73  		" 'N' iubmb, NULL qualifiers, status FROM reactions";
74  
75  	private static final String FIND_ABSTRACT_STM =
76  		SEL_ABSTRACT_COLS_FROM_TBLS +
77  		" WHERE enzyme_id = ? ORDER BY order_in";
78  
79  	private static final String FIND_ABSTRACT_SIB_STM =
80  		SEL_ABSTRACT_COLS_FROM_TBLS + " WHERE enzyme_id = ? AND" +
81  		" (web_view LIKE '%SIB%' OR web_view = 'INTENZ') ORDER BY order_in";
82  
83  	private static final String INSERT_ABSTRACT_STM =
84  		"INSERT INTO reactions (enzyme_id, equation, order_in, status, source," +
85  		" web_view) VALUES (?, ?, ?, ?, ?, ?)";
86  
87    private static final String DELETE_ALL_ABSTRACT_STM =
88  	  "DELETE reactions WHERE enzyme_id = ?";
89  
90    /**
91     * Tries to find reaction information about an enzyme.
92     *
93     * @param enzymeId Enzyme ID of entry.
94     * @param con      The logical connection.
95     * @return a <code>EnzymaticReactions</code> object containing
96     * 	<code>Reaction</code>instances or <code>null</code> if nothing has been found.
97     * @throws SQLException in case of a generic database problem.
98     * @throws MapperException in case of problem retrieving Rhea reactions.
99     */
100   public EnzymaticReactions find(Long enzymeId, Connection con)
101   throws SQLException, MapperException {
102         if (enzymeId == null) {
103             throw new NullPointerException("Parameter 'enzymeId' must not be null.");
104         }
105         if (con == null) {
106             throw new NullPointerException("Parameter 'con' must not be null.");
107         }
108 
109         EnzymaticReactions result = find(enzymeId, con, FIND_STM);
110     	EnzymaticReactions abstractReactions =
111     		find(enzymeId, con, FIND_ABSTRACT_STM);
112         if (result == null) { // no Rhea reactions
113             result = abstractReactions;
114         } else {
115         	if (abstractReactions != null) result.add(abstractReactions);
116         }
117         return result;
118     }
119 
120   /**
121    * Exports all reactions which are displayed in the ENZYME view.
122    *
123    * Affected table rows will be locked.
124    *
125    * @param enzymeId The enzyme ID used to retreive the related reactions.
126    * @param con The database connection.
127    * @return an <code>EnzymaticReactions</code> containing reactions
128    * 	or <code>null</code> if no reaction could be found.
129    * @throws SQLException if a generic database error occured.
130    * @throws MapperException in case of problem retrieving Rhea reactions.
131    * @throws NullPointerException if either of the parameters is <code>null</code>.
132    */
133   public EnzymaticReactions exportSibReactions(Long enzymeId, Connection con)
134   throws SQLException, MapperException {
135     if (enzymeId == null) throw new NullPointerException("Parameter 'enzymeId' must not be null.");
136     if (con == null) throw new NullPointerException("Parameter 'con' must not be null.");
137 
138     EnzymaticReactions result = find(enzymeId, con, FIND_SIB_STM);
139     if (result == null)
140     	result = find(enzymeId, con, FIND_ABSTRACT_SIB_STM);
141     else
142         result.add(find(enzymeId, con, FIND_ABSTRACT_SIB_STM));
143     return result;
144   }
145   
146   private EnzymaticReactions find(Long enzymeId, Connection con,
147 		  String findQuery)
148   throws SQLException, MapperException {
149 	  EnzymaticReactions result = null;
150 	  PreparedStatement findStatement = null;
151 	  ResultSet rs = null;
152 	  try {
153 		  findStatement = con.prepareStatement(findQuery);
154 		  findStatement.setLong(1, enzymeId.longValue());
155 		  rs = findStatement.executeQuery();
156 		  while (rs.next()) {
157 			  if (result == null) result = new EnzymaticReactions();
158               result.add(loadReaction(rs), rs.getString("web_view"),
159             		  rs.getString("iubmb").equalsIgnoreCase("Y"));
160 		  }
161 	  } finally {
162 		  if (rs != null) rs.close();
163 		  if (findStatement != null) findStatement.close();
164 	  }
165 	  return result;
166   }
167 
168   /**
169    * Stores the given list of reactions into the database.
170    *
171    * @param reactions The vector of reactions.
172    * @param enzymeId  The enzyme ID.
173    * @param con       ...
174    * @throws SQLException
175    */
176   public void insert(EnzymaticReactions reactions, Long enzymeId, Connection con)
177   throws SQLException {
178     if (reactions == null) throw new NullPointerException("Parameter 'reactions' must not be null.");
179     if (enzymeId == null) throw new NullPointerException("Parameter 'enzymeId' must not be null.");
180     if (con == null) throw new NullPointerException("Parameter 'con' must not be null.");
181 
182     for (int i = 0; i < reactions.size(); i++) {
183 		Reaction reaction = reactions.getReaction(i);
184 		EnzymeViewConstant view = reactions.getReactionView(i);
185 		boolean iubmb = reactions.getReactionIubmbFlag(i);
186     	if (reaction.getId().equals(Reaction.NO_ID_ASSIGNED)){
187     		insertReaction(enzymeId, reaction, view, iubmb, i+1, con);
188     	} else {
189     		insertMapping(enzymeId, reaction.getId(), view, iubmb, i+1, con);
190     	}
191     }
192   }
193   
194   /**
195    * Inserts abstract reactions into the old REACTIONS table.
196    * @param enzymeId
197    * @param reaction
198    * @param view
199    * @param iubmb
200    * @param orderIn
201    * @param con
202    * @throws SQLException
203    */
204   private void insertReaction(Long enzymeId, Reaction reaction,
205 		  EnzymeViewConstant view, boolean iubmb, int orderIn, Connection con)
206   throws SQLException {
207 	  PreparedStatement stm = null;
208 	  try {
209 		  stm = con.prepareStatement(INSERT_ABSTRACT_STM);
210 		  stm.setLong(1, enzymeId);
211 		  stm.setString(2, reaction.getTextualRepresentation());
212 		  stm.setInt(3, orderIn);
213 		  stm.setString(4, reaction.getStatus().toString()); // NO status
214 		  stm.setString(5, reaction.getSource().toString());
215 		  stm.setString(6, view.toString());
216 		  stm.execute();
217 	  } finally {
218 		  if (stm != null) stm.close();
219 	  }
220   }
221   
222   /**
223    * Inserts a mapping reaction-enzyme into the database.
224    * @param enzymeId
225    * @param reactionId
226    * @param view
227    * @param iubmb
228    * @param orderIn
229    * @param con
230  * @throws SQLException
231    */
232   public void insertMapping(Long enzymeId, Long reactionId,
233 		  EnzymeViewConstant view, boolean iubmb,
234 		  int orderIn, Connection con) throws SQLException{
235 	  PreparedStatement stm = null;
236 	  try {
237 		  stm = con.prepareStatement(INSERT_STM);
238 		  stm.setLong(1, reactionId);
239 		  stm.setLong(2, enzymeId);
240 		  stm.setString(3, view.toString());
241 		  stm.setString(4, iubmb? "Y" : "N");
242 		  stm.setInt(5, orderIn);
243 		  stm.execute();
244 		  LOGGER.info("[MAPPED] enzyme_id=" + enzymeId + " to reaction_id=" + reactionId);
245 	  } finally {
246 		  if (stm != null) stm.close();
247 	  }
248   }
249 
250   /**
251    * Replace the reactions in the database related to one enzyme
252    * with those passed as parameter.
253    *
254    * @param enzymeId  The enzyme ID.
255    * @param reactions The vector of reactions.
256    * @param con
257    * @throws SQLException
258    */
259   public void update(Long enzymeId, EnzymaticReactions reactions, Connection con)
260   throws SQLException {
261     deleteAll(enzymeId, con);
262     insert(reactions, enzymeId, con);
263   }
264 
265   /**
266    * Deletes all reactions mappings and abstract reactions related to one enzyme instance.
267    *
268    * @param enzymeId Enzyme ID of the enzyme instance.
269    * @param con      ...
270    * @throws SQLException
271    */
272   void deleteAll(Long enzymeId, Connection con) throws SQLException {
273     if (enzymeId == null) throw new NullPointerException("Parameter 'enzymeId' must not be null.");
274     if (con == null) throw new NullPointerException("Parameter 'con' must not be null.");
275 
276     PreparedStatement stm = null;
277     try {
278       stm = con.prepareStatement(DELETE_ALL_STM);
279       stm.setLong(1, enzymeId.longValue());
280       stm.execute();
281       stm.close();
282       stm = con.prepareStatement(DELETE_ALL_ABSTRACT_STM);
283       stm.setLong(1, enzymeId.longValue());
284       stm.execute();
285     } finally {
286       if (stm != null) stm.close();
287     }
288   }
289 
290   /**
291    * Creates an empty Reaction object, with just an equation, source and status.
292    * The reaction ID will be <code>null</code> for old plain text reactions, not
293    * <code>null</code> in case of error while reading data from Rhea.
294    * @param reactionId
295    * @param equation
296    * @param source A database code
297    * @param status
298    * @return
299    * @throws java.sql.SQLException
300    */
301     private Reaction loadEmtpyReaction(Long reactionId, String equation,
302             String source, String status)
303     throws SQLException {
304         Reaction reaction = new Reaction(reactionId, equation, Database.fromCode(source));
305         reaction.setStatus(Status.valueOf(status));
306         return reaction;
307     }
308 
309   /**
310    * Creates the <code>Reaction</code> object from the given result set.
311    *
312    * @param rs The result set object.
313    * @return a {@link Reaction}
314    * @throws SQLException in case of a generic database problem.
315    * @throws MapperException in case of problem retrieving the Rhea reaction.
316    */
317   private Reaction loadReaction(ResultSet rs) throws SQLException, MapperException {
318     assert rs != null : "Parameter 'rs' must not be null.";
319 
320     String equation = rs.getString("equation");
321     String source = rs.getString("source");
322     Long reactionId = rs.getLong("reaction_id");
323     String status = rs.getString("status");
324 	// Convert enzyme status codes to Rhea-ction status codes:
325 	if (status.equals("SU") || status.equals("PR")) status = "NO";
326     Reaction reaction;
327     if (reactionId.equals(0L)){
328         reaction = loadEmtpyReaction(reactionId, equation, source, status);
329     } else { // get the whole reaction
330         try {
331             rheaReader.setConnection(rs.getStatement().getConnection());
332             reaction = rheaReader.findByReactionId(reactionId);
333         } catch (Exception ex) {
334             LOGGER.error("Unable to retrieve reaction from Rhea", ex);
335             reaction = loadEmtpyReaction(reactionId, equation, source, status);
336         } finally {
337         	rheaReader.close();
338         }
339     }
340     return reaction;
341   }
342 
343 	public void close() throws MapperException {
344 		rheaReader.close();
345 	}
346 
347 	@Override
348 	protected void finalize() throws Throwable {
349 		close();
350 	}
351 
352 }