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


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2004-2007, 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:        package org.geotools.metadata;
017:
018:        // J2SE dependencies
019:        import java.util.Arrays;
020:        import java.util.LinkedHashMap;
021:        import java.util.LinkedHashSet;
022:        import java.util.Set;
023:        import java.util.Map;
024:        import java.util.List;
025:        import java.util.Iterator;
026:        import java.util.Collection;
027:        import java.util.Collections;
028:
029:        // Geotools dependencies
030:        import org.geotools.util.CheckedArrayList;
031:        import org.geotools.util.CheckedHashSet;
032:        import org.geotools.util.logging.Logging;
033:        import org.geotools.resources.i18n.Errors;
034:        import org.geotools.resources.i18n.ErrorKeys;
035:
036:        /**
037:         * Base class for metadata that may (or may not) be modifiable. Implementations will typically
038:         * provide {@code set*(...)} methods for each corresponding {@code get*()} method. An initially
039:         * modifiable metadata may become unmodifiable at a later stage (typically after its construction
040:         * is completed) by the call to the {@link #freeze} method.
041:         * <p>
042:         * Subclasses should follow the pattern below for every {@code get} and {@code set} methods,
043:         * with a special processing for {@linkplain Collection collections}:
044:         *
045:         * <blockquote><pre>
046:         * private Foo property;
047:         *
048:         * public Foo getProperty() {
049:         *     return property;
050:         * }
051:         *
052:         * public synchronized void setProperty(Foo newValue) {
053:         *     {@linkplain #checkWritePermission()};
054:         *     property = newValue;
055:         * }
056:         * </pre></blockquote>
057:         *
058:         * For collections (note that the call to {@link #checkWritePermission()} is implicit):
059:         *
060:         * <blockquote><pre>
061:         * private Collection&lt;Foo&gt; properties;
062:         *
063:         * public synchronized Collection&lt;Foo&gt; getProperties() {
064:         *     return properties = {@linkplain #nonNullCollection nonNullCollection}(properties, Foo.class);
065:         * }
066:         *
067:         * public synchronized void setProperties(Collection&lt;Foo&gt; newValues) {
068:         *     properties = {@linkplain #copyCollection copyCollection}(newValues, properties, Foo.class);
069:         * }
070:         * </pre></blockquote>
071:         *
072:         * @since 2.4
073:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/metadata/ModifiableMetadata.java $
074:         * @version $Id: ModifiableMetadata.java 27848 2007-11-12 13:10:32Z desruisseaux $
075:         * @author Martin Desruisseaux
076:         */
077:        public abstract class ModifiableMetadata extends AbstractMetadata
078:                implements  Cloneable {
079:            /**
080:             * A null implementation for the {@link #FREEZING} constant.
081:             */
082:            private static final class Null extends ModifiableMetadata {
083:                public MetadataStandard getStandard() {
084:                    return null;
085:                }
086:            }
087:
088:            /**
089:             * A flag used for {@link #unmodifiable} in order to specify that {@link #freeze}
090:             * is under way.
091:             */
092:            private static final ModifiableMetadata FREEZING = new Null();
093:
094:            /**
095:             * An unmodifiable copy of this metadata. Will be created only when first needed.
096:             * If {@code null}, then no unmodifiable entity is available.
097:             * If {@code this}, then this entity is itself unmodifiable.
098:             */
099:            private transient ModifiableMetadata unmodifiable;
100:
101:            /**
102:             * Constructs an initially empty metadata.
103:             */
104:            protected ModifiableMetadata() {
105:                super ();
106:            }
107:
108:            /**
109:             * Constructs a metadata entity initialized with the values from the specified metadata.
110:             * This constructor behavior is as in {@linkplain AbstractMetadata#AbstractMetadata(Object)
111:             * superclass constructor}.
112:             *
113:             * @param  source The metadata to copy values from.
114:             * @throws ClassCastException if the specified metadata don't implements the expected
115:             *         metadata interface.
116:             * @throws UnmodifiableMetadataException if this class don't define {@code set} methods
117:             *         corresponding to the {@code get} methods found in the implemented interface,
118:             *         or if this instance is not modifiable for some other reason.
119:             */
120:            protected ModifiableMetadata(final Object source)
121:                    throws ClassCastException, UnmodifiableMetadataException {
122:                super (source);
123:            }
124:
125:            /**
126:             * Returns {@code true} if this metadata is modifiable. This method returns
127:             * {@code false} if {@link #freeze()} has been invoked on this object.
128:             */
129:            //@Override
130:            public final boolean isModifiable() {
131:                return unmodifiable != this ;
132:            }
133:
134:            /**
135:             * Returns an unmodifiable copy of this metadata. Any attempt to modify an attribute of the
136:             * returned object will throw an {@link UnmodifiableMetadataException}. If this metadata is
137:             * already unmodifiable, then this method returns {@code this}.
138:             * <p>
139:             * The default implementation {@linkplain #clone() clone} this metadata and
140:             * {@linkplain #freeze() freeze} the clone before to return it.
141:             *
142:             * @return An unmodifiable copy of this metadata.
143:             */
144:            public synchronized AbstractMetadata unmodifiable() {
145:                // Reminder: 'unmodifiable' is reset to null by checkWritePermission().
146:                if (unmodifiable == null) {
147:                    final ModifiableMetadata candidate;
148:                    try {
149:                        /*
150:                         * Need a SHALLOW copy of this metadata, because some attributes
151:                         * may already be unmodifiable and we don't want to clone them.
152:                         */
153:                        candidate = (ModifiableMetadata) clone();
154:                    } catch (CloneNotSupportedException exception) {
155:                        /*
156:                         * The metadata is not cloneable for some reason left to the user
157:                         * (for example it may be backed by some external database).
158:                         * Assumes that the metadata is unmodifiable.
159:                         */
160:                        Logging.unexpectedException(LOGGER, exception);
161:                        return this ;
162:                    }
163:                    candidate.freeze();
164:                    // Set the field only after success. The 'unmodifiable' field must
165:                    // stay null if an exception occured during clone() or freeze().
166:                    unmodifiable = candidate;
167:                }
168:                assert !unmodifiable.isModifiable();
169:                return unmodifiable;
170:            }
171:
172:            /**
173:             * Returns an unmodifiable copy of the specified object. This method performs the
174:             * following heuristic tests:
175:             * <p>
176:             * <ul>
177:             *   <li>If the specified object is an instance of {@code ModifiableMetadata},
178:             *       then {@link #unmodifiable()} is invoked on this object.</li>
179:             *   <li>Otherwise, if the object is a {@linkplain Collection collection}, then the
180:             *       content is copied into a new collection of similar type, with values replaced
181:             *       by their unmodifiable variant.</li>
182:             *   <li>Otherwise, if the object implements the {@link org.opengis.util.Cloneable}
183:             *       interface, then a clone is returned.</li>
184:             *   <li>Otherwise, the object is assumed immutable and returned unchanged.</li>
185:             * </ul>
186:             *
187:             * @param  object The object to convert in an immutable one.
188:             * @return A presumed immutable view of the specified object.
189:             */
190:            static Object unmodifiable(final Object object) {
191:                /*
192:                 * CASE 1 - The object is an implementation of ModifiableMetadata. It may have
193:                 *          its own algorithm for creating an unmodifiable view of metadata.
194:                 */
195:                if (object instanceof  ModifiableMetadata) {
196:                    return ((ModifiableMetadata) object).unmodifiable();
197:                }
198:                /*
199:                 * CASE 2 - The object is a collection. All elements are replaced by their
200:                 *          unmodifiable variant and stored in a new collection of similar
201:                 *          type.
202:                 */
203:                if (object instanceof  Collection) {
204:                    final Collection collection = (Collection) object;
205:                    if (collection.isEmpty()) {
206:                        return (collection instanceof  List) ? (Collection) Collections.EMPTY_LIST
207:                                : (Collection) Collections.EMPTY_SET;
208:                    }
209:                    final Object[] array = collection.toArray();
210:                    for (int i = 0; i < array.length; i++) {
211:                        array[i] = unmodifiable(array[i]);
212:                    }
213:                    // Uses standard Java collections rather than Geotools Checked* classes,
214:                    // since we don't need anymore synchronization or type checking.
215:                    final List asList = Arrays.asList(array);
216:                    if (collection instanceof  Set) {
217:                        return Collections.unmodifiableSet(new LinkedHashSet(
218:                                asList));
219:                    } else {
220:                        // Conservatively assumes a List if we are not sure to have a Set,
221:                        // since the list is less destructive (no removal of duplicated).
222:                        return Collections.unmodifiableList(asList);
223:                    }
224:                }
225:                /*
226:                 * CASE 3 - The object is a map. Copies all entries in a new map and replaces all values
227:                 *          by their unmodifiable variant. The keys are assumed already immutable.
228:                 */
229:                if (object instanceof  Map) {
230:                    Map map = (Map) object;
231:                    if (map.isEmpty()) {
232:                        return Collections.EMPTY_MAP;
233:                    }
234:                    map = new LinkedHashMap(map);
235:                    for (final Iterator it = map.entrySet().iterator(); it
236:                            .hasNext();) {
237:                        final Map.Entry entry = (Map.Entry) it.next();
238:                        entry.setValue(unmodifiable(entry.getValue()));
239:                    }
240:                    return Collections.unmodifiableMap(map);
241:                }
242:                /*
243:                 * CASE 4 - The object is cloneable.
244:                 */
245:                if (object instanceof  org.opengis.util.Cloneable) {
246:                    return ((org.opengis.util.Cloneable) object).clone();
247:                }
248:                /*
249:                 * CASE 5 - Any other case. The object is assumed immutable and returned unchanged.
250:                 */
251:                return object;
252:            }
253:
254:            /**
255:             * Declares this metadata and all its attributes as unmodifiable. This method is invoked
256:             * automatically by the {@link #unmodifiable()} method. Subclasses usually don't need to
257:             * override it since the default implementation performs its work using Java reflection.
258:             */
259:            public synchronized void freeze() {
260:                ModifiableMetadata success = null;
261:                try {
262:                    unmodifiable = FREEZING;
263:                    getStandard().freeze(this );
264:                    success = this ;
265:                } finally {
266:                    unmodifiable = success;
267:                }
268:            }
269:
270:            /**
271:             * Checks if changes in the metadata are allowed. All {@code setFoo(...)} methods in
272:             * subclasses should invoke this method (directly or indirectly) before to apply any
273:             * change.
274:             *
275:             * @throws UnmodifiableMetadataException if this metadata is unmodifiable.
276:             */
277:            protected void checkWritePermission()
278:                    throws UnmodifiableMetadataException {
279:                assert Thread.holdsLock(this );
280:                if (!isModifiable()) {
281:                    throw new UnmodifiableMetadataException(Errors
282:                            .format(ErrorKeys.UNMODIFIABLE_METADATA));
283:                }
284:                invalidate();
285:            }
286:
287:            /**
288:             * Invoked when the metadata changed. Some cached informations will need
289:             * to be recomputed.
290:             */
291:            //@Override
292:            final void invalidate() {
293:                super .invalidate();
294:                unmodifiable = null;
295:            }
296:
297:            /**
298:             * Tests if the specified collection is modifiable. This method should
299:             * be used for assertions only since it destroy the collection content
300:             * in case of assertion failure.
301:             */
302:            private static boolean isModifiable(final Collection collection) {
303:                if (!collection.isEmpty())
304:                    try {
305:                        collection.clear();
306:                        return true;
307:                    } catch (UnsupportedOperationException e) {
308:                        // This is the expected exception.
309:                    }
310:                return false;
311:            }
312:
313:            /**
314:             * Copies the content of one collection ({@code source}) into an other ({@code target}).
315:             * If the target collection is {@code null}, or if its type ({@link List} vs {@link Set})
316:             * doesn't matches the type of the source collection, a new target collection is expected.
317:             * <p>
318:             * A call to {@link #checkWritePermission} is implicit before the copy is performed.
319:             *
320:             * @param  source      The source collection. {@code null} is synonymous to empty. 
321:             * @param  target      The target collection, or {@code null} if not yet created.
322:             * @param  elementType The base type of elements to put in the collection.
323:             * @return {@code target}, or a newly created collection.
324:             * @throws UnmodifiableMetadataException if this metadata is unmodifiable.
325:             */
326:            protected final Collection copyCollection(final Collection source,
327:                    Collection target, final Class elementType)
328:                    throws UnmodifiableMetadataException {
329:                if (unmodifiable == FREEZING) {
330:                    /*
331:                     * freeze() method is under progress. The source collection is already
332:                     * an unmodifiable instance created by unmodifiable(Object).
333:                     */
334:                    assert !isModifiable(source);
335:                    return source;
336:                }
337:                checkWritePermission();
338:                if (source == null) {
339:                    if (target != null) {
340:                        target.clear();
341:                    }
342:                } else {
343:                    final boolean isList = (source instanceof  List);
344:                    if (target != null && (target instanceof  List) == isList) {
345:                        target.clear();
346:                    } else {
347:                        int capacity = source.size();
348:                        if (isList) {
349:                            target = new CheckedArrayList(elementType, capacity);
350:                        } else {
351:                            capacity = Math.round(capacity / 0.75f) + 1;
352:                            target = new CheckedHashSet(elementType, capacity);
353:                        }
354:                    }
355:                    target.addAll(source);
356:                }
357:                return target;
358:            }
359:
360:            /**
361:             * Returns the specified collection, or a new one if {@code c} is null.
362:             * This is a convenience method for implementation of {@code getFoo()}
363:             * methods.
364:             *
365:             * @param  c The collection to checks.
366:             * @param  elementType The element type (used only if {@code c} is null).
367:             * @return {@code c}, or a new collection if {@code c} is null.
368:             */
369:            protected final Collection nonNullCollection(final Collection c,
370:                    final Class elementType) {
371:                assert Thread.holdsLock(this );
372:                if (c != null) {
373:                    return c;
374:                }
375:                if (isModifiable()) {
376:                    return new CheckedHashSet(elementType);
377:                }
378:                return Collections.EMPTY_SET;
379:            }
380:
381:            /**
382:             * Returns the specified list, or a new one if {@code c} is null.
383:             * This is a convenience method for implementation of {@code getFoo()}
384:             * methods.
385:             *
386:             * @param  c The list to checks.
387:             * @param  elementType The element type (used only if {@code c} is null).
388:             * @return {@code c}, or a new list if {@code c} is null.
389:             */
390:            protected final List nonNullList(final List c,
391:                    final Class elementType) {
392:                assert Thread.holdsLock(this );
393:                if (c != null) {
394:                    return c;
395:                }
396:                if (isModifiable()) {
397:                    return new CheckedArrayList(elementType);
398:                }
399:                return Collections.EMPTY_LIST;
400:            }
401:
402:            /**
403:             * Returns a shallow copy of this metadata.
404:             * <P>
405:             * While {@linkplain Cloneable cloneable}, this class do not provides the {@code clone()}
406:             * operation as part of the public API. The clone operation is required for the internal
407:             * working of the {@link #unmodifiable()} method, which expect from {@code clone()} a
408:             * <strong>shallow</strong> copy of this metadata entity. The default implementation of
409:             * {@link Object#clone()} is suffisient for most use.
410:             *
411:             * @return A <strong>shallow</strong> copy of this metadata.
412:             * @throws CloneNotSupportedException if the clone is not supported.
413:             */
414:            protected Object clone() throws CloneNotSupportedException {
415:                return super.clone();
416:            }
417:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.