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 @ 44058

History | View | Annotate | Download (7.46 KB)

1 43020 jjdelcerro
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 43358 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
14 43020 jjdelcerro
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 43629 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
19
import org.gvsig.tools.dispose.Disposable;
20
import org.gvsig.tools.dispose.DisposeUtils;
21 43020 jjdelcerro
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 43358 jjdelcerro
        private final FeatureAttributeDescriptor[] columns;
35 43020 jjdelcerro
36 43358 jjdelcerro
        public ResultSetEntryBase(ResultSet resulSet, FeatureAttributeDescriptor[] columns) {
37
            this(resulSet,null, columns);
38 43020 jjdelcerro
        }
39
40 43358 jjdelcerro
        public ResultSetEntryBase(ResultSet resulSet, String sql, FeatureAttributeDescriptor[] columns) {
41 43020 jjdelcerro
            this.resultSet = resulSet;
42
            this.id = nextid++;
43
            this.sql = sql;
44 43358 jjdelcerro
            this.columns = columns;
45 43020 jjdelcerro
            used();
46
            resulSets.put(this.getID(), this);
47
        }
48
49
        private void used() {
50
            lastUse = System.currentTimeMillis();
51
        }
52
53
        @Override
54
        public ResultSet get() {
55
            used();
56
            return resultSet;
57
        }
58
59
        @Override
60
        public int getID() {
61
            return this.id;
62
        }
63
64
        @Override
65
        public boolean isZombie() {
66
            if( this.resultSet == null ) {
67
                return true;
68
            }
69
            return System.currentTimeMillis() - lastUse > mlsecondsToZombie;
70
        }
71
72
        @Override
73
        public String getSQL() {
74
            return this.sql;
75
        }
76
77 43629 jjdelcerro
        @Override
78 43358 jjdelcerro
        public FeatureAttributeDescriptor[] getColumns() {
79
            return this.columns;
80
        }
81
82 43020 jjdelcerro
        @Override
83
        public Object getObject(int columnIndex) throws SQLException {
84
            used();
85
            return this.resultSet.getObject(columnIndex);
86
        }
87
88
        @Override
89
        public byte[] getBytes(int columnIndex) throws SQLException {
90
            used();
91
            return this.resultSet.getBytes(columnIndex);
92
        }
93
94
        @Override
95
        public boolean next() throws SQLException {
96
            return this.resultSet.next();
97
        }
98
99
        @Override
100
        public void close() throws Exception {
101
            if( this.resultSet == null ) {
102
                // Already close
103
                return;
104
            }
105
            Statement st = null;
106
            Connection con = null;
107
            try {
108
                resulSets.remove(this.getID());
109
                st = this.resultSet.getStatement();
110
                if( st != null ) {
111
                    con = st.getConnection();
112
                }
113
            } catch(Exception ex) {
114
                logger.warn("Problems closing ResulSetEntryBase.",ex);
115
            }
116
            JDBCUtils.closeQuietly(this.resultSet);
117
            JDBCUtils.closeQuietly(st);
118 43377 jjdelcerro
            helper.closeConnection(con);
119 43020 jjdelcerro
            this.resultSet = null;
120
            logger.debug(
121
                    "Close ResulSetEntryBase id {} (total {})",
122
                    this.getID(),
123
                    getOpenCount()
124
            );
125
            pack();
126
        }
127
128
    }
129
130
    private int nextid = 1;
131
132
    private Map<Integer, ResultSetEntryBase> resulSets;
133
134
    private long mlsecondsToZombie = 1000 * 60 * 10; // 10 Min
135
136
    private JDBCHelper helper = null;
137
138
    public ResulSetControlerBase(JDBCHelper helper) {
139
        this.helper = helper;
140
        this.resulSets = new HashMap<>();
141
        this.nextid = 1;
142
    }
143
144
    @Override
145
    public long getTimeToZombie() {
146
        return mlsecondsToZombie;
147
    }
148
149
    @Override
150
    public void setTimeToZombie(long mlSeconds) {
151
        mlsecondsToZombie = mlSeconds;
152
    }
153
154
    @Override
155
    public void close() throws Exception {
156
        this.closeAll();
157
        this.helper = null;
158
        this.resulSets = null;
159
        this.nextid = -10;
160
    }
161
162
    @Override
163 43358 jjdelcerro
    public ResultSetEntryBase create(
164
            String sql,
165
            int fetchSize,
166
            FeatureAttributeDescriptor[] columns) throws DataException {
167
        return create(sql, null, fetchSize, columns);
168 43020 jjdelcerro
    }
169
170
    @Override
171
    public synchronized ResultSetEntryBase create(
172
            final String sql,
173
            final List values,
174 43358 jjdelcerro
            final int fetchSize,
175
            FeatureAttributeDescriptor[] columns) throws DataException {
176 43020 jjdelcerro
177
        this.pack();
178
        ResultSet rs = null;
179
        Connection conn = null;
180
        PreparedStatement st = null;
181 43629 jjdelcerro
        Disposable paramsDisposer = null;
182 43020 jjdelcerro
        try {
183
            conn = helper.getConnection();
184
            conn.setAutoCommit(false);
185
            st = conn.prepareStatement(sql);
186
187 43629 jjdelcerro
            JDBCSQLBuilderBase sqlbuilder = helper.createSQLBuilder();
188
            paramsDisposer = sqlbuilder.setStatementParameters(st, values, helper.getGeometrySupportType());
189 43020 jjdelcerro
190
            if (fetchSize > 0) {
191 43358 jjdelcerro
                // See parameter "SelectMethod" of SQL Server Connection Properties
192
                // https://docs.oracle.com/cd/E13157_01/wlevs/docs30/jdbc_drivers/mssqlserver.html
193 43020 jjdelcerro
                st.setFetchSize(fetchSize);
194
            }
195
            rs = JDBCUtils.executeQuery(st, sql);
196
            if (fetchSize > 0) {
197
                rs.setFetchSize(fetchSize);
198
            }
199 43629 jjdelcerro
            ResultSetEntryBase rsentry = new ResultSetEntryBase(rs, sql, columns);
200
            return rsentry;
201 43020 jjdelcerro
202
        } catch (SQLException e) {
203
            JDBCUtils.closeQuietly(rs);
204
            JDBCUtils.closeQuietly(st);
205
            JDBCUtils.closeQuietly(conn);
206
            throw new JDBCExecutePreparedSQLException(sql, values, e);
207 43629 jjdelcerro
        } finally {
208
            DisposeUtils.disposeQuietly(paramsDisposer);
209 43020 jjdelcerro
        }
210
    }
211
212
    @Override
213
    public synchronized void closeAll() {
214
215
        // Para evitar problemas de concurrencia al eliminar elementos del
216
        // map mientras lo recorremos, cargamos las entredas en un List
217
        List<ResultSetEntryBase> entries = new ArrayList<>();
218
        entries.addAll(this.resulSets.values());
219
220
        for (ResultSetEntryBase entry : entries) {
221
            JDBCUtils.closeQuietly(entry);
222
        }
223
    }
224
225
    @Override
226
    public synchronized void pack() {
227
        // Para evitar problemas de concurrencia al eliminar elementos del
228
        // map mientras lo recorremos, cargamos las entredas en un List
229
        List<ResultSetEntryBase> entries = new ArrayList<>();
230
        entries.addAll(this.resulSets.values());
231
232
        int maxID = 0;
233
        for (ResultSetEntryBase entry : entries) {
234
            if (entry.isZombie()) {
235
                JDBCUtils.closeQuietly(entry);
236
            } else {
237
                if (entry.getID() > maxID) {
238
                    maxID = entry.getID();
239
                }
240
            }
241
        }
242
        this.nextid = maxID + 1;
243
    }
244
245
    @Override
246
    public synchronized int getOpenCount() {
247
        return this.resulSets.size();
248
    }
249
}