Source Code Cross Referenced for MetadataSource.java in  » GIS » GeoTools-2.4.1 » org » geotools » metadata » sql » 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.metadata.sql 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2004-2006, GeoTools Project Managment Committee (PMC)
005:         *    (C) 2004, Institut de Recherche pour le Développement
006:         *   
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation;
010:         *    version 2.1 of the License.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.metadata.sql;
018:
019:        // J2SE dependencies
020:        import java.io.IOException;
021:        import java.io.InputStream;
022:        import java.lang.reflect.Array;
023:        import java.lang.reflect.InvocationTargetException;
024:        import java.lang.reflect.Method;
025:        import java.lang.reflect.Proxy;
026:        import java.net.MalformedURLException;
027:        import java.net.URL;
028:        import java.net.URI;
029:        import java.net.URISyntaxException;
030:        import java.sql.Connection;
031:        import java.sql.SQLException;
032:        import java.util.ArrayList;
033:        import java.util.Collection;
034:        import java.util.HashMap;
035:        import java.util.Iterator;
036:        import java.util.LinkedHashSet;
037:        import java.util.List;
038:        import java.util.Map;
039:        import java.util.Properties;
040:        import java.util.SortedSet;
041:        import java.util.TreeSet;
042:
043:        // OpenGIS dependencies
044:        import org.opengis.metadata.MetaData;
045:        import org.opengis.util.CodeList;
046:        import org.opengis.util.InternationalString;
047:
048:        // Geotools dependencies
049:        import org.geotools.util.SimpleInternationalString;
050:
051:        /**
052:         * A connection to a metadata database. The metadata database can be created
053:         * using one of the scripts suggested in GeoAPI, for example
054:         * <code><A HREF="http://geoapi.sourceforge.net/snapshot/javadoc/org/opengis/metadata/doc-files/postgre/create.sql">create.sql</A></CODE>.
055:         * Then, in order to get for example a telephone number, the following code
056:         * may be used.
057:         *
058:         * <BLOCKQUOTE><PRE>
059:         * import org.opengis.metadata.citation.{@linkplain org.opengis.metadata.citation.Telephone Telephone};
060:         * ...
061:         * Connection     connection = ...
062:         * MetadataSource source     = new MetadataSource(connection);
063:         * Telephone      telephone  = (Telephone) source.getEntry(Telephone.class, id);
064:         * </PRE></BLOCKQUOTE>
065:         *
066:         * where {@code id} is the primary key value for the desired record in the
067:         * {@code CI_Telephone} table.
068:         *
069:         * @author Touraïvane
070:         * @author Olivier Kartotaroeno
071:         * @author Martin Desruisseaux
072:         *
073:         * @since 2.1
074:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/metadata/sql/MetadataSource.java $
075:         */
076:        public class MetadataSource {
077:            /**
078:             * The package for metadata <strong>interfaces</strong> (not the implementation).
079:             */
080:            final String metadataPackage = "org.opengis.metadata.";
081:
082:            /**
083:             * The connection to the database.
084:             */
085:            private final Connection connection;
086:
087:            /**
088:             * The SQL query to use for fetching the attribute in a specific row.
089:             * The first question mark is the table name to search into; the second
090:             * one is the primary key of the record to search.
091:             */
092:            private final String query = "SELECT * FROM metadata.\"?\" WHERE id=?";
093:
094:            /**
095:             * The SQL query to use for fetching a code list element.
096:             * The first question mark is the table name to search into;
097:             * the second one is the primary key of the element to search.
098:             */
099:            private final String codeQuery = "SELECT name FROM metadata.\"?\" WHERE code=?";
100:
101:            /**
102:             * The prepared statements created is previous call to {@link #getValue}.
103:             * Those statements are encapsulated into {@link MetadataResult} objects.
104:             */
105:            private final Map statements = new HashMap();
106:
107:            /**
108:             * The map from GeoAPI names to ISO names. For example the GeoAPI
109:             * {@link org.opengis.metadata.citation.Citation} interface maps
110:             * to the ISO 19115 {@code CI_Citation} name.
111:             */
112:            private final Properties geoApiToIso = new Properties();
113:
114:            /**
115:             * Type of collections.
116:             */
117:            private final Properties collectionTypes = new Properties();
118:
119:            /**
120:             * The class loader to use for proxy creation.
121:             */
122:            private final ClassLoader loader;
123:
124:            /**
125:             * Creates a new metadata source.
126:             *
127:             * @param connection The connection to the database.
128:             */
129:            public MetadataSource(final Connection connection) {
130:                this .connection = connection;
131:                try {
132:                    InputStream in = MetaData.class
133:                            .getResourceAsStream("GeoAPI_to_ISO.properties");
134:                    geoApiToIso.load(in);
135:                    in.close();
136:                    in = MetaData.class
137:                            .getResourceAsStream("CollectionTypes.properties");
138:                    // TODO: remove the (!= null) check after the next geoapi update.
139:                    if (in != null) {
140:                        collectionTypes.load(in);
141:                        in.close();
142:                    }
143:                } catch (IOException exception) {
144:                    /*
145:                     * Note: we do not expose the checked IOException because in a future
146:                     *       version (when we will be allowed to use J2SE 1.5), it should
147:                     *       disaspear. This is because a J2SE 1.5 enabled version should
148:                     *       use method's annotations instead.
149:                     */
150:                    throw new MetadataException("Can't read resources.",
151:                            exception); // TODO: localize
152:                }
153:                loader = getClass().getClassLoader();
154:            }
155:
156:            /**
157:             * Returns an implementation of the specified metadata interface filled
158:             * with the data referenced by the specified identifier. Alternatively,
159:             * this method can also returns a {@link CodeList} element.
160:             *
161:             * @param  type The interface to implement (e.g.
162:             *         {@link org.opengis.metadata.citation.Citation}), or
163:             *         the {@link CodeList}.
164:             * @param  identifier The identifier used in order to locate the record for
165:             *         the metadata entity to be created. This is usually the primary key
166:             *         of the record to search for.
167:             * @return An implementation of the required interface, or the code list element.
168:             * @throws SQLException if a SQL query failed.
169:             */
170:            public synchronized Object getEntry(final Class type,
171:                    final String identifier) throws SQLException {
172:                if (CodeList.class.isAssignableFrom(type)) {
173:                    return getCodeList(type, identifier);
174:                }
175:                return Proxy.newProxyInstance(loader, new Class[] { type },
176:                        new MetadataEntity(identifier, this ));
177:            }
178:
179:            /**
180:             * Returns an attribute from a table.
181:             *
182:             * @param  type       The interface class. This is mapped to the table name in the database.
183:             * @param  method     The method invoked. This is mapped to the column name in the database.
184:             * @param  identifier The primary key of the record to search for.
185:             * @return The value of the requested attribute.
186:             * @throws SQLException if the SQL query failed.
187:             */
188:            final synchronized Object getValue(final Class type,
189:                    final Method method, final String identifier)
190:                    throws SQLException {
191:                final String className = getClassName(type);
192:                MetadataResult result = (MetadataResult) statements.get(type);
193:                if (result == null) {
194:                    result = new MetadataResult(connection, query,
195:                            getTableName(className));
196:                    statements.put(type, result);
197:                }
198:                final String columnName = getColumnName(className, method);
199:                final Class valueType = method.getReturnType();
200:                /*
201:                 * Process the ResultSet value according the expected return type. If a collection
202:                 * is expected, then assumes that the ResultSet contains an array and invokes the
203:                 * 'getValue' method for each element.
204:                 */
205:                if (Collection.class.isAssignableFrom(valueType)) {
206:                    final Collection collection;
207:                    if (List.class.isAssignableFrom(valueType)) {
208:                        collection = new ArrayList();
209:                    } else if (SortedSet.class.isAssignableFrom(valueType)) {
210:                        collection = new TreeSet();
211:                    } else {
212:                        collection = new LinkedHashSet();
213:                    }
214:                    assert valueType.isAssignableFrom(collection.getClass());
215:                    final Object elements = result.getArray(identifier,
216:                            columnName);
217:                    if (elements != null) {
218:                        final Class elementType = getElementType(className,
219:                                method);
220:                        final boolean isMetadata = isMetadata(elementType);
221:                        final int length = Array.getLength(elements);
222:                        for (int i = 0; i < length; i++) {
223:                            collection.add(isMetadata ? getEntry(elementType,
224:                                    Array.get(elements, i).toString())
225:                                    : convert(elementType, Array.get(elements,
226:                                            i)));
227:                        }
228:                    }
229:                    return collection;
230:                }
231:                /*
232:                 * If a GeoAPI interface or a code list is expected, then assumes that the ResultSet
233:                 * value is a foreigner key. Queries again the database in the foreigner table.
234:                 */
235:                if (valueType.isInterface() && isMetadata(valueType)) {
236:                    final String foreigner = result.getString(identifier,
237:                            columnName);
238:                    return result.wasNull() ? null : getEntry(valueType,
239:                            foreigner);
240:                }
241:                if (CodeList.class.isAssignableFrom(valueType)) {
242:                    final String foreigner = result.getString(identifier,
243:                            columnName);
244:                    return result.wasNull() ? null : getCodeList(valueType,
245:                            foreigner);
246:                }
247:                /*
248:                 * Not a foreigner key. Get the value and transform it to the
249:                 * espected type, if needed.
250:                 */
251:                return convert(valueType, result.getObject(identifier,
252:                        columnName));
253:            }
254:
255:            /**
256:             * Returns {@code true} if the specified type belong to the metadata package.
257:             */
258:            private boolean isMetadata(final Class valueType) {
259:                return valueType.getName().startsWith(metadataPackage);
260:            }
261:
262:            /**
263:             * Converts the specified non-metadata value into an object of the expected type.
264:             * The expected value is an instance of a class outside the metadata package, for
265:             * example {@link String}, {@link InternationalString}, {@link URI}, etc.
266:             */
267:            private static Object convert(final Class valueType,
268:                    final Object value) {
269:                if (value != null
270:                        && !valueType.isAssignableFrom(value.getClass())) {
271:                    if (InternationalString.class.isAssignableFrom(valueType)) {
272:                        return new SimpleInternationalString(value.toString());
273:                    }
274:                    if (URL.class.isAssignableFrom(valueType))
275:                        try {
276:                            return new URL(value.toString());
277:                        } catch (MalformedURLException exception) {
278:                            // TODO: localize and provides more details.
279:                            throw new MetadataException("Illegal value.",
280:                                    exception);
281:                        }
282:                    if (URI.class.isAssignableFrom(valueType))
283:                        try {
284:                            return new URI(value.toString());
285:                        } catch (URISyntaxException exception) {
286:                            // TODO: localize and provides more details.
287:                            throw new MetadataException("Illegal value.",
288:                                    exception);
289:                        }
290:                }
291:                return value;
292:            }
293:
294:            /**
295:             * Returns a code list of the given type.
296:             *
297:             * @param  type The type, as a subclass of {@link CodeList}.
298:             * @param  identifier The identifier in the code list. This method accepts either The numerical
299:             *         value of the code to search for (usually the primary key), or the code name.
300:             * @return The code list element.
301:             * @throws SQLException if a SQL query failed.
302:             */
303:            private CodeList getCodeList(final Class type, String identifier)
304:                    throws SQLException {
305:                assert Thread.holdsLock(this );
306:                final String className = getClassName(type);
307:                int code; // The identifier as an integer.
308:                boolean isNumerical; // 'true' if 'code' is valid.
309:                try {
310:                    code = Integer.parseInt(identifier);
311:                    isNumerical = true;
312:                } catch (NumberFormatException exception) {
313:                    code = 0;
314:                    isNumerical = false;
315:                }
316:                /*
317:                 * Converts the numerical value into the code list name.
318:                 */
319:                if (isNumerical) {
320:                    MetadataResult result = (MetadataResult) statements
321:                            .get(type);
322:                    if (result == null) {
323:                        result = new MetadataResult(connection, codeQuery,
324:                                getTableName(className));
325:                        statements.put(type, result);
326:                    }
327:                    identifier = result.getString(identifier);
328:                }
329:                /*
330:                 * Search a code list with the same name than the one declared
331:                 * in the database. We will use name instead of code numerical
332:                 * value, since the later is more bug prone.
333:                 */
334:                final CodeList[] values;
335:                try {
336:                    values = (CodeList[]) type.getMethod("values",
337:                            (Class[]) null).invoke(null, (Object[]) null);
338:                } catch (NoSuchMethodException exception) {
339:                    throw new MetadataException("Can't read code list.",
340:                            exception); // TODO: localize
341:                } catch (IllegalAccessException exception) {
342:                    throw new MetadataException("Can't read code list.",
343:                            exception); // TODO: localize
344:                } catch (InvocationTargetException exception) {
345:                    throw new MetadataException("Can't read code list.",
346:                            exception); // TODO: localize
347:                }
348:                CodeList candidate;
349:                final StringBuffer candidateName = new StringBuffer(className);
350:                candidateName.append('.');
351:                final int base = candidateName.length();
352:                if (code >= 1 && code < values.length) {
353:                    candidate = values[code - 1];
354:                    candidateName.append(candidate.name());
355:                    if (identifier.equals(geoApiToIso.getProperty(candidateName
356:                            .toString()))) {
357:                        return candidate;
358:                    }
359:                }
360:                /*
361:                 * The previous code was an optimization which checked directly the code list
362:                 * for the same code than the one used in the database. Most of the time, the
363:                 * name matches and this loop is never executed. If we reach this point, then
364:                 * maybe the numerical code are not the same in the database than in the Java
365:                 * CodeList implementation. Check each code list element by name.
366:                 */
367:                for (int i = 0; i < values.length; i++) {
368:                    candidate = values[i];
369:                    candidateName.setLength(base);
370:                    candidateName.append(candidate.name());
371:                    if (identifier.equals(geoApiToIso.getProperty(candidateName
372:                            .toString()))) {
373:                        return candidate;
374:                    }
375:                }
376:                // TODO: localize
377:                throw new SQLException("Unknow code list: \"" + identifier
378:                        + "\" in table \"" + getTableName(className) + '"');
379:            }
380:
381:            /**
382:             * Returns the unqualified Java interface name for the specified type.
383:             * This is usually the GeoAPI name.
384:             */
385:            private static String getClassName(final Class type) {
386:                final String className = type.getName();
387:                return className.substring(className.lastIndexOf('.') + 1);
388:            }
389:
390:            /**
391:             * Returns the table name for the specified class.
392:             * This is usually the ISO 19115 name.
393:             */
394:            private String getTableName(final String className) {
395:                final String tableName = geoApiToIso.getProperty(className);
396:                return (tableName != null) ? tableName : className;
397:            }
398:
399:            /**
400:             * Returns the column name for the specified method.
401:             */
402:            private String getColumnName(final String className,
403:                    final Method method) {
404:                final String methodName = method.getName();
405:                final String columnName = geoApiToIso.getProperty(className
406:                        + '.' + methodName);
407:                return (columnName != null) ? columnName : methodName;
408:            }
409:
410:            /**
411:             * Returns the element type in collection for the specified method.
412:             */
413:            private Class getElementType(final String className,
414:                    final Method method) {
415:                final String key = className + '.' + method.getName();
416:                final String typeName = collectionTypes.getProperty(key);
417:                Exception cause = null;
418:                if (typeName != null)
419:                    try {
420:                        return Class.forName(typeName);
421:                    } catch (ClassNotFoundException exception) {
422:                        cause = exception;
423:                    }
424:                // TODO: localize.
425:                final MetadataException e = new MetadataException(
426:                        "Unknow element type for " + key);
427:                if (cause != null) {
428:                    e.initCause(cause);
429:                }
430:                throw e;
431:            }
432:
433:            /**
434:             * Close all connections used in this object.
435:             */
436:            public synchronized void close() throws SQLException {
437:                for (final Iterator it = statements.values().iterator(); it
438:                        .hasNext();) {
439:                    ((MetadataResult) it.next()).close();
440:                    it.remove();
441:                }
442:                connection.close();
443:            }
444:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.