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 / spi / JDBCResourcesStorage.java @ 45736

History | View | Annotate | Download (18.8 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2020 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.store.jdbc2.spi;
25

    
26
import java.io.ByteArrayInputStream;
27
import java.io.ByteArrayOutputStream;
28
import java.io.File;
29
import java.io.FileInputStream;
30
import java.io.FileNotFoundException;
31
import java.io.FileOutputStream;
32
import java.io.IOException;
33
import java.io.InputStream;
34
import java.io.OutputStream;
35
import java.net.URL;
36
import java.util.ArrayList;
37
import java.util.List;
38
import org.apache.commons.codec.digest.DigestUtils;
39
import org.apache.commons.io.FileUtils;
40
import org.apache.commons.io.IOUtils;
41
import org.apache.commons.io.output.NullOutputStream;
42
import org.apache.commons.lang3.StringUtils;
43
import org.apache.commons.lang3.tuple.ImmutablePair;
44
import org.apache.commons.lang3.tuple.Pair;
45
import org.gvsig.expressionevaluator.ExpressionBuilder;
46
import org.gvsig.expressionevaluator.ExpressionUtils;
47
import org.gvsig.fmap.dal.DALLocator;
48
import org.gvsig.fmap.dal.DataManager;
49
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_NAME;
50
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_RESOURCE;
51
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_RESOURCES_NAME;
52
import org.gvsig.fmap.dal.feature.EditableFeature;
53
import org.gvsig.fmap.dal.feature.Feature;
54
import org.gvsig.fmap.dal.feature.FeatureStore;
55
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
56
import org.gvsig.tools.ToolsLocator;
57
import org.gvsig.tools.dispose.DisposeUtils;
58
import org.gvsig.tools.folders.FoldersManager;
59
import org.gvsig.tools.resourcesstorage.AbstractResourcesStorage;
60
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

    
64
/**
65
 *
66
 * @author jjdelcerro
67
 */
68
@SuppressWarnings("UseSpecificCatch")
69
public class JDBCResourcesStorage extends AbstractResourcesStorage {
70

    
71
    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCResourcesStorage.class);
72

    
73
    private static class DataBaseResource implements Resource {
74

    
75
        private class ResourceInputStream extends InputStream {
76

    
77
            @Override
78
            public int read() throws IOException {
79
                return in.read();
80
            }
81

    
82
            @Override
83
            public void close() throws IOException {
84
                DataBaseResource.this.close();
85
            }
86
        }
87

    
88
        private class ResourceOutputStream extends OutputStream {
89

    
90
            @Override
91
            public void write(int b) throws IOException {
92
                out.write(b);
93
            }
94

    
95
            @Override
96
            public void flush() throws IOException {
97
                out.flush();
98
            }
99

    
100
            @Override
101
            public void close() throws IOException {
102
                DataBaseResource.this.close();
103
            }
104
        }
105

    
106
        private final JDBCStoreParameters storeParameters;
107
        private final String tableName;
108
        private final String name;
109
        private final boolean readonly;
110

    
111
        private InputStream in;
112
        private OutputStream out;
113

    
114
        public DataBaseResource(JDBCStoreParameters storeParameters, String tableName, String name, boolean readonly) {
115
            this.storeParameters = storeParameters;
116
            this.tableName = tableName;
117
            this.name = name;
118
            this.readonly = readonly;
119
        }
120

    
121
        @Override
122
        public String getName() {
123
          return name;
124
        }
125
        
126
        @Override
127
        public boolean isReadOnly() {
128
            return false;
129
        }
130
        @Override
131
        public URL getURL() {
132
            try {
133
                String url = this.storeParameters.getUrl();
134
                return new URL(url + "&tableName=" + this.tableName + "&resourceName=" + this.name);
135
            } catch (Throwable ex) {
136
                return null;
137
            }
138
        }
139

    
140
        @Override
141
        public boolean exists() {
142
            FeatureStore store = null;
143
            try {
144
                FoldersManager fm = ToolsLocator.getFoldersManager();
145
                Pair<String, String> key = this.getCacheID();
146
                File f = fm.getTemporaryFile("resources-storage","jdbc", key.getLeft(), key.getRight());
147
                if( f.exists() ) {
148
                  return true;
149
                }
150
                DataManager dataManager = DALLocator.getDataManager();
151
                store = (FeatureStore) dataManager.openStore(
152
                        this.storeParameters.getDataStoreName(),
153
                        this.storeParameters
154
                );
155
                ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
156
                String filter = builder.eq(
157
                        builder.column(FIELD_RESOURCES_NAME),
158
                        builder.constant(this.tableName+"."+this.name)
159
                ).toString();
160
                Feature feature = store.findFirst(filter);
161
                return feature!=null;
162
            } catch (Throwable ex) {
163
                LOGGER.warn("Can't access to the resoure '" + this.getURL() + "'.", ex);
164
            } finally {
165
                DisposeUtils.disposeQuietly(store);
166
            }
167
            return false;
168
        }
169

    
170
        public boolean remove() {
171
            FeatureStore store = null;
172
            try {
173
                FoldersManager fm = ToolsLocator.getFoldersManager();
174
                Pair<String, String> key = this.getCacheID();
175
                File f = fm.getTemporaryFile("resources-storage","jdbc", key.getLeft(), key.getRight());
176
                if( f.exists() ) {
177
                  f.delete();
178
                }
179
                DataManager dataManager = DALLocator.getDataManager();
180
                store = (FeatureStore) dataManager.openStore(
181
                        this.storeParameters.getDataStoreName(),
182
                        this.storeParameters
183
                );
184
                ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
185
                String filter = builder.eq(
186
                        builder.column(FIELD_RESOURCES_NAME),
187
                        builder.constant(this.tableName+"."+this.name)
188
                ).toString();
189
                Feature feature = store.findFirst(filter);
190
                if(feature != null){
191
                    store.edit();
192
                    store.delete(feature);
193
                    store.finishEditing();
194
                    return true;
195
                }
196
                return false;
197
            } catch (Throwable ex) {
198
                FeatureStore.cancelEditingQuietly(store);
199
                LOGGER.warn("Can't access to the resoure '" + this.getURL() + "'.", ex);
200
            } finally {
201
                DisposeUtils.disposeQuietly(store);
202
            }
203
            return false;
204
        }
205

    
206
        private Pair<String,String> getCacheID() {
207
          byte[] data = this.storeParameters.toByteArray();
208
          ImmutablePair<String, String> r = new ImmutablePair<>(
209
                  DigestUtils.md5Hex(data), 
210
                  this.tableName+"."+this.name
211
          );
212
          return r;
213
        }
214
        
215
        private boolean removeCache() {
216
          FoldersManager fm = ToolsLocator.getFoldersManager();
217
          Pair<String, String> key = this.getCacheID();
218
          File f = fm.getTemporaryFile("resources-storage","jdbc", key.getLeft(), key.getRight());
219
          if( f.exists() ) {
220
              try {
221
                  FileUtils.forceDelete(f);
222
              } catch (IOException ex) {
223
                  return false;
224
              }
225
          }
226
          return true;
227
        }
228
        
229
        private InputStream getInputStreamFromCache() {
230
          FoldersManager fm = ToolsLocator.getFoldersManager();
231
          Pair<String, String> key = this.getCacheID();
232
          File f = fm.getTemporaryFile("resources-storage","jdbc", key.getLeft(), key.getRight());
233
          if( !f.exists() ) {
234
            InputStream is = null;
235
            FileOutputStream os = null;
236
            File f2 = null;
237
            try {
238
              is = this.getInputStream();
239
              if (is==null) {
240
                  return null;
241
              }
242
              FileUtils.forceMkdir(f.getParentFile());
243
              os = new FileOutputStream(f);
244
              IOUtils.copy(is, os);              
245
              
246
              f2 = fm.getTemporaryFile("resources-storage","jdbc", key.getLeft(), "parameters");              
247
              byte[] data = this.storeParameters.toByteArray();
248
              os = new FileOutputStream(f2);
249
              IOUtils.write(data, os);
250
            } catch (IOException ex) {
251
              FileUtils.deleteQuietly(f);
252
              FileUtils.deleteQuietly(f2);
253
              return null;
254
            } finally {
255
              IOUtils.closeQuietly(is);
256
              IOUtils.closeQuietly(os);
257
            }
258
          }
259
          InputStream is = null;
260
          try {
261
            is = new FileInputStream(f);
262
          } catch (FileNotFoundException ex) {
263
          }
264
          return is;
265
        }
266
        
267
        private InputStream getInputStream() throws IOException {
268
            FeatureStore store = null;
269
            try {
270
                DataManager dataManager = DALLocator.getDataManager();
271
                store = (FeatureStore) dataManager.openStore(
272
                        this.storeParameters.getDataStoreName(),
273
                        this.storeParameters
274
                );
275
                ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
276
                String filter = builder.eq(
277
                        builder.column(FIELD_RESOURCES_NAME),
278
                        builder.constant(this.tableName+"."+this.name)
279
                ).toString();
280
                Feature feature = store.findFirst(filter);
281
                if (feature == null) {
282
                    return null;
283
                }
284
                byte[] resource = feature.getByteArray(FIELD_RESOURCES_RESOURCE);
285
                InputStream is = new ByteArrayInputStream(resource);
286
                return is;
287
            } catch (Throwable ex) {
288
                LOGGER.warn("Can't access to the resoure '" + this.getURL() + "'.", ex);
289
            } finally {
290
                DisposeUtils.disposeQuietly(store);
291
            }
292
            return null;
293
        }
294

    
295
        @Override
296
        public InputStream asInputStream() throws IOException {
297
            if (this.in != null || this.out != null) {
298
                throw new IllegalStateException("Resource is already open (" + this.getURL() + ")");
299
            }
300
            InputStream is = this.getInputStreamFromCache();
301
            if( is==null ) {
302
                is = this.getInputStream();
303
                if ( is==null) {
304
                    return null;
305
                }
306
            }
307
            this.in = is;
308
            return new ResourceInputStream();
309
        }
310

    
311
        @Override
312
        public OutputStream asOutputStream() throws IOException {
313
            if (this.in != null || this.out != null) {
314
                throw new IllegalStateException("Resource is already open (" + this.getURL() + ").");
315
            }
316
            if( this.readonly ) {
317
                this.out = new NullOutputStream();
318
            } else {
319
                this.out = new ByteArrayOutputStream();
320
            }
321
            return new ResourceOutputStream();
322
        }
323

    
324
        @Override
325
        public void close() {
326
            if (this.in != null) {
327
                IOUtils.closeQuietly(this.in);
328
                this.in = null;
329
            }
330
            if (!this.readonly && this.out != null) {
331
                FeatureStore store = null;
332
                try {
333
                    DataManager dataManager = DALLocator.getDataManager();
334
                    store = (FeatureStore) dataManager.openStore(
335
                            this.storeParameters.getDataStoreName(),
336
                            this.storeParameters
337
                    );
338
                    store.edit();
339
                    ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
340
                    String filter = builder.eq(
341
                            builder.column(FIELD_RESOURCES_NAME),
342
                            builder.constant(this.tableName+"."+this.name)
343
                    ).toString();
344
                    Feature feature = store.findFirst(filter);
345
                    EditableFeature efeature;
346
                    if (feature == null) {
347
                        efeature = store.createNewFeature();
348
                        efeature.set(FIELD_RESOURCES_NAME, this.tableName+"."+this.name);
349
                        efeature.set(FIELD_RESOURCES_RESOURCE, ((ByteArrayOutputStream)this.out).toByteArray());
350
                        store.insert(efeature);
351
                    } else {
352
                        efeature = feature.getEditable();
353
                        efeature.set(FIELD_RESOURCES_RESOURCE, ((ByteArrayOutputStream)this.out).toByteArray());
354
                        store.update(efeature);
355
                    }
356
                    store.finishEditing();
357
                    removeCache();
358
                } catch (Throwable ex) {
359
                    FeatureStore.cancelEditingQuietly(store);
360
                    LOGGER.warn("Can't write the resoure '" + this.getURL() + "'.", ex);
361
                } finally {
362
                    DisposeUtils.disposeQuietly(store);
363
                }
364
            }
365
        }
366
    }
367

    
368
    private final ResourcesStorage alternativeStorge;
369
    private final JDBCStoreParameters resourcesStoreParameters;
370
    private final String tableName;
371
    private final boolean readonly;
372

    
373
    public JDBCResourcesStorage(
374
                ResourcesStorage alternativeStorge, 
375
                JDBCStoreParameters resourcesStoreParameters, 
376
                String tableName
377
        ) {
378
        this(alternativeStorge, resourcesStoreParameters, tableName, false);
379
    }
380

    
381
    public JDBCResourcesStorage(
382
                ResourcesStorage alternativeStorge, 
383
                JDBCStoreParameters resourcesStoreParameters, 
384
                String tableName,
385
                boolean readonly
386
        ) {
387
        this.readonly = readonly;
388
        this.alternativeStorge = alternativeStorge;
389
        if( StringUtils.equals(TABLE_RESOURCES_NAME, tableName) ) {
390
            // No podemos buscar recursos de la tabla de recursos, ya que si no
391
            // al abrise la tabla de recursos entraria en bucle.
392
            this.resourcesStoreParameters = null;
393
        } else {
394
            this.resourcesStoreParameters = resourcesStoreParameters;
395
        }
396
        this.tableName = tableName;
397
    }
398

    
399
    @Override
400
    public boolean isEmpty() {
401
        return this.resourcesStoreParameters == null;
402
    }
403

    
404
    @Override
405
    public Resource getResource(String name) {
406
        if( this.alternativeStorge!=null ) {
407
            Resource r = this.alternativeStorge.getResource(name);
408
            if( r.exists() ) {
409
                return r;
410
            }
411
        }
412
        if (this.resourcesStoreParameters == null) {
413
            return null;
414
        }
415
        return new DataBaseResource(
416
                this.resourcesStoreParameters, 
417
                this.tableName, 
418
                name,
419
                this.readonly
420
        );
421
    }
422

    
423
    @Override
424
    public List<Resource> getResources(String name) {
425
        if (this.resourcesStoreParameters == null) {
426
            return null;
427
        }
428
        if( this.alternativeStorge!=null ) {
429
            List<Resource> r = this.alternativeStorge.getResources(name);
430
            if( r!=null && !r.isEmpty() ) {
431
                return r;
432
            }
433
        }
434
        FeatureStore store = null;
435
        try {
436
            DataManager dataManager = DALLocator.getDataManager();
437
            store = (FeatureStore) dataManager.openStore(
438
                    this.resourcesStoreParameters.getDataStoreName(),
439
                    this.resourcesStoreParameters
440
            );
441
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
442
            List<ResourcesStorage.Resource> ress = new ArrayList<>();
443
            int n = 0;
444
            while (true) {
445
                String multiresourceName;
446
                if (n == 0) {
447
                    multiresourceName = name;
448
                } else {
449
                    multiresourceName = String.valueOf(n) + "." + name ;
450
                }
451
                String filter = builder.eq(
452
                        builder.column(FIELD_RESOURCES_NAME),
453
                        builder.constant(this.tableName+"."+multiresourceName)
454
                ).toString();
455
                Feature feature = store.findFirst(filter);
456
                if( feature==null ) {
457
                    break;
458
                }
459
                ress.add(new DataBaseResource(
460
                        this.resourcesStoreParameters, 
461
                        this.tableName,
462
                        multiresourceName,
463
                        this.readonly
464
                    )
465
                );
466
                n++;
467
            }
468
            if (ress.isEmpty()) {
469
                return null;
470
            }
471
            return ress;
472
        } catch (Throwable ex) {
473
            LOGGER.warn("Can't get resources for '" + this.resourcesStoreParameters.getUrl()+"&resourceName="+name + "'.", ex);
474
            return null;
475
            
476
        } finally {
477
            DisposeUtils.disposeQuietly(store);
478
        }
479

    
480
    }
481

    
482
    @Override
483
    public boolean remove(String resourceName) {
484
        if( this.alternativeStorge!=null ) {
485
            try {
486
                this.alternativeStorge.remove(resourceName);
487
            } catch (Exception e) {
488
                //Do nothing
489
            }
490
        }
491
        if (this.resourcesStoreParameters == null) {
492
            return false;
493
        }
494
        DataBaseResource resource = new DataBaseResource(
495
                this.resourcesStoreParameters,
496
                this.tableName, 
497
                resourceName,
498
                this.readonly
499
        );
500
        
501
        return resource.remove();
502
    }
503
    
504
    void clearCache() throws IOException {
505
        byte[] data = this.resourcesStoreParameters.toByteArray();
506

    
507
        FoldersManager fm = ToolsLocator.getFoldersManager();
508
        File f = fm.getTemporaryFile("resources-storage", "jdbc", DigestUtils.md5Hex(data));
509
        FileUtils.deleteDirectory(f);
510

    
511
    }
512

    
513
}