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
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
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
13
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCExecutePreparedSQLException;
14
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
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.JDBCHelperBase;
19
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
20
import org.gvsig.tools.dispose.Disposable;
21
import org.gvsig.tools.dispose.DisposeUtils;
22
import org.slf4j.Logger;
23
import org.slf4j.LoggerFactory;
24

    
25
public class ResulSetControlerBase implements ResulSetControler {
26

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

    
29
    public class ResultSetEntryBase implements ResultSetEntry {
30

    
31
        private ResultSet resultSet = null;
32
        private final int id;
33
        private long lastUse = 0;
34
        private final String sql;
35
        private final FeatureAttributeDescriptor[] columns;
36
        private final String[] extraValueNames;
37
        private Throwable closeCause ;
38
        
39
        private final String connId;
40
        private final String hexId;
41
        private final JDBCConnection conn;
42

    
43
        public ResultSetEntryBase(JDBCConnection conn, ResultSet resulSet, String sql, FeatureAttributeDescriptor[] columns, String[] extraValueNames) {
44
            this.conn = conn;
45
            this.closeCause = null;
46
            this.resultSet = resulSet;
47
            this.connId = JDBCUtils.getConnId(this.resultSet);
48
            this.hexId = JDBCUtils.getHexId(this);
49
            this.id = nextid++;
50
            this.sql = sql;
51
            this.columns = columns;
52
            this.extraValueNames = extraValueNames;
53
            used();
54
            synchronized(resulSets){
55
                resulSets.put(this.getID(), this);
56
            }
57
            if( LOGGER.isDebugEnabled() ) {
58
                LOGGER.debug("["+JDBCUtils.getConnId(resulSet)+"] ResultSetEntryBase "+this.hexId+" "+sql);
59
            }
60
            LOGGER.debug(((JDBCHelperBase)helper).getConnectionProviderStatus());
61
        }
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
        @Override
92
        public String[] getExtraValueNames() {
93
            return this.extraValueNames;
94
        }
95
        
96
        @Override
97
        public FeatureAttributeDescriptor[] getColumns() {
98
            return this.columns;
99
        }
100
        
101
        @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
            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
            return this.resultSet.next();
120
        }
121

    
122
        @Override
123
        public void close() throws Exception {
124
            if( LOGGER.isDebugEnabled() ) {
125
                LOGGER.debug("["+this.connId+"] ResultSetEntryBase close "+this.hexId);
126
            }
127
            if( this.resultSet == null ) {
128
                // Already close
129
                return;
130
            }
131
            this.closeCause = new Throwable();
132
            
133
            Statement st = null;
134
            try {
135
                synchronized(resulSets){
136
                    resulSets.remove(this.getID());
137
                }
138
                st = this.resultSet.getStatement();
139
            } catch(Exception ex) {
140
                LOGGER.warn("Problems closing ResulSetEntryBase.",ex);
141
            }
142
            JDBCUtils.closeQuietly(this.resultSet);
143
            JDBCUtils.closeQuietly(st);
144
            this.conn.closeQuietly();
145
            this.resultSet = null;
146
            LOGGER.debug(
147
                    "Close ResulSetEntryBase id {} (total {})",
148
                    this.getID(),
149
                    getOpenCount()
150
            );
151
            LOGGER.debug(((JDBCHelperBase)helper).getConnectionProviderStatus());
152
            pack();
153
        }
154

    
155
    }
156

    
157
    private int nextid = 1;
158

    
159
    private final Map<Integer, ResultSetEntryBase> resulSets;
160

    
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
        this.resulSets.clear();
186
        this.nextid = -10;
187
    }
188

    
189
    @Override
190
    public ResultSetEntryBase create(
191
            String sql, 
192
            int fetchSize, 
193
            FeatureAttributeDescriptor[] columns,
194
            String[] extraValueNames) throws DataException {
195
        return create(sql, null, fetchSize, columns, extraValueNames);
196
    }
197

    
198
    @Override
199
    public synchronized ResultSetEntryBase create(
200
            String sql, 
201
            List<Object> values, 
202
            int fetchSize, 
203
            FeatureAttributeDescriptor[] columns, 
204
            String[] extraValueNames) throws DataException {
205
        this.pack();
206
        ResultSet rs = null;
207
        JDBCConnection conn = null;
208
        PreparedStatement st = null;
209
        Disposable paramsDisposer = null;
210
        try {
211
            conn = helper.getConnection();
212
            conn.begin();
213
            st = conn.prepareStatement(sql);
214

    
215
            JDBCSQLBuilderBase sqlbuilder = helper.createSQLBuilder();
216
            paramsDisposer = sqlbuilder.setStatementParameters(st, values, helper.getGeometrySupportType());
217

    
218
            if (fetchSize > 0) {
219
                // See parameter "SelectMethod" of SQL Server Connection Properties
220
                // https://docs.oracle.com/cd/E13157_01/wlevs/docs30/jdbc_drivers/mssqlserver.html
221
                st.setFetchSize(fetchSize);
222
            }
223
            rs = JDBCUtils.executeQuery(st, sql);
224
            if (fetchSize > 0) {
225
                rs.setFetchSize(fetchSize);
226
            }
227
            ResultSetEntryBase rsentry = new ResultSetEntryBase(conn, rs, sql, columns,  extraValueNames);
228
            return rsentry;
229

    
230
        } catch (SQLException e) {
231
            JDBCUtils.closeQuietly(rs);
232
            JDBCUtils.closeQuietly(st);
233
            JDBCConnection.closeQuietly(conn);
234
            conn.closeQuietly();
235
            throw new JDBCExecutePreparedSQLException(sql, values, e);
236
        } finally {
237
            DisposeUtils.disposeQuietly(paramsDisposer);
238
        }
239
    }
240
    
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

    
249
    @Override
250
    public synchronized void closeAll() {
251

    
252
        List<ResultSetEntryBase> values = getResultSetValues();
253

    
254
        for (ResultSetEntryBase entry : values) {
255
            JDBCUtils.closeQuietly(entry);
256
        }
257
    }
258

    
259
    @Override
260
    public synchronized void pack() {
261

    
262
        List<ResultSetEntryBase> values = getResultSetValues();
263

    
264
        int maxID = 0;
265
        for (ResultSetEntryBase entry : values) {
266
            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
    public int getOpenCount() {
279
        synchronized(resulSets){
280
            return this.resulSets.size();
281
        }
282
    }
283
}