View Javadoc
1   package com.randomnoun.common.spring;
2   
3   /* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a
4    * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html)
5    */
6   
7   import java.io.*;
8   import java.sql.*;
9   import java.util.*;
10  
11  import javax.sql.*;
12  
13  import org.apache.log4j.Logger;
14  import org.springframework.jdbc.core.*;
15  import org.springframework.jdbc.support.DatabaseMetaDataCallback;
16  import org.springframework.jdbc.support.JdbcUtils;
17  import org.springframework.jdbc.support.MetaDataAccessException;
18  import org.springframework.jdbc.support.lob.DefaultLobHandler;
19  import org.springframework.jdbc.support.lob.LobHandler;
20  
21  import com.randomnoun.common.StreamUtil;
22  import com.randomnoun.common.spring.ClobRowMapper;
23  
24  /**
25   * This class is intended to replace the standard RowMapper provided by Spring
26   * to allow CLOBs to be treated as String objects transparently (i.e. the Map
27   * which represents a row returned by this class will not contain any
28   * oracle.sql.CLOB objects).
29   *
30   * <p>LobHandlers aren't required in recent Oracle drivers, so this entire class is 
31   * probably obsolete these days.
32   *
33   * 
34   * @author knoxg
35   */
36  public class ClobRowMapper implements RowMapper<Map<String, Object>>
37  {
38      
39      /** Logger for this class */
40      public final Logger logger = Logger.getLogger(ClobRowMapper.class);
41  
42      /** Oracle Large OBject handler. */
43      final LobHandler lobHandler; 
44  
45      public String detectDatabase(DataSource ds) {
46          logger.debug("Looking up default SQLErrorCodes for DataSource");
47          String dbName = "unknown";
48          
49          try {
50              @SuppressWarnings("unchecked")
51  			Map<String, Object> dbmdInfo = (Map<String, Object>) JdbcUtils.extractDatabaseMetaData(ds, new DatabaseMetaDataCallback() {
52                  public Object processMetaData(DatabaseMetaData dbmd) throws SQLException {
53                      Map<String, Object> info = new HashMap<String, Object>(2);
54                      if (dbmd != null) {
55                          info.put("DatabaseProductName", dbmd.getDatabaseProductName());
56                          info.put("DriverVersion", dbmd.getDriverVersion());
57                      }
58                      return info;
59                  }
60              });
61              if (dbmdInfo != null) {
62                  
63                  // should always be the case outside of test environments
64                  dbName = (String) dbmdInfo.get("DatabaseProductName");
65                  String driverVersion = (String) dbmdInfo.get("DriverVersion");
66                  logger.debug("Found dbName='" + dbName + "', driverVerson='" + driverVersion + "'");
67  
68                  if (dbName != null && dbName.startsWith("DB2")) {
69                      dbName = "DB2";
70                  }
71                  /* 
72                  if (dbName != null) {
73                      this.dataSourceProductName.put(ds, dbName);
74                      logger.info("Database Product Name is " + dbName);
75                      logger.info("Driver Version is " + driverVersion);
76                      SQLErrorCodes sec = (SQLErrorCodes) this.rdbmsErrorCodes.get(dbName);
77                      if (sec != null) {
78                          return sec;
79                      }
80                      logger.info("Error Codes for " + dbName + " not found");
81                  }
82                  */
83              }
84          }
85          catch (MetaDataAccessException ex) {
86              logger.warn("Error while getting database metadata", ex);
87          }
88  
89          // fallback is to return an empty ErrorCodes instance
90          logger.debug("Returning dbName='" + dbName + "'");
91          return dbName;
92      }
93              
94              
95      /**
96       * Creates a new ClobRowMapper object.
97       */
98      public ClobRowMapper(JdbcTemplate jt)
99      {
100     	lobHandler = new DefaultLobHandler();
101     	/*
102         DataSource ds = jt.getDataSource();
103         try {
104             if (detectDatabase(ds).equals("DB2")) {
105             	lobHandler = new DefaultLobHandler();
106             } else {
107                 // lobHandler = new OracleLobHandler();
108             }
109         } catch (Exception e) {
110             throw new RuntimeException("Could not instantiate lobHandler");
111         }
112         */
113     }
114 
115     /** Map rows to a disconnected HashMap representation */
116     public Map<String, Object> mapRow(ResultSet rs, int rowNum)
117         throws SQLException
118     {
119         Map<String, Object> row = new HashMap<String, Object>();
120         String key;
121         Object value;
122 
123         ResultSetMetaData metaData = rs.getMetaData();
124         int columnCount = metaData.getColumnCount();
125 
126         for (int i = 1; i <= columnCount; i++) {
127 			// key.toUpperCase required for SqlServer; DB2 & Oracle will automatically
128 			// do this anyway
129             key = metaData.getColumnLabel(i).toUpperCase();  
130             value = rs.getObject(i);
131             if (value != null && value.getClass().getName().equals("oracle.sql.CLOB")) {
132                 value = lobHandler.getClobAsString(rs, i);
133             } else if (value instanceof java.sql.Clob) {
134                 Clob clob = (Clob) value;
135                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
136                 try {
137                     StreamUtil.copyStream(clob.getAsciiStream(), baos, 1024);
138                 } catch (IOException ioe) {
139                     throw (SQLException) new SQLException("IO error transferring CLOB").initCause(ioe);
140                 }
141                 
142                 value = baos.toString();
143             }
144             row.put(key, value);
145         }
146 
147         return row;
148     }
149 }