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

History | View | Annotate | Download (7.47 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

    
36
        public ResultSetEntryBase(ResultSet resulSet, FeatureAttributeDescriptor[] columns) {
37
            this(resulSet,null, columns);
38
        }
39

    
40
        public ResultSetEntryBase(ResultSet resulSet, String sql, FeatureAttributeDescriptor[] columns) {
41
            this.resultSet = resulSet;
42
            this.id = nextid++;
43
            this.sql = sql;
44
            this.columns = columns;
45
            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
        @Override
78
        public FeatureAttributeDescriptor[] getColumns() {
79
            return this.columns;
80
        }
81
        
82
        @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
            helper.closeConnection(con);
119
            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
    public ResultSetEntryBase create(
164
            String sql, 
165
            int fetchSize, 
166
            FeatureAttributeDescriptor[] columns) throws DataException {
167
        return create(sql, null, fetchSize, columns);
168
    }
169

    
170
    @Override
171
    public synchronized ResultSetEntryBase create(
172
            final String sql,
173
            final List values,
174
            final int fetchSize, 
175
            FeatureAttributeDescriptor[] columns) throws DataException {
176

    
177
        this.pack();
178
        ResultSet rs = null;
179
        Connection conn = null;
180
        PreparedStatement st = null;
181
        Disposable paramsDisposer = null;
182
        try {
183
            conn = helper.getConnection();
184
            conn.setAutoCommit(false);
185
            st = conn.prepareStatement(sql);
186

    
187
            JDBCSQLBuilderBase sqlbuilder = helper.createSQLBuilder();
188
            paramsDisposer = sqlbuilder.setStatementParameters(st, values, helper.getGeometrySupportType());
189

    
190
            if (fetchSize > 0) {
191
                // See parameter "SelectMethod" of SQL Server Connection Properties
192
                // https://docs.oracle.com/cd/E13157_01/wlevs/docs30/jdbc_drivers/mssqlserver.html
193
                st.setFetchSize(fetchSize);
194
            }
195
            rs = JDBCUtils.executeQuery(st, sql);
196
            if (fetchSize > 0) {
197
                rs.setFetchSize(fetchSize);
198
            }
199
            ResultSetEntryBase rsentry = new ResultSetEntryBase(rs, sql, columns);
200
            return rsentry;
201

    
202
        } catch (SQLException e) {
203
            JDBCUtils.closeQuietly(rs);
204
            JDBCUtils.closeQuietly(st);
205
            this.helper.closeConnectionQuietly(conn);
206
            throw new JDBCExecutePreparedSQLException(sql, values, e);
207
        } finally {
208
            DisposeUtils.disposeQuietly(paramsDisposer);
209
        }
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
}