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

History | View | Annotate | Download (8.86 KB)

1 43020 jjdelcerro
package org.gvsig.fmap.dal.store.jdbc2.impl;
2
3
import java.sql.PreparedStatement;
4
import java.sql.ResultSet;
5
import java.sql.SQLException;
6
import java.sql.Statement;
7
import java.util.ArrayList;
8
import java.util.HashMap;
9
import java.util.List;
10
import java.util.Map;
11
import org.gvsig.fmap.dal.exception.DataException;
12 43358 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
13 43020 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecutePreparedSQLException;
14 46315 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
15 43020 jjdelcerro
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 45736 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
19 43629 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
20
import org.gvsig.tools.dispose.Disposable;
21
import org.gvsig.tools.dispose.DisposeUtils;
22 43020 jjdelcerro
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24
25
public class ResulSetControlerBase implements ResulSetControler {
26
27 44375 jjdelcerro
    final static private Logger LOGGER = LoggerFactory.getLogger(ResulSetControlerBase.class);
28 43020 jjdelcerro
29
    public class ResultSetEntryBase implements ResultSetEntry {
30
31
        private ResultSet resultSet = null;
32
        private final int id;
33
        private long lastUse = 0;
34 45766 fdiaz
        private final String sql;
35 43358 jjdelcerro
        private final FeatureAttributeDescriptor[] columns;
36 44376 jjdelcerro
        private final String[] extraValueNames;
37 45425 jjdelcerro
        private Throwable closeCause ;
38
39 45766 fdiaz
        private final String connId;
40
        private final String hexId;
41 46315 jjdelcerro
        private final JDBCConnection conn;
42 43020 jjdelcerro
43 46315 jjdelcerro
        public ResultSetEntryBase(JDBCConnection conn, ResultSet resulSet, String sql, FeatureAttributeDescriptor[] columns, String[] extraValueNames) {
44
            this.conn = conn;
45 45425 jjdelcerro
            this.closeCause = null;
46 43020 jjdelcerro
            this.resultSet = resulSet;
47 45425 jjdelcerro
            this.connId = JDBCUtils.getConnId(this.resultSet);
48
            this.hexId = JDBCUtils.getHexId(this);
49 43020 jjdelcerro
            this.id = nextid++;
50
            this.sql = sql;
51 43358 jjdelcerro
            this.columns = columns;
52 44376 jjdelcerro
            this.extraValueNames = extraValueNames;
53 43020 jjdelcerro
            used();
54 45766 fdiaz
            synchronized(resulSets){
55
                resulSets.put(this.getID(), this);
56
            }
57 45097 jjdelcerro
            if( LOGGER.isDebugEnabled() ) {
58 45425 jjdelcerro
                LOGGER.debug("["+JDBCUtils.getConnId(resulSet)+"] ResultSetEntryBase "+this.hexId+" "+sql);
59 45097 jjdelcerro
            }
60 45736 fdiaz
            LOGGER.debug(((JDBCHelperBase)helper).getConnectionProviderStatus());
61 43020 jjdelcerro
        }
62
63
        private void used() {
64
            lastUse = System.currentTimeMillis();
65
        }
66
67
        @Override
68
        public ResultSet get() {
69
            used();
70
            return resultSet;
71
        }
72
73
        @Override
74
        public int getID() {
75
            return this.id;
76
        }
77
78
        @Override
79
        public boolean isZombie() {
80
            if( this.resultSet == null ) {
81
                return true;
82
            }
83
            return System.currentTimeMillis() - lastUse > mlsecondsToZombie;
84
        }
85
86
        @Override
87
        public String getSQL() {
88
            return this.sql;
89
        }
90
91 43629 jjdelcerro
        @Override
92 44376 jjdelcerro
        public String[] getExtraValueNames() {
93
            return this.extraValueNames;
94
        }
95
96
        @Override
97 43358 jjdelcerro
        public FeatureAttributeDescriptor[] getColumns() {
98
            return this.columns;
99
        }
100
101 43020 jjdelcerro
        @Override
102
        public Object getObject(int columnIndex) throws SQLException {
103
            used();
104
            return this.resultSet.getObject(columnIndex);
105
        }
106
107
        @Override
108
        public byte[] getBytes(int columnIndex) throws SQLException {
109
            used();
110
            return this.resultSet.getBytes(columnIndex);
111
        }
112
113
        @Override
114
        public boolean next() throws SQLException {
115 45425 jjdelcerro
            if( this.closeCause!=null ) {
116
                LOGGER.debug("["+this.connId+"] ResultSetEntryBase already closed "+this.hexId);
117
                throw new IllegalStateException("ResultSetEntryBase already closed, connId="+this.connId+", id="+this.hexId+" (sql="+sql+")", closeCause);
118
            }
119 43020 jjdelcerro
            return this.resultSet.next();
120
        }
121
122
        @Override
123
        public void close() throws Exception {
124 45097 jjdelcerro
            if( LOGGER.isDebugEnabled() ) {
125 45425 jjdelcerro
                LOGGER.debug("["+this.connId+"] ResultSetEntryBase close "+this.hexId);
126 45097 jjdelcerro
            }
127 43020 jjdelcerro
            if( this.resultSet == null ) {
128
                // Already close
129
                return;
130
            }
131 45425 jjdelcerro
            this.closeCause = new Throwable();
132
133 43020 jjdelcerro
            Statement st = null;
134
            try {
135 45766 fdiaz
                synchronized(resulSets){
136
                    resulSets.remove(this.getID());
137
                }
138 43020 jjdelcerro
                st = this.resultSet.getStatement();
139
            } catch(Exception ex) {
140 44375 jjdelcerro
                LOGGER.warn("Problems closing ResulSetEntryBase.",ex);
141 43020 jjdelcerro
            }
142
            JDBCUtils.closeQuietly(this.resultSet);
143
            JDBCUtils.closeQuietly(st);
144 46315 jjdelcerro
            this.conn.closeQuietly();
145 43020 jjdelcerro
            this.resultSet = null;
146 45736 fdiaz
            LOGGER.debug(
147 43020 jjdelcerro
                    "Close ResulSetEntryBase id {} (total {})",
148
                    this.getID(),
149
                    getOpenCount()
150
            );
151 45736 fdiaz
            LOGGER.debug(((JDBCHelperBase)helper).getConnectionProviderStatus());
152 43020 jjdelcerro
            pack();
153
        }
154
155
    }
156
157
    private int nextid = 1;
158
159 45766 fdiaz
    private final Map<Integer, ResultSetEntryBase> resulSets;
160 43020 jjdelcerro
161
    private long mlsecondsToZombie = 1000 * 60 * 10; // 10 Min
162
163
    private JDBCHelper helper = null;
164
165
    public ResulSetControlerBase(JDBCHelper helper) {
166
        this.helper = helper;
167
        this.resulSets = new HashMap<>();
168
        this.nextid = 1;
169
    }
170
171
    @Override
172
    public long getTimeToZombie() {
173
        return mlsecondsToZombie;
174
    }
175
176
    @Override
177
    public void setTimeToZombie(long mlSeconds) {
178
        mlsecondsToZombie = mlSeconds;
179
    }
180
181
    @Override
182
    public void close() throws Exception {
183
        this.closeAll();
184
        this.helper = null;
185 45766 fdiaz
        this.resulSets.clear();
186 43020 jjdelcerro
        this.nextid = -10;
187
    }
188
189
    @Override
190 43358 jjdelcerro
    public ResultSetEntryBase create(
191
            String sql,
192
            int fetchSize,
193 44376 jjdelcerro
            FeatureAttributeDescriptor[] columns,
194
            String[] extraValueNames) throws DataException {
195
        return create(sql, null, fetchSize, columns, extraValueNames);
196 43020 jjdelcerro
    }
197
198
    @Override
199
    public synchronized ResultSetEntryBase create(
200 44376 jjdelcerro
            String sql,
201
            List<Object> values,
202
            int fetchSize,
203
            FeatureAttributeDescriptor[] columns,
204
            String[] extraValueNames) throws DataException {
205 43020 jjdelcerro
        this.pack();
206
        ResultSet rs = null;
207 46315 jjdelcerro
        JDBCConnection conn = null;
208 43020 jjdelcerro
        PreparedStatement st = null;
209 43629 jjdelcerro
        Disposable paramsDisposer = null;
210 43020 jjdelcerro
        try {
211
            conn = helper.getConnection();
212 46315 jjdelcerro
            conn.begin();
213 43020 jjdelcerro
            st = conn.prepareStatement(sql);
214
215 43629 jjdelcerro
            JDBCSQLBuilderBase sqlbuilder = helper.createSQLBuilder();
216
            paramsDisposer = sqlbuilder.setStatementParameters(st, values, helper.getGeometrySupportType());
217 43020 jjdelcerro
218
            if (fetchSize > 0) {
219 43358 jjdelcerro
                // See parameter "SelectMethod" of SQL Server Connection Properties
220
                // https://docs.oracle.com/cd/E13157_01/wlevs/docs30/jdbc_drivers/mssqlserver.html
221 43020 jjdelcerro
                st.setFetchSize(fetchSize);
222
            }
223
            rs = JDBCUtils.executeQuery(st, sql);
224
            if (fetchSize > 0) {
225
                rs.setFetchSize(fetchSize);
226
            }
227 46315 jjdelcerro
            ResultSetEntryBase rsentry = new ResultSetEntryBase(conn, rs, sql, columns,  extraValueNames);
228 43629 jjdelcerro
            return rsentry;
229 43020 jjdelcerro
230
        } catch (SQLException e) {
231
            JDBCUtils.closeQuietly(rs);
232
            JDBCUtils.closeQuietly(st);
233 46315 jjdelcerro
            JDBCConnection.closeQuietly(conn);
234
            conn.closeQuietly();
235 43020 jjdelcerro
            throw new JDBCExecutePreparedSQLException(sql, values, e);
236 43629 jjdelcerro
        } finally {
237
            DisposeUtils.disposeQuietly(paramsDisposer);
238 43020 jjdelcerro
        }
239
    }
240 45766 fdiaz
241
    private List<ResultSetEntryBase> getResultSetValues() {
242
        synchronized(this.resulSets){
243
            List<ResultSetEntryBase> values = new ArrayList<>();
244
            values.addAll(this.resulSets.values());
245
            return values;
246
        }
247
    }
248 43020 jjdelcerro
249
    @Override
250
    public synchronized void closeAll() {
251
252 45766 fdiaz
        List<ResultSetEntryBase> values = getResultSetValues();
253 43020 jjdelcerro
254 45766 fdiaz
        for (ResultSetEntryBase entry : values) {
255 43020 jjdelcerro
            JDBCUtils.closeQuietly(entry);
256
        }
257
    }
258
259
    @Override
260
    public synchronized void pack() {
261
262 45766 fdiaz
        List<ResultSetEntryBase> values = getResultSetValues();
263
264 43020 jjdelcerro
        int maxID = 0;
265 45766 fdiaz
        for (ResultSetEntryBase entry : values) {
266 43020 jjdelcerro
            if (entry.isZombie()) {
267
                JDBCUtils.closeQuietly(entry);
268
            } else {
269
                if (entry.getID() > maxID) {
270
                    maxID = entry.getID();
271
                }
272
            }
273
        }
274
        this.nextid = maxID + 1;
275
    }
276
277
    @Override
278 45766 fdiaz
    public int getOpenCount() {
279
        synchronized(resulSets){
280
            return this.resulSets.size();
281
        }
282 43020 jjdelcerro
    }
283
}