Source Code Cross Referenced for ArcSDERasterGridCoverage2DReader.java in  » GIS » GeoTools-2.4.1 » org » geotools » arcsde » gce » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.arcsde.gce 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    Geotools2 - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2002, Geotools Project Managment Committee (PMC)
005:         *
006:         *    This library is free software; you can redistribute it and/or
007:         *    modify it under the terms of the GNU Lesser General Public
008:         *    License as published by the Free Software Foundation;
009:         *    version 2.1 of the License.
010:         *
011:         *    This library is distributed in the hope that it will be useful,
012:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
013:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014:         *    Lesser General Public License for more details.
015:         *
016:         */
017:        package org.geotools.arcsde.gce;
018:
019:        import java.awt.Color;
020:        import java.awt.Font;
021:        import java.awt.Graphics2D;
022:        import java.awt.Point;
023:        import java.awt.Rectangle;
024:        import java.awt.RenderingHints;
025:        import java.awt.image.BufferedImage;
026:        import java.awt.image.renderable.ParameterBlock;
027:        import java.io.File;
028:        import java.io.IOException;
029:        import java.util.ArrayList;
030:        import java.util.HashMap;
031:        import java.util.StringTokenizer;
032:        import java.util.logging.Level;
033:        import java.util.logging.Logger;
034:
035:        import javax.media.jai.ImageLayout;
036:        import javax.media.jai.JAI;
037:
038:        import org.geotools.arcsde.gce.band.ArcSDERasterBandCopier;
039:        import org.geotools.arcsde.gce.imageio.ArcSDERasterImageReadParam;
040:        import org.geotools.arcsde.gce.imageio.ArcSDERasterReader;
041:        import org.geotools.arcsde.gce.imageio.ArcSDERasterReaderSpi;
042:        import org.geotools.arcsde.pool.ArcSDEConnectionConfig;
043:        import org.geotools.arcsde.pool.ArcSDEConnectionPool;
044:        import org.geotools.arcsde.pool.ArcSDEConnectionPoolFactory;
045:        import org.geotools.arcsde.pool.ArcSDEPooledConnection;
046:        import org.geotools.arcsde.pool.UnavailableArcSDEConnectionException;
047:        import org.geotools.coverage.Category;
048:        import org.geotools.coverage.GridSampleDimension;
049:        import org.geotools.coverage.grid.GeneralGridRange;
050:        import org.geotools.coverage.grid.GridCoverage2D;
051:        import org.geotools.coverage.grid.GridGeometry2D;
052:        import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
053:        import org.geotools.coverage.grid.io.AbstractGridFormat;
054:        import org.geotools.data.DataSourceException;
055:        import org.geotools.factory.Hints;
056:        import org.geotools.geometry.DirectPosition2D;
057:        import org.geotools.geometry.GeneralEnvelope;
058:        import org.geotools.geometry.jts.ReferencedEnvelope;
059:        import org.geotools.parameter.Parameter;
060:        import org.geotools.referencing.CRS;
061:        import org.geotools.referencing.operation.transform.LinearTransform1D;
062:        import org.geotools.util.NumberRange;
063:        import org.omg.CORBA._PolicyStub;
064:        import org.opengis.coverage.grid.Format;
065:        import org.opengis.coverage.grid.GridCoverage;
066:        import org.opengis.coverage.grid.GridCoverageReader;
067:        import org.opengis.parameter.GeneralParameterValue;
068:        import org.opengis.referencing.FactoryException;
069:        import org.opengis.referencing.crs.CoordinateReferenceSystem;
070:        import org.opengis.referencing.operation.MathTransform;
071:        import org.opengis.referencing.operation.TransformException;
072:        import org.opengis.geometry.BoundingBox;
073:        import org.opengis.geometry.DirectPosition;
074:        import org.opengis.geometry.Envelope;
075:
076:        import com.esri.sde.sdk.client.SeColumnDefinition;
077:        import com.esri.sde.sdk.client.SeException;
078:        import com.esri.sde.sdk.client.SeExtent;
079:        import com.esri.sde.sdk.client.SeQuery;
080:        import com.esri.sde.sdk.client.SeRaster;
081:        import com.esri.sde.sdk.client.SeRasterAttr;
082:        import com.esri.sde.sdk.client.SeRasterBand;
083:        import com.esri.sde.sdk.client.SeRasterColumn;
084:        import com.esri.sde.sdk.client.SeRow;
085:        import com.esri.sde.sdk.client.SeSqlConstruct;
086:        import com.esri.sde.sdk.client.SeTable;
087:        import com.esri.sde.sdk.pe.PeFactory;
088:        import com.esri.sde.sdk.pe.PeProjectedCS;
089:        import com.esri.sde.sdk.pe.PeProjectionException;
090:
091:        /**
092:         * This class can read an ArcSDE Raster datasource and
093:         * create a {@link GridCoverage2D} from the data.
094:         * 
095:         * @author Saul Farber (based on ArcGridReader)
096:         * @since 2.3.x
097:         */
098:        public final class ArcSDERasterGridCoverage2DReader extends
099:                AbstractGridCoverage2DReader implements  GridCoverageReader {
100:
101:            private static final boolean DEBUG = false;
102:            /** Logger. */
103:            private final static Logger LOGGER = org.geotools.util.logging.Logging
104:                    .getLogger(ArcSDERasterGridCoverage2DReader.class
105:                            .getPackage().getName());
106:
107:            /**
108:             * The connectionpool we're using to fetch images from this ArcSDE raster
109:             * layer
110:             */
111:            private ArcSDEConnectionPool connectionPool = null;
112:
113:            /** The name of the raster table we're pulling images from in this reader * */
114:            private String rasterTable = null;
115:
116:            /**
117:             * raster column names on this raster. If there's more than one raster
118:             * column (is this possible?) then we just use the first one.
119:             */
120:            private String[] rasterColumns;
121:
122:            /** An SDE API object which holds lots of metadata about the raster layer * */
123:            private SeRasterAttr rasterAttributes = null;
124:
125:            /** The epsg code for the native projection of this raster * */
126:            private int epsgCode = -1;
127:
128:            /** Array holding information on each level of the pyramid in this raster. * */
129:            private ArcSDEPyramid pyramidInfo;
130:
131:            /** size in pixels of each tile 
132:                @deprecated -- use pyramidInfo.getLevel(x).getTileWidth(),getTileHeight()**/
133:            private int tileWidth, tileHeight;
134:
135:            /** Local copy of the javax.imageio.ImageReader subclass for reading from this ArcSDE Raster Source **/
136:            private ArcSDERasterReader imageIOReader;
137:            /**
138:             * hashmap storing ArcSDERasterBand data-typed objects keyed to their
139:             * SeRasterBand.getId()s *
140:             */
141:            private HashMap bandInfo;
142:
143:            private GridSampleDimension[] gridBands;
144:
145:            private int bufferedImageType;
146:            private Point _levelZeroPRP;
147:
148:            /**
149:             * Creates a new instance of an ArcSDERasterReader
150:             * 
151:             * @param input
152:             *            Source object (probably a connection-type URL) for which we
153:             *            want to build the ArcSDERasterReader
154:             * @throws DataSourceException
155:             */
156:            public ArcSDERasterGridCoverage2DReader(Object input)
157:                    throws DataSourceException {
158:                this (input, null);
159:            }
160:
161:            /**
162:             * Creates a new instance of an ArcSDERasterReader
163:             * 
164:             * @param input
165:             *            Source object (probably a connection-type URL) for which we
166:             *            want to build the ArcSDERasterReader
167:             * @param hints
168:             *            Hints to be used by this reader throughout his life.
169:             * @throws DataSourceException
170:             */
171:            public ArcSDERasterGridCoverage2DReader(Object input,
172:                    final Hints hints) throws DataSourceException {
173:
174:                if (hints != null)
175:                    this .hints.add(hints);
176:
177:                setupConnectionPool(input);
178:                calculateCoordinateReferenceSystem();
179:                pyramidInfo = new ArcSDEPyramid(rasterAttributes, crs);
180:                if (_levelZeroPRP != null) {
181:                    _levelZeroPRP = new Point(_levelZeroPRP.x
182:                            * pyramidInfo.tileWidth, _levelZeroPRP.y
183:                            * pyramidInfo.tileHeight);
184:                }
185:                calculateBandDependentInfo();
186:                setupCoverageMetadata();
187:                setupImageIOReader();
188:
189:                LOGGER.info("ArcSDE raster " + coverageName
190:                        + " based on table " + rasterTable
191:                        + " has been configured.");
192:            }
193:
194:            /**
195:             * @see org.opengis.coverage.grid.GridCoverageReader#getFormat()
196:             */
197:            public Format getFormat() {
198:                return new ArcSDERasterFormat();
199:            }
200:
201:            /**
202:             * Reads a {@link GridCoverage2D} possibly matching as close as possible the
203:             * resolution computed by using the input params provided by using the
204:             * parameters for this {@link #read(GeneralParameterValue[])}.
205:             * 
206:             * <p>
207:             * To have an idea about the possible read parameters take a look at
208:             * {@link AbstractGridFormat} class and {@link ArcSDERasterFormat} class.
209:             * 
210:             * @param params
211:             *            an array of {@link GeneralParameterValue} containing the
212:             *            parameters to control this read process.
213:             * 
214:             * @return a {@link GridCoverage2D}.
215:             * 
216:             * @see AbstractGridFormat
217:             * @see ArcSDERasterFormat
218:             * @see org.opengis.coverage.grid.GridCoverageReader#read(org.opengis.parameter.GeneralParameterValue[])
219:             */
220:            public GridCoverage read(GeneralParameterValue[] params)
221:                    throws IllegalArgumentException, IOException {
222:
223:                GeneralEnvelope readEnvelope = null;
224:                Rectangle requestedDim = null;
225:                if (params != null) {
226:                    final int length = params.length;
227:                    Parameter param;
228:                    String name;
229:                    for (int i = 0; i < length; i++) {
230:                        param = (Parameter) params[i];
231:                        name = param.getDescriptor().getName().getCode();
232:                        if (name.equals(AbstractGridFormat.READ_GRIDGEOMETRY2D
233:                                .getName().toString())) {
234:                            final GridGeometry2D gg = (GridGeometry2D) param
235:                                    .getValue();
236:                            readEnvelope = new GeneralEnvelope((Envelope) gg
237:                                    .getEnvelope2D());
238:                            requestedDim = gg.getGridRange2D().getBounds();
239:                        } else {
240:                            LOGGER.warning("discarding parameter with name "
241:                                    + name);
242:                        }
243:
244:                    }
245:                }
246:                if (requestedDim == null) {
247:                    throw new IllegalArgumentException(
248:                            "You must call ArcSDERasterReader.read() with a GPV[] including a Parameter for READ_GRIDGEOMETRY2D.");
249:                }
250:                if (readEnvelope == null) {
251:                    readEnvelope = new GeneralEnvelope(pyramidInfo
252:                            .getPyramidLevel(pyramidInfo.getNumLevels() - 1)
253:                            .getEnvelope());
254:                }
255:                if (LOGGER.isLoggable(Level.FINE))
256:                    LOGGER.fine("ArcSDE raster image requested: ["
257:                            + readEnvelope + ", " + requestedDim + "]");
258:                return createCoverage(readEnvelope, requestedDim, null);
259:            }
260:
261:            /**
262:             * This method creates the GridCoverage2D from the underlying SDE Raster
263:             * Table.
264:             * 
265:             * Note: Because of pyramiding, this coverage will not usually be exactly
266:             * the same size/extent as the coverage requested originally by read(). This
267:             * is because the ArcSDERasterReader will choose to supply you with best
268:             * data available, and let the eventually renderer (generally the
269:             * GridCoverageRenderer) downsample/generalize the returned coverage.
270:             * 
271:             * 
272:             * @param requestedDim
273:             *            The requested image dimensions in pixels
274:             * @param readEnvelope
275:             *            The request envelope, in CRS units
276:             * @param forcedLevel
277:             *            If this parameter is non-null, it contains the level of the pyramid at which to render
278:             *            this request.  Note that this parameter should be used with care, as forcing a rendering
279:             *            at too low a level could cause significant memory overload!
280:             * 
281:             * 
282:             * @return a GridCoverage
283:             * @throws IOException
284:             * 
285:             * @throws java.io.IOException
286:             */
287:            private GridCoverage createCoverage(
288:                    GeneralEnvelope requestedEnvelope, Rectangle requestedDim,
289:                    Integer forcedLevel) throws IOException {
290:
291:                ArcSDEPooledConnection scon = null;
292:                try {
293:
294:                    if (LOGGER.isLoggable(Level.INFO))
295:                        LOGGER
296:                                .info("Creating coverage out of request: imagesize -- "
297:                                        + requestedDim
298:                                        + "  envelope -- "
299:                                        + requestedEnvelope);
300:
301:                    ReferencedEnvelope reqEnv = new ReferencedEnvelope(
302:                            requestedEnvelope.getMinimum(0), requestedEnvelope
303:                                    .getMaximum(0), requestedEnvelope
304:                                    .getMinimum(1), requestedEnvelope
305:                                    .getMaximum(1), requestedEnvelope
306:                                    .getCoordinateReferenceSystem());
307:
308:                    final CoordinateReferenceSystem nativeCRS = pyramidInfo
309:                            .getPyramidLevel(0).getEnvelope()
310:                            .getCoordinateReferenceSystem();
311:                    if (!CRS.equalsIgnoreMetadata(nativeCRS, reqEnv
312:                            .getCoordinateReferenceSystem())) {
313:                        //we're being reprojected.  We'll need to reproject reqEnv into our native coordsys
314:                        try {
315:                            ReferencedEnvelope origReqEnv = reqEnv;
316:                            reqEnv = reqEnv.transform(nativeCRS, true);
317:                        } catch (FactoryException fe) {
318:                            //unable to reproject?
319:                            throw new DataSourceException(
320:                                    "Unable to find a reprojection from requested coordsys to native coordsys for this request",
321:                                    fe);
322:                        } catch (TransformException te) {
323:                            throw new DataSourceException(
324:                                    "Unable to perform reprojection from requested coordsys to native coordsys for this request",
325:                                    te);
326:                        }
327:                    }
328:
329:                    int level = 0;
330:                    if (forcedLevel != null) {
331:                        level = forcedLevel.intValue();
332:                    } else {
333:                        level = pyramidInfo.pickOptimalRasterLevel(reqEnv,
334:                                requestedDim);
335:                    }
336:
337:                    ArcSDEPyramidLevel optimalLevel = pyramidInfo
338:                            .getPyramidLevel(level);
339:
340:                    BufferedImage outputImage = null;
341:                    ReferencedEnvelope outputImageEnvelope = null;
342:
343:                    if (!optimalLevel.getEnvelope().intersects(
344:                            (BoundingBox) reqEnv)) {
345:                        //this is a blank raster.  I guess we should create a completely blank image with the
346:                        //correct size and return that.  Transparency?
347:                        outputImage = createInitialBufferedImage(
348:                                requestedDim.width, requestedDim.height);
349:                        outputImageEnvelope = new ReferencedEnvelope(reqEnv);
350:
351:                    } else {
352:                        //ok, there's actually something to render.  Render it.
353:                        RasterQueryInfo rasterGridInfo = pyramidInfo
354:                                .fitExtentToRasterPixelGrid(reqEnv, level);
355:
356:                        scon = connectionPool.getConnection();
357:
358:                        ArcSDERasterImageReadParam rParam = new ArcSDERasterImageReadParam();
359:                        rParam.setConnection(scon);
360:
361:                        outputImage = createInitialBufferedImage(
362:                                rasterGridInfo.image.width,
363:                                rasterGridInfo.image.height);
364:                        rParam.setDestination(outputImage);
365:
366:                        final int minImageX = Math.max(rasterGridInfo.image.x,
367:                                0);
368:                        final int maxImageX = Math.min(rasterGridInfo.image.x
369:                                + rasterGridInfo.image.width, pyramidInfo
370:                                .getPyramidLevel(level).size.width);
371:                        int minImageY = Math.max(rasterGridInfo.image.y, 0);
372:                        int maxImageY = Math.min(rasterGridInfo.image.y
373:                                + rasterGridInfo.image.height, pyramidInfo
374:                                .getPyramidLevel(level).size.height);
375:
376:                        Rectangle sourceRegion = new Rectangle(minImageX,
377:                                minImageY, maxImageX - minImageX, maxImageY
378:                                        - minImageY);
379:                        //check for inaccessible negative-indexed level-zero tiles.  Shift to level 1 if necessary.
380:                        if (level == 0 && _levelZeroPRP != null) {
381:                            if ((maxImageY > _levelZeroPRP.y && minImageY < _levelZeroPRP.y)
382:                                    || (maxImageX > _levelZeroPRP.x && minImageX < _levelZeroPRP.x)) {
383:                                LOGGER
384:                                        .warning("Using pyramid level 1 to render this request, as the data is unavailable at a negatively indexed tile.");
385:                                return createCoverage(requestedEnvelope,
386:                                        requestedDim, new Integer(1));
387:                            } else if (maxImageY > _levelZeroPRP.y
388:                                    && maxImageX > _levelZeroPRP.x) {
389:                                // we're on the south side of the PRP...need to shift everything up
390:                                sourceRegion.translate(_levelZeroPRP.x * -1,
391:                                        _levelZeroPRP.y * -1);
392:                            } else {
393:                                // all the data we want is negatively indexed on one axis or another.  Since
394:                                // we can't get at it, we'll have to shift up to level 1;
395:                                LOGGER
396:                                        .warning("Using pyramid level 1 to render this request, as the data is unavailable at a negatively indexed tile.");
397:                                return createCoverage(requestedEnvelope,
398:                                        requestedDim, new Integer(1));
399:                            }
400:                        }
401:
402:                        if (LOGGER.isLoggable(Level.FINE))
403:                            LOGGER
404:                                    .fine("Expanded request to cover source region ["
405:                                            + sourceRegion
406:                                            + "] in level "
407:                                            + level
408:                                            + ".  Spatial extent of this source region is "
409:                                            + rasterGridInfo.envelope);
410:
411:                        rParam.setSourceRegion(sourceRegion);
412:
413:                        if (rasterGridInfo.image.x < 0
414:                                || rasterGridInfo.image.y < 0) {
415:                            Point destOffset = new Point(0, 0);
416:                            if (rasterGridInfo.image.x < 0)
417:                                destOffset.x = rasterGridInfo.image.x * -1;
418:                            if (rasterGridInfo.image.y < 0)
419:                                destOffset.y = rasterGridInfo.image.y * -1;
420:                            rParam.setDestination(outputImage.getSubimage(
421:                                    destOffset.x, destOffset.y, outputImage
422:                                            .getWidth()
423:                                            - destOffset.x, outputImage
424:                                            .getHeight()
425:                                            - destOffset.y));
426:                            if (LOGGER.isLoggable(Level.FINER))
427:                                LOGGER.finer("source region is offset by "
428:                                        + destOffset + " into the "
429:                                        + outputImage.getWidth() + "x"
430:                                        + outputImage.getHeight()
431:                                        + " output image.");
432:                        }
433:
434:                        outputImageEnvelope = new ReferencedEnvelope(
435:                                rasterGridInfo.envelope);
436:
437:                        // not quite sure how, but I figure one could request a subset of all available bands...
438:                        // for now we'll just grab the first three, and assume they're RGB in order.
439:                        SeRasterBand[] seBands = rasterAttributes.getBands();
440:                        int[] bands = new int[Math.min(3, seBands.length)];
441:                        HashMap bandMapper = new HashMap();
442:                        for (int i = 0; i < bands.length; i++) {
443:                            bands[i] = i + 1;
444:                            bandMapper.put(new Integer((int) seBands[i].getId()
445:                                    .longValue()), new Integer(i));
446:                        }
447:                        rParam.setSourceBands(bands);
448:                        rParam.setBandMapper(bandMapper);
449:
450:                        //if we don't provide an ImageLayout to the JAI ImageRead operation, it'll try to read
451:                        //the entire raster layer!  It's only a slight abuse of the semantics of the word "tile"
452:                        //when we tell JAI that it can tile our image at exactly the size of the section of the
453:                        //raster layer we're looking to render.
454:                        final ImageLayout layout = new ImageLayout();
455:                        layout.setTileWidth(sourceRegion.width);
456:                        layout.setTileHeight(sourceRegion.height);
457:
458:                        ParameterBlock pb = new ParameterBlock();
459:                        pb.add(new Object());
460:                        pb.add(new Integer(level));
461:                        pb.add(Boolean.FALSE);
462:                        pb.add(Boolean.FALSE);
463:                        pb.add(Boolean.FALSE);
464:                        pb.add(null);
465:                        pb.add(null);
466:                        pb.add(rParam);
467:                        pb.add(imageIOReader);
468:
469:                        //We're not really interested in this renderedRaster, becasue I can't figure out how to get JAI
470:                        //to render the source area to a translated offset in the destination image.  Note that this
471:                        //is really a throwaway operation.  The ".getData()" call at the end forces the created RenderedImage
472:                        //to load its internal data, which causes the rParam.getDestination() bufferedImage to get loaded
473:                        //We use that at the end, essentially discarding this RenderedImage (it's not actually what we want,
474:                        //anyway).
475:                        JAI
476:                                .create(
477:                                        "ImageRead",
478:                                        pb,
479:                                        new RenderingHints(
480:                                                JAI.KEY_IMAGE_LAYOUT, layout))
481:                                .getData();
482:
483:                        if (DEBUG) {
484:                            Graphics2D g = outputImage.createGraphics();
485:                            g.setColor(Color.orange);
486:                            g.setFont(new Font("Sans-serif", Font.BOLD, 12));
487:                            g.drawString(sourceRegion.getMinX() + ","
488:                                    + sourceRegion.getMinY(), 30, 40);
489:                        }
490:
491:                    }
492:
493:                    // Create the coverage
494:                    return coverageFactory.create(coverageName, outputImage,
495:                            new GeneralEnvelope(outputImageEnvelope),
496:                            gridBands, null, null);
497:
498:                } catch (DataSourceException e) {
499:                    if (LOGGER.isLoggable(Level.SEVERE))
500:                        LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
501:                    throw new DataSourceException(e);
502:                } catch (SeException se) {
503:                    if (LOGGER.isLoggable(Level.SEVERE))
504:                        LOGGER.log(Level.SEVERE, se.getSeError().getErrDesc(),
505:                                se);
506:                    throw new DataSourceException(se);
507:                } catch (UnavailableArcSDEConnectionException uce) {
508:                    if (LOGGER.isLoggable(Level.SEVERE))
509:                        LOGGER
510:                                .log(Level.SEVERE, uce.getLocalizedMessage(),
511:                                        uce);
512:                    throw new DataSourceException(uce);
513:                } finally {
514:                    if (scon != null)
515:                        scon.close();
516:                }
517:            }
518:
519:            /**
520:             * @param sdeUrl -
521:             *            A StringBuffer containing a string of form
522:             *            'sde://user:pass@sdehost:[port]/[dbname]
523:             * 
524:             * @return a ConnectionConfig object representing these parameters
525:             */
526:            static ArcSDEConnectionConfig sdeURLToConnectionConfig(
527:                    StringBuffer sdeUrl) {
528:                // annoyingly, geoserver currently stores the user-entered SDE string as
529:                // a File, and passes us the
530:                // File object. The File object strips the 'sde://user...' into a
531:                // 'sde:/user..'. So we need to check
532:                // for both forms of the url.
533:                String sdeHost, sdeUser, sdePass, sdeDBName;
534:                int sdePort;
535:                if (sdeUrl.indexOf("sde:/") == -1) {
536:                    throw new IllegalArgumentException(
537:                            "ArcSDE Raster URL must be of the form sde://user:pass@sdehost:port/[dbname]#rasterTableName -- Got "
538:                                    + sdeUrl);
539:                } else {
540:                    if (sdeUrl.indexOf("sde://") == -1)
541:                        sdeUrl.delete(0, 5);
542:                    else
543:                        sdeUrl.delete(0, 6);
544:                }
545:
546:                int idx = sdeUrl.indexOf(":");
547:                if (idx == -1) {
548:                    throw new IllegalArgumentException(
549:                            "ArcSDE Raster URL must be of the form sde://user:pass@sdehost:port/[dbname]#rasterTableName");
550:                } else {
551:                    sdeUser = sdeUrl.substring(0, idx).toString();
552:                    sdeUrl.delete(0, idx);
553:                }
554:
555:                idx = sdeUrl.indexOf("@");
556:                if (idx == -1) {
557:                    throw new IllegalArgumentException(
558:                            "ArcSDE Raster URL must be of the form sde://user:pass@sdehost:port/[dbname]#rasterTableName");
559:                } else {
560:                    sdePass = sdeUrl.substring(1, idx).toString();
561:                    sdeUrl.delete(0, idx);
562:                }
563:
564:                idx = sdeUrl.indexOf(":");
565:                if (idx == -1) {
566:                    // there's no "port" specification. Assume 5151;
567:                    sdePort = 5151;
568:
569:                    idx = sdeUrl.indexOf("/");
570:                    if (idx == -1) {
571:                        throw new IllegalArgumentException(
572:                                "ArcSDE Raster URL must be of the form sde://user:pass@sdehost:port/[dbname]#rasterTableName");
573:                    } else {
574:                        sdeHost = sdeUrl.substring(1, idx).toString();
575:                        sdeUrl.delete(0, idx);
576:                    }
577:
578:                } else {
579:                    sdeHost = sdeUrl.substring(1, idx).toString();
580:                    sdeUrl.delete(0, idx);
581:
582:                    idx = sdeUrl.indexOf("/");
583:                    if (idx == -1) {
584:                        throw new IllegalArgumentException(
585:                                "ArcSDE Raster URL must be of the form sde://user:pass@sdehost:port/[dbname]#rasterTableName");
586:                    } else {
587:                        sdePort = Integer.parseInt(sdeUrl.substring(1, idx)
588:                                .toString());
589:                        sdeUrl.delete(0, idx);
590:                    }
591:                }
592:
593:                idx = sdeUrl.indexOf("#");
594:                if (idx == -1) {
595:                    throw new IllegalArgumentException(
596:                            "ArcSDE Raster URL must be of the form sde://user:pass@sdehost:port/[dbname]#rasterTableName");
597:                } else {
598:                    sdeDBName = sdeUrl.substring(1, idx).toString();
599:                    sdeUrl.delete(0, idx);
600:                }
601:
602:                return new ArcSDEConnectionConfig("arcsde", sdeHost, sdePort
603:                        + "", sdeDBName, sdeUser, sdePass);
604:            }
605:
606:            /**
607:             * Gets the coordinate system that will be associated to the
608:             * {@link GridCoverage}. The WGS84 coordinate system is used by default.
609:             * 
610:             */
611:            private void calculateCoordinateReferenceSystem()
612:                    throws DataSourceException {
613:
614:                if (rasterAttributes == null) {
615:                    throw new DataSourceException(
616:                            "Raster Attributes are null, can't calculated CRS info.");
617:                }
618:
619:                ArcSDEPooledConnection con = null;
620:                try {
621:                    con = connectionPool.getConnection();
622:                    SeRasterColumn rCol = new SeRasterColumn(con,
623:                            rasterAttributes.getRasterColumnId());
624:
625:                    PeProjectedCS pcs = new PeProjectedCS(rCol.getCoordRef()
626:                            .getProjectionDescription());
627:                    epsgCode = -1;
628:                    int[] projcs = PeFactory.projcsCodelist();
629:                    for (int i = 0; i < projcs.length; i++) {
630:                        try {
631:                            PeProjectedCS candidate = PeFactory
632:                                    .projcs(projcs[i]);
633:                            //in ArcSDE 9.2, if the PeFactory doesn't support a projection it claimed
634:                            //to support, it returns 'null'.  So check for it.
635:                            if (candidate != null
636:                                    && candidate.getName().trim().equals(
637:                                            pcs.getName()))
638:                                epsgCode = projcs[i];
639:                        } catch (PeProjectionException pe) {
640:                            // Strangely SDE includes codes in the projcsCodeList() that
641:                            // it doesn't actually support.
642:                            // Catch the exception and skip them here.
643:                        }
644:                    }
645:
646:                    if (epsgCode == -1) {
647:                        LOGGER
648:                                .warning("Couldn't determine EPSG code for this raster.  Using SDE's WKT-like coordSysDescription() instead.");
649:                        crs = CRS.parseWKT(rCol.getCoordRef()
650:                                .getCoordSysDescription());
651:                    } else {
652:                        crs = CRS.decode("EPSG:" + epsgCode);
653:                    }
654:
655:                    SeExtent sdeExtent = rasterAttributes.getExtent();
656:                    originalEnvelope = new GeneralEnvelope(crs);
657:                    originalEnvelope.setRange(0, sdeExtent.getMinX(), sdeExtent
658:                            .getMaxX());
659:                    originalEnvelope.setRange(1, sdeExtent.getMinY(), sdeExtent
660:                            .getMaxY());
661:                } catch (UnavailableArcSDEConnectionException e) {
662:                    LOGGER.log(Level.SEVERE, "", e);
663:                    throw new DataSourceException(e);
664:                } catch (SeException e) {
665:                    LOGGER.log(Level.SEVERE, "", e);
666:                    throw new DataSourceException(e.getSeError().getErrDesc(),
667:                            e);
668:                } catch (FactoryException e) {
669:                    LOGGER.log(Level.SEVERE, "", e);
670:                    throw new DataSourceException(e);
671:                } catch (PeProjectionException e) {
672:                    LOGGER.log(Level.SEVERE, "", e);
673:                    throw new DataSourceException(e);
674:                } finally {
675:                    if (con != null && !con.isClosed())
676:                        con.close();
677:                }
678:            }
679:
680:            /**
681:             * Checks the input prvided to this {@link ArcSDERasterGridCoverage2DReader} and sets all
682:             * the other objects and flags accordingly.
683:             * 
684:             * @param input provied to this {@link ArcSDERasterGridCoverage2DReader}.
685:             * @throws DataSourceException
686:             * @throws IOException
687:             */
688:            private void setupConnectionPool(Object input)
689:                    throws DataSourceException {
690:                if (input == null) {
691:                    final DataSourceException ex = new DataSourceException(
692:                            "No source set to read this coverage.");
693:                    if (LOGGER.isLoggable(Level.SEVERE))
694:                        LOGGER.log(Level.SEVERE, ex.getLocalizedMessage(), ex);
695:                    throw ex;
696:                }
697:
698:                // this will be our connection string
699:                String sdeUrl = null;
700:
701:                if (input instanceof  String) {
702:                    sdeUrl = (String) input;
703:                    LOGGER.warning("connecting to ArcSDE Raster: " + sdeUrl);
704:                } else if (input instanceof  File) {
705:                    sdeUrl = ((File) input).getPath();
706:                    LOGGER
707:                            .warning("connectiong via file-hack to ArcSDE Raster: "
708:                                    + sdeUrl);
709:                } else {
710:                    throw new IllegalArgumentException(
711:                            "Unsupported input type: " + input.getClass());
712:                }
713:
714:                ArcSDEConnectionConfig sdeConfig = sdeURLToConnectionConfig(new StringBuffer(
715:                        sdeUrl));
716:                if (sdeUrl.indexOf(";") != -1) {
717:                    final String extraParams = sdeUrl.substring(sdeUrl
718:                            .indexOf(";") + 1, sdeUrl.length());
719:                    sdeUrl = sdeUrl.substring(0, sdeUrl.indexOf(";"));
720:
721:                    // Right now we only support one kind of extra parameter, so we'll pull it out here.
722:                    if (extraParams.indexOf("LZERO_ORIGIN_TILE=") != -1) {
723:                        String offsetTile = extraParams.substring(extraParams
724:                                .indexOf("LZERO_ORIGIN_TILE=") + 18);
725:                        int xOffsetTile = Integer.parseInt(offsetTile
726:                                .substring(0, offsetTile.indexOf(",")));
727:                        int yOffsetTile = Integer.parseInt(offsetTile
728:                                .substring(offsetTile.indexOf(",") + 1));
729:                        _levelZeroPRP = new Point(xOffsetTile, yOffsetTile);
730:                    }
731:
732:                }
733:                rasterTable = sdeUrl.substring(sdeUrl.indexOf("#") + 1);
734:
735:                if (LOGGER.isLoggable(Level.FINE))
736:                    LOGGER.fine("Building ArcSDEGridCoverageReader2D for "
737:                            + sdeConfig + ", with raster table " + rasterTable);
738:
739:                connectionPool = ArcSDEConnectionPoolFactory.getInstance()
740:                        .createPool(sdeConfig);
741:
742:                try {
743:                    ArcSDEPooledConnection scon = connectionPool
744:                            .getConnection();
745:
746:                    SeTable sTable = connectionPool.getSdeTable(scon,
747:                            rasterTable);
748:                    SeQuery q = null;
749:                    try {
750:                        SeColumnDefinition[] cols = sTable.describe();
751:                        ArrayList fetchColumns = new ArrayList();
752:                        for (int i = 0; i < cols.length; i++) {
753:                            if (cols[i].getType() == SeColumnDefinition.TYPE_RASTER)
754:                                fetchColumns.add(cols[i].getName());
755:                        }
756:                        if (fetchColumns.size() == 0)
757:                            throw new DataSourceException(
758:                                    "Couldn't find any TYPE_RASTER columns in ArcSDE table "
759:                                            + rasterTable);
760:
761:                        rasterColumns = (String[]) fetchColumns
762:                                .toArray(new String[fetchColumns.size()]);
763:                        q = new SeQuery(scon, rasterColumns,
764:                                new SeSqlConstruct(rasterTable));
765:                        q.prepareQuery();
766:                        q.execute();
767:
768:                        SeRow r = q.fetch();
769:                        rasterAttributes = r.getRaster(0);
770:
771:                        q.close();
772:                    } catch (SeException se) {
773:                        throw new DataSourceException(
774:                                "Error fetching raster connection data from "
775:                                        + rasterTable + ": "
776:                                        + se.getSeError().getErrDesc(), se);
777:                    } finally {
778:                        if (scon != null && !scon.isClosed())
779:                            scon.close();
780:                    }
781:
782:                } catch (UnavailableArcSDEConnectionException uce) {
783:                    throw new DataSourceException(
784:                            "Unable to fetch a connection to ArcSDE server at "
785:                                    + connectionPool.getConfig()
786:                                            .getServerName() + ".", uce);
787:                }
788:
789:            }
790:
791:            /**
792:             * Inspects the band layout of this raster layer to determine whether this reader can actually
793:             * support this raster layer, what sort of BufferedImage to create when rendering this layer
794:             * and how to describe each band in rendered layers.
795:             *  
796:             * @throws DataSourceException if there's an error communicating with SDE about this raster layer.
797:             */
798:            private void calculateBandDependentInfo()
799:                    throws DataSourceException {
800:                try {
801:                    SeRasterBand[] sdeBands = rasterAttributes.getBands();
802:                    bandInfo = new HashMap();
803:                    for (int i = 0; i < sdeBands.length; i++) {
804:                        bandInfo.put(new Long(sdeBands[i].getId().longValue()),
805:                                ArcSDERasterBandCopier.getInstance(
806:                                        rasterAttributes.getPixelType(),
807:                                        pyramidInfo.tileHeight,
808:                                        pyramidInfo.tileWidth));
809:                    }
810:
811:                    for (int i = 0; i < rasterAttributes.getNumBands(); i++) {
812:                        if (rasterAttributes.getBandInfo(i + 1).hasColorMap()) {
813:                            throw new IllegalArgumentException(
814:                                    "ArcSDERasterGridCoverage2DReader doesn't support reading from ColorMapped SDE rasters yet.");
815:                        }
816:                    }
817:
818:                    if (rasterAttributes.getNumBands() == 1) {
819:                        if (rasterAttributes.getPixelType() == SeRaster.SE_PIXEL_TYPE_1BIT) {
820:                            LOGGER
821:                                    .warning("Discovered 1-bit single-band raster.  Using return image type: TYPE_BYTE_BINARY and 1-bit black/white category.");
822:                            NumberRange sampleValueRange = new NumberRange(0, 1);
823:                            Category bitBandCat = new Category(
824:                                    this .coverageName + ": Band One (1-bit)",
825:                                    new Color[] { Color.BLACK, Color.WHITE },
826:                                    sampleValueRange,
827:                                    LinearTransform1D.IDENTITY);
828:                            gridBands = new GridSampleDimension[1];
829:                            gridBands[0] = new GridSampleDimension(bitBandCat
830:                                    .getName(), new Category[] { bitBandCat },
831:                                    null).geophysics(true);
832:
833:                            bufferedImageType = BufferedImage.TYPE_BYTE_BINARY;
834:                        } else if (rasterAttributes.getPixelType() == SeRaster.SE_PIXEL_TYPE_8BIT_S
835:                                || rasterAttributes.getPixelType() == SeRaster.SE_PIXEL_TYPE_8BIT_U) {
836:                            LOGGER
837:                                    .warning("Discovered 8-bit single-band raster.  Using return image type: TYPE_BYTE_GRAY");
838:                            NumberRange sampleValueRange = new NumberRange(0,
839:                                    255);
840:                            Category greyscaleBandCat = new Category(
841:                                    this .coverageName
842:                                            + ": Band One (grayscale)",
843:                                    new Color[] { Color.BLACK, Color.WHITE },
844:                                    sampleValueRange,
845:                                    LinearTransform1D.IDENTITY);
846:                            gridBands = new GridSampleDimension[1];
847:                            gridBands[0] = new GridSampleDimension(
848:                                    greyscaleBandCat.getName(),
849:                                    new Category[] { greyscaleBandCat }, null)
850:                                    .geophysics(true);
851:
852:                            bufferedImageType = BufferedImage.TYPE_BYTE_GRAY;
853:                        } else {
854:                            throw new IllegalArgumentException(
855:                                    "One-band, non-colormapped raster layers with type "
856:                                            + rasterAttributes.getPixelType()
857:                                            + " are not supported.");
858:                        }
859:
860:                    } else if (rasterAttributes.getNumBands() == 3
861:                            || rasterAttributes.getNumBands() == 4) {
862:                        if (rasterAttributes.getPixelType() != SeRaster.SE_PIXEL_TYPE_8BIT_U) {
863:                            throw new IllegalArgumentException(
864:                                    "3 or 4 band rasters are only supported if they have pixel type 8-bit unsigned pixels.");
865:                        }
866:                        LOGGER
867:                                .warning("Three or four banded non-colormapped raster detected.  Assuming bands 1,2 and 3 constitue a 3-band RGB image.  Using return image type: TYPE_INT_ARGB (alpha will be used to support no-data pixels)");
868:                        NumberRange sampleValueRange = new NumberRange(0, 255);
869:                        Category nan = new Category("no-data",
870:                                new Color[] { new Color(0x00000000) },
871:                                new NumberRange(0, 0),
872:                                LinearTransform1D.IDENTITY);
873:                        Category white = new Category("valid-data",
874:                                new Color[] { new Color(0xff000000) },
875:                                new NumberRange(255, 255),
876:                                LinearTransform1D.IDENTITY);
877:                        Category redBandCat = new Category("red", new Color[] {
878:                                Color.BLACK, Color.RED }, sampleValueRange,
879:                                LinearTransform1D.IDENTITY);
880:                        Category blueBandCat = new Category("blue",
881:                                new Color[] { Color.BLACK, Color.BLUE },
882:                                sampleValueRange, LinearTransform1D.IDENTITY);
883:                        Category greenBandCat = new Category("green",
884:                                new Color[] { Color.BLACK, Color.GREEN },
885:                                sampleValueRange, LinearTransform1D.IDENTITY);
886:
887:                        gridBands = new GridSampleDimension[4];
888:                        gridBands[0] = new GridSampleDimension("Red band",
889:                                new Category[] { redBandCat }, null);
890:                        gridBands[1] = new GridSampleDimension("Green band",
891:                                new Category[] { blueBandCat }, null);
892:                        gridBands[2] = new GridSampleDimension("Blue band",
893:                                new Category[] { greenBandCat }, null);
894:                        gridBands[3] = new GridSampleDimension(
895:                                "NODATA Mask Band",
896:                                new Category[] { nan, white }, null);
897:
898:                        bufferedImageType = BufferedImage.TYPE_INT_ARGB;
899:                    } else {
900:                        StringBuffer errmsg = new StringBuffer();
901:                        errmsg
902:                                .append("ArcSDERasterGridCoverage2DReader doesn't support ");
903:                        errmsg.append(rasterAttributes.getNumBands());
904:                        errmsg.append("-banded images of type ");
905:                        errmsg.append(rasterAttributes.getPixelType());
906:                        throw new IllegalArgumentException();
907:                    }
908:
909:                } catch (SeException se) {
910:                    LOGGER.log(Level.SEVERE, se.getSeError().getErrDesc(), se);
911:                    throw new DataSourceException(se);
912:                }
913:            }
914:
915:            private void setupCoverageMetadata() {
916:
917:                ArcSDEPyramidLevel highestRes = pyramidInfo
918:                        .getPyramidLevel(pyramidInfo.getNumLevels() - 1);
919:                Rectangle actualDim = new Rectangle(0, 0, highestRes
920:                        .getNumTilesWide()
921:                        * tileWidth, highestRes.getNumTilesHigh() * tileHeight);
922:                originalGridRange = new GeneralGridRange(actualDim);
923:
924:                coverageName = rasterTable;
925:            }
926:
927:            private void setupImageIOReader() throws DataSourceException {
928:                HashMap readerMap = new HashMap();
929:                readerMap.put(ArcSDERasterReaderSpi.PYRAMID, pyramidInfo);
930:                readerMap.put(ArcSDERasterReaderSpi.RASTER_TABLE, rasterTable);
931:                readerMap.put(ArcSDERasterReaderSpi.RASTER_COLUMN,
932:                        rasterColumns[0]);
933:
934:                try {
935:                    imageIOReader = (ArcSDERasterReader) new ArcSDERasterReaderSpi()
936:                            .createReaderInstance(readerMap);
937:                } catch (IOException ioe) {
938:                    LOGGER
939:                            .log(
940:                                    Level.SEVERE,
941:                                    "Error creating ImageIOReader in ArcSDERasterGridCoverage2DReader",
942:                                    ioe);
943:                    throw new DataSourceException(ioe);
944:                }
945:            }
946:
947:            private BufferedImage createInitialBufferedImage(final int width,
948:                    final int height) throws DataSourceException {
949:                final BufferedImage ret = new BufferedImage(width, height,
950:                        bufferedImageType);
951:                // By default BufferedImages are created with all banks set to zero.  That's an all-black, transparent image.
952:                // Transparency is handled in the ArcSDERasterBandCopier.  Blackness isn't.  Let's fix that and set
953:                // the image to white.
954:                int[] pixels = new int[width * height];
955:                for (int i = 0; i < width * height; i++) {
956:                    pixels[i] = 0x00ffffff;
957:                }
958:                ret.setRGB(0, 0, width, height, pixels, 0, 1);
959:
960:                return ret;
961:            }
962:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.