Source Code Cross Referenced for QuickTileCache.java in  » GIS » GeoServer » org » vfny » geoserver » wms » responses » map » metatile » 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 » GeoServer » org.vfny.geoserver.wms.responses.map.metatile 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002:         * This code is licensed under the GPL 2.0 license, availible at the root
003:         * application directory.
004:         */
005:        package org.vfny.geoserver.wms.responses.map.metatile;
006:
007:        import java.awt.Point;
008:        import java.awt.geom.Point2D;
009:        import java.awt.image.RenderedImage;
010:        import java.util.Enumeration;
011:        import java.util.HashSet;
012:        import java.util.Set;
013:
014:        import javax.servlet.http.HttpServletRequest;
015:
016:        import org.apache.commons.lang.builder.EqualsBuilder;
017:        import org.apache.commons.lang.builder.HashCodeBuilder;
018:        import org.geoserver.wfs.TransactionEvent;
019:        import org.geoserver.wfs.TransactionListener;
020:        import org.geoserver.wfs.WFSException;
021:        import org.geotools.util.SoftValueHashMap;
022:        import org.geotools.util.WeakHashSet;
023:        import org.vfny.geoserver.global.GeoServer;
024:        import org.vfny.geoserver.wms.requests.GetMapRequest;
025:
026:        import com.vividsolutions.jts.geom.Envelope;
027:
028:        public class QuickTileCache implements  TransactionListener {
029:            /**
030:             * Set of parameters that we can ignore, since they do not define a map, are
031:             * either unrelated, or define the tiling instead
032:             */
033:            private static final Set ignoredParameters;
034:
035:            static {
036:                ignoredParameters = new HashSet();
037:                ignoredParameters.add("REQUEST");
038:                ignoredParameters.add("TILED");
039:                ignoredParameters.add("BBOX");
040:                ignoredParameters.add("WIDTH");
041:                ignoredParameters.add("HEIGHT");
042:                ignoredParameters.add("SERVICE");
043:                ignoredParameters.add("VERSION");
044:                ignoredParameters.add("EXCEPTIONS");
045:            }
046:
047:            /**
048:             * Canonicalizer used to return the same object when two threads ask for the
049:             * same meta-tile
050:             */
051:            private WeakHashSet metaTileKeys = new WeakHashSet();
052:
053:            private SoftValueHashMap tileCache = new SoftValueHashMap(0);
054:
055:            public QuickTileCache(GeoServer geoServer) {
056:                geoServer.addListener(new GeoServer.Listener() {
057:
058:                    public void changed() {
059:                        tileCache.clear();
060:                    }
061:
062:                });
063:            }
064:
065:            /**
066:             * For testing only
067:             */
068:            QuickTileCache() {
069:            }
070:
071:            /**
072:             * Given a tiled request, builds a key that can be used to access the cache
073:             * looking for a specific meta-tile, and also as a synchronization tool to
074:             * avoid multiple requests to trigger parallel computation of the same
075:             * meta-tile
076:             * 
077:             * @param request
078:             * @return
079:             */
080:            public MetaTileKey getMetaTileKey(GetMapRequest request) {
081:                String mapDefinition = buildMapDefinition(request
082:                        .getHttpServletRequest());
083:                Envelope bbox = request.getBbox();
084:                Point2D origin = request.getTilesOrigin();
085:                MapKey mapKey = new MapKey(mapDefinition, normalize(bbox
086:                        .getWidth()
087:                        / request.getWidth()), origin);
088:                Point tileCoords = getTileCoordinates(bbox, origin);
089:                Point metaTileCoords = getMetaTileCoordinates(tileCoords);
090:                MetaTileKey key = new MetaTileKey(mapKey, metaTileCoords);
091:
092:                // since this will be used for thread synchronization, we have to make
093:                // sure two thread asking for the same meta tile will get the same key
094:                // object
095:                return (MetaTileKey) metaTileKeys.canonicalize(key);
096:            }
097:
098:            /**
099:             * Given a tile, returns the coordinates of the meta-tile that contains it
100:             * (where the meta-tile coordinate is the coordinate of its lower left
101:             * subtile)
102:             * 
103:             * @param tileCoords
104:             * @return
105:             */
106:            Point getMetaTileCoordinates(Point tileCoords) {
107:                int x = tileCoords.x;
108:                int y = tileCoords.y;
109:                int rx = x % 3;
110:                int ry = y % 3;
111:                int mtx = (rx == 0) ? x : ((x >= 0) ? (x - rx) : (x - 3 - rx));
112:                int mty = (ry == 0) ? y : ((y >= 0) ? (y - ry) : (y - 3 - ry));
113:
114:                return new Point(mtx, mty);
115:            }
116:
117:            /**
118:             * Given an envelope and origin, find the tile coordinate (row,col)
119:             * 
120:             * @param env
121:             * @param origin
122:             * @return
123:             */
124:            Point getTileCoordinates(Envelope env, Point2D origin) {
125:                // this was using the low left corner and Math.round, but turned
126:                // out to be fragile when fairly zoomed in. Using the tile center
127:                // and then flooring the division seems to work much more reliably.
128:                double centerx = env.getMinX() + env.getWidth() / 2;
129:                double centery = env.getMinY() + env.getHeight() / 2;
130:                int x = (int) Math.floor((centerx - origin.getX())
131:                        / env.getWidth());
132:                int y = (int) Math.floor((centery - origin.getY())
133:                        / env.getWidth());
134:
135:                return new Point(x, y);
136:            }
137:
138:            /**
139:             * This is tricky. We need to have doubles that can be compared by equality
140:             * because resolution and origin are doubles, and are part of a hashmap key,
141:             * so we have to normalize them somehow, in order to make the little
142:             * differences disappear. Here we take the mantissa, which is made of 52
143:             * bits, and throw away the 20 more significant ones, which means we're
144:             * dealing with 12 significant decimal digits (2^40 -> more or less one
145:             * billion million). See also <a
146:             * href="http://en.wikipedia.org/wiki/IEEE_754">IEEE 754</a> on Wikipedia.
147:             * 
148:             * @param d
149:             * @return
150:             */
151:            static double normalize(double d) {
152:                if (Double.isInfinite(d) || Double.isNaN(d)) {
153:                    return d;
154:                }
155:
156:                return Math.round(d * 10e6) / 10e6;
157:            }
158:
159:            /**
160:             * Turns the request back into a sort of GET request (not url-encoded) for
161:             * fast comparison
162:             * 
163:             * @param request
164:             * @return
165:             */
166:            private String buildMapDefinition(HttpServletRequest request) {
167:                StringBuffer sb = new StringBuffer();
168:                Enumeration en = request.getParameterNames();
169:
170:                while (en.hasMoreElements()) {
171:                    String paramName = (String) en.nextElement();
172:
173:                    if (ignoredParameters.contains(paramName.toUpperCase())) {
174:                        continue;
175:                    }
176:
177:                    // we don't have multi-valued parameters afaik, otherwise we would
178:                    // have to use getParameterValues and deal with the returned array
179:                    sb.append(paramName).append('=').append(
180:                            request.getParameter(paramName));
181:
182:                    if (en.hasMoreElements()) {
183:                        sb.append('&');
184:                    }
185:                }
186:
187:                return sb.toString();
188:            }
189:
190:            /**
191:             * Key defining a tiling layer in a map
192:             */
193:            static class MapKey {
194:                String mapDefinition;
195:
196:                double resolution;
197:
198:                Point2D origin;
199:
200:                public MapKey(String mapDefinition, double resolution,
201:                        Point2D origin) {
202:                    super ();
203:                    this .mapDefinition = mapDefinition;
204:                    this .resolution = resolution;
205:                    this .origin = origin;
206:                }
207:
208:                public int hashCode() {
209:                    return new HashCodeBuilder().append(mapDefinition).append(
210:                            resolution).append(resolution).append(origin)
211:                            .toHashCode();
212:                }
213:
214:                public boolean equals(Object obj) {
215:                    if (!(obj instanceof  MapKey)) {
216:                        return false;
217:                    }
218:
219:                    MapKey other = (MapKey) obj;
220:
221:                    return new EqualsBuilder().append(mapDefinition,
222:                            other.mapDefinition).append(resolution,
223:                            other.resolution).append(origin, other.origin)
224:                            .isEquals();
225:                }
226:
227:                public String toString() {
228:                    return mapDefinition + "\nw:" + "\nresolution:"
229:                            + resolution + "\norig:" + origin.getX() + ","
230:                            + origin.getY();
231:                }
232:            }
233:
234:            /**
235:             * Key that identifies a certain meta-tile in a tiled map layer
236:             */
237:            static class MetaTileKey {
238:                MapKey mapKey;
239:
240:                Point metaTileCoords;
241:
242:                public MetaTileKey(MapKey mapKey, Point metaTileCoords) {
243:                    super ();
244:                    this .mapKey = mapKey;
245:                    this .metaTileCoords = metaTileCoords;
246:                }
247:
248:                public Envelope getMetaTileEnvelope() {
249:                    double minx = mapKey.origin.getX()
250:                            + (mapKey.resolution * 256 * metaTileCoords.x);
251:                    double miny = mapKey.origin.getY()
252:                            + (mapKey.resolution * 256 * metaTileCoords.y);
253:
254:                    return new Envelope(minx, minx
255:                            + (mapKey.resolution * 256 * 3), miny, miny
256:                            + (mapKey.resolution * 256 * 3));
257:                }
258:
259:                public int hashCode() {
260:                    return new HashCodeBuilder().append(mapKey).append(
261:                            metaTileCoords).toHashCode();
262:                }
263:
264:                public boolean equals(Object obj) {
265:                    if (!(obj instanceof  MetaTileKey)) {
266:                        return false;
267:                    }
268:
269:                    MetaTileKey other = (MetaTileKey) obj;
270:
271:                    return new EqualsBuilder().append(mapKey, other.mapKey)
272:                            .append(metaTileCoords, other.metaTileCoords)
273:                            .isEquals();
274:                }
275:
276:                public int getMetaFactor() {
277:                    return 3;
278:                }
279:
280:                public int getTileSize() {
281:                    return 256;
282:                }
283:
284:                public String toString() {
285:                    return mapKey + "\nmtc:" + metaTileCoords.x + ","
286:                            + metaTileCoords.y;
287:                }
288:            }
289:
290:            /**
291:             * Gathers a tile from the cache, if available
292:             * 
293:             * @param key
294:             * @param request
295:             * @return
296:             */
297:            public synchronized RenderedImage getTile(MetaTileKey key,
298:                    GetMapRequest request) {
299:                CacheElement ce = (CacheElement) tileCache.get(key);
300:
301:                if (ce == null) {
302:                    return null;
303:                }
304:
305:                return getTile(key, request, ce.tiles);
306:            }
307:
308:            /**
309:             * 
310:             * @param key
311:             * @param request
312:             * @param tiles
313:             * @return
314:             */
315:            public RenderedImage getTile(MetaTileKey key,
316:                    GetMapRequest request, RenderedImage[] tiles) {
317:                Point tileCoord = getTileCoordinates(request.getBbox(),
318:                        key.mapKey.origin);
319:                Point metaCoord = key.metaTileCoords;
320:
321:                return tiles[tileCoord.x - metaCoord.x
322:                        + ((tileCoord.y - metaCoord.y) * key.getMetaFactor())];
323:            }
324:
325:            /**
326:             * Puts the specified tile array in the cache, and returns the tile the
327:             * request was looking for
328:             * 
329:             * @param key
330:             * @param request
331:             * @param tiles
332:             * @return
333:             */
334:            public synchronized void storeTiles(MetaTileKey key,
335:                    RenderedImage[] tiles) {
336:                tileCache.put(key, new CacheElement(tiles));
337:            }
338:
339:            class CacheElement {
340:                RenderedImage[] tiles;
341:
342:                public CacheElement(RenderedImage[] tiles) {
343:                    this .tiles = tiles;
344:                }
345:            }
346:
347:            public void dataStoreChange(TransactionEvent event)
348:                    throws WFSException {
349:                // if anything changes we just wipe out the cache. the mapkey
350:                // contains a string with part of the map request where the layer
351:                // name is included, but we would have to parse it and consider
352:                // also that the namespace may be missing in the getmap request
353:                tileCache.clear();
354:            }
355:        }
w_ww_.___j__a_v_a_2_s_.__c__o__m_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.