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