Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / impl / ResulSetControlerBase.java @ 45097

History | View | Annotate | Download (8.03 KB)

1
package org.gvsig.fmap.dal.store.jdbc2.impl;
2

    
3
import java.sql.Connection;
4
import java.sql.PreparedStatement;
5
import java.sql.ResultSet;
6
import java.sql.SQLException;
7
import java.sql.Statement;
8
import java.util.ArrayList;
9
import java.util.HashMap;
10
import java.util.List;
11
import java.util.Map;
12
import org.gvsig.fmap.dal.exception.DataException;
13
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
14
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecutePreparedSQLException;
15
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
16
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
17
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler;
18
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
19
import org.gvsig.tools.dispose.Disposable;
20
import org.gvsig.tools.dispose.DisposeUtils;
21
import org.slf4j.Logger;
22
import org.slf4j.LoggerFactory;
23

    
24
public class ResulSetControlerBase implements ResulSetControler {
25

    
26
    final static private Logger LOGGER = LoggerFactory.getLogger(ResulSetControlerBase.class);
27

    
28
    public class ResultSetEntryBase implements ResultSetEntry {
29

    
30
        private ResultSet resultSet = null;
31
        private final int id;
32
        private long lastUse = 0;
33
        private String sql;
34
        private final FeatureAttributeDescriptor[] columns;
35
        private final String[] extraValueNames;
36

    
37
        public ResultSetEntryBase(ResultSet resulSet, String sql, FeatureAttributeDescriptor[] columns, String[] extraValueNames) {
38
            this.resultSet = resulSet;
39
            this.id = nextid++;
40
            this.sql = sql;
41
            this.columns = columns;
42
            this.extraValueNames = extraValueNames;
43
            used();
44
            resulSets.put(this.getID(), this);
45
            if( LOGGER.isDebugEnabled() ) {
46
                LOGGER.debug("["+JDBCUtils.getConnId(resulSet)+"] ResultSetEntryBase "+JDBCUtils.getHexId(this)+" "+sql);
47
            }
48
        }
49

    
50
        private void used() {
51
            lastUse = System.currentTimeMillis();
52
        }
53

    
54
        @Override
55
        public ResultSet get() {
56
            used();
57
            return resultSet;
58
        }
59

    
60
        @Override
61
        public int getID() {
62
            return this.id;
63
        }
64

    
65
        @Override
66
        public boolean isZombie() {
67
            if( this.resultSet == null ) {
68
                return true;
69
            }
70
            return System.currentTimeMillis() - lastUse > mlsecondsToZombie;
71
        }
72

    
73
        @Override
74
        public String getSQL() {
75
            return this.sql;
76
        }
77

    
78
        @Override
79
        public String[] getExtraValueNames() {
80
            return this.extraValueNames;
81
        }
82
        
83
        @Override
84
        public FeatureAttributeDescriptor[] getColumns() {
85
            return this.columns;
86
        }
87
        
88
        @Override
89
        public Object getObject(int columnIndex) throws SQLException {
90
            used();
91
            return this.resultSet.getObject(columnIndex);
92
        }
93

    
94
        @Override
95
        public byte[] getBytes(int columnIndex) throws SQLException {
96
            used();
97
            return this.resultSet.getBytes(columnIndex);
98
        }
99

    
100
        @Override
101
        public boolean next() throws SQLException {
102
            return this.resultSet.next();
103
        }
104

    
105
        @Override
106
        public void close() throws Exception {
107
            if( LOGGER.isDebugEnabled() ) {
108
                LOGGER.debug("["+JDBCUtils.getConnId(this.resultSet)+"] ResultSetEntryBase close "+JDBCUtils.getHexId(this));
109
            }
110
            if( this.resultSet == null ) {
111
                // Already close
112
                return;
113
            }
114
            Statement st = null;
115
            Connection con = null;
116
            try {
117
                resulSets.remove(this.getID());
118
                st = this.resultSet.getStatement();
119
                if( st != null ) {
120
                    con = st.getConnection();
121
                }
122
            } catch(Exception ex) {
123
                LOGGER.warn("Problems closing ResulSetEntryBase.",ex);
124
            }
125
            JDBCUtils.closeQuietly(this.resultSet);
126
            JDBCUtils.closeQuietly(st);
127
            helper.closeConnection(con);
128
            this.resultSet = null;
129
            LOGGER.trace(
130
                    "Close ResulSetEntryBase id {} (total {})",
131
                    this.getID(),
132
                    getOpenCount()
133
            );
134
            pack();
135
        }
136

    
137
    }
138

    
139
    private int nextid = 1;
140

    
141
    private Map<Integer, ResultSetEntryBase> resulSets;
142

    
143
    private long mlsecondsToZombie = 1000 * 60 * 10; // 10 Min
144

    
145
    private JDBCHelper helper = null;
146

    
147
    public ResulSetControlerBase(JDBCHelper helper) {
148
        this.helper = helper;
149
        this.resulSets = new HashMap<>();
150
        this.nextid = 1;
151
    }
152

    
153
    @Override
154
    public long getTimeToZombie() {
155
        return mlsecondsToZombie;
156
    }
157

    
158
    @Override
159
    public void setTimeToZombie(long mlSeconds) {
160
        mlsecondsToZombie = mlSeconds;
161
    }
162

    
163
    @Override
164
    public void close() throws Exception {
165
        this.closeAll();
166
        this.helper = null;
167
        this.resulSets = null;
168
        this.nextid = -10;
169
    }
170

    
171
    @Override
172
    public ResultSetEntryBase create(
173
            String sql, 
174
            int fetchSize, 
175
            FeatureAttributeDescriptor[] columns,
176
            String[] extraValueNames) throws DataException {
177
        return create(sql, null, fetchSize, columns, extraValueNames);
178
    }
179

    
180
    @Override
181
    public synchronized ResultSetEntryBase create(
182
            String sql, 
183
            List<Object> values, 
184
            int fetchSize, 
185
            FeatureAttributeDescriptor[] columns, 
186
            String[] extraValueNames) throws DataException {
187
        this.pack();
188
        ResultSet rs = null;
189
        Connection conn = null;
190
        PreparedStatement st = null;
191
        Disposable paramsDisposer = null;
192
        try {
193
            conn = helper.getConnection();
194
            conn.setAutoCommit(false);
195
            st = conn.prepareStatement(sql);
196

    
197
            JDBCSQLBuilderBase sqlbuilder = helper.createSQLBuilder();
198
            paramsDisposer = sqlbuilder.setStatementParameters(st, values, helper.getGeometrySupportType());
199

    
200
            if (fetchSize > 0) {
201
                // See parameter "SelectMethod" of SQL Server Connection Properties
202
                // https://docs.oracle.com/cd/E13157_01/wlevs/docs30/jdbc_drivers/mssqlserver.html
203
                st.setFetchSize(fetchSize);
204
            }
205
            rs = JDBCUtils.executeQuery(st, sql);
206
            if (fetchSize > 0) {
207
                rs.setFetchSize(fetchSize);
208
            }
209
            ResultSetEntryBase rsentry = new ResultSetEntryBase(rs, sql, columns,  extraValueNames);
210
            return rsentry;
211

    
212
        } catch (SQLException e) {
213
            JDBCUtils.closeQuietly(rs);
214
            JDBCUtils.closeQuietly(st);
215
            this.helper.closeConnectionQuietly(conn);
216
            throw new JDBCExecutePreparedSQLException(sql, values, e);
217
        } finally {
218
            DisposeUtils.disposeQuietly(paramsDisposer);
219
        }
220
    }
221

    
222
    @Override
223
    public synchronized void closeAll() {
224

    
225
        // Para evitar problemas de concurrencia al eliminar elementos del
226
        // map mientras lo recorremos, cargamos las entredas en un List
227
        List<ResultSetEntryBase> entries = new ArrayList<>();
228
        entries.addAll(this.resulSets.values());
229

    
230
        for (ResultSetEntryBase entry : entries) {
231
            JDBCUtils.closeQuietly(entry);
232
        }
233
    }
234

    
235
    @Override
236
    public synchronized void pack() {
237
        // Para evitar problemas de concurrencia al eliminar elementos del
238
        // map mientras lo recorremos, cargamos las entredas en un List
239
        List<ResultSetEntryBase> entries = new ArrayList<>();
240
        entries.addAll(this.resulSets.values());
241

    
242
        int maxID = 0;
243
        for (ResultSetEntryBase entry : entries) {
244
            if (entry.isZombie()) {
245
                JDBCUtils.closeQuietly(entry);
246
            } else {
247
                if (entry.getID() > maxID) {
248
                    maxID = entry.getID();
249
                }
250
            }
251
        }
252
        this.nextid = maxID + 1;
253
    }
254

    
255
    @Override
256
    public synchronized int getOpenCount() {
257
        return this.resulSets.size();
258
    }
259
}