001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2007, GeoTools Project Managment Committee (PMC)
005: * (C) 2007, Geomatys
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.referencing.factory;
018:
019: // J2SE dependencies
020: import java.io.IOException;
021: import java.io.PrintWriter;
022: import java.io.Writer;
023: import java.util.Collection;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.Set;
027:
028: // The following are just data structure, not dependencies to the whole Swing framework.
029: import javax.swing.tree.TreeNode;
030: import javax.swing.tree.MutableTreeNode;
031: import javax.swing.tree.DefaultMutableTreeNode;
032:
033: // OpenGIS dependencies
034: import org.opengis.metadata.citation.Citation;
035: import org.opengis.referencing.Factory;
036: import org.opengis.referencing.AuthorityFactory;
037: import org.opengis.referencing.crs.CRSFactory;
038: import org.opengis.referencing.crs.CRSAuthorityFactory;
039: import org.opengis.referencing.cs.CSFactory;
040: import org.opengis.referencing.cs.CSAuthorityFactory;
041: import org.opengis.referencing.datum.DatumFactory;
042: import org.opengis.referencing.datum.DatumAuthorityFactory;
043: import org.opengis.referencing.operation.CoordinateOperationAuthorityFactory;
044: import org.opengis.referencing.operation.CoordinateOperationFactory;
045:
046: // Geotools dependencies
047: import org.geotools.factory.BufferedFactory;
048: import org.geotools.factory.OptionalFactory;
049: import org.geotools.referencing.ReferencingFactoryFinder;
050: import org.geotools.resources.OptionalDependencies;
051: import org.geotools.resources.Utilities;
052: import org.geotools.resources.X364;
053:
054: /**
055: * Build a tree of factory dependencies.
056: *
057: * @since 2.4
058: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/FactoryDependencies.java $
059: * @version $Id: FactoryDependencies.java 25477 2007-05-10 13:01:00Z desruisseaux $
060: * @author Martin Desruisseaux
061: */
062: public class FactoryDependencies {
063: /**
064: * A list of interfaces that may be implemented by this class. Used for
065: * the properties printed between parenthesis by {@link #createTree()}.
066: */
067: private static final Class[] TYPES = { CRSFactory.class,
068: CRSAuthorityFactory.class, CSFactory.class,
069: CSAuthorityFactory.class, DatumFactory.class,
070: DatumAuthorityFactory.class,
071: CoordinateOperationFactory.class,
072: CoordinateOperationAuthorityFactory.class,
073: BufferedFactory.class, OptionalFactory.class, Factory.class // Processed in a special way.
074: };
075:
076: /**
077: * Labels for {@link #TYPES}.
078: */
079: private static final String[] TYPE_LABELS = { "crs", "crs", "cs",
080: "cs", "datum", "datum", "operation", "operation",
081: "buffered", "optional", "registered" };
082:
083: /**
084: * The number of elements in {@link #TYPES} which are referencing factories.
085: * They are printed in a different color than the last elements.
086: */
087: private static final int FACTORY_COUNT = TYPES.length - 3;
088:
089: /**
090: * The factory to format.
091: */
092: private final Factory factory;
093:
094: /**
095: * {@code true} for applying colors on a ANSI X3.64 (aka ECMA-48 and ISO/IEC 6429)
096: * compliant output device.
097: */
098: private boolean colorEnabled;
099:
100: /**
101: * {@code true} for printing attributes {@link #TYPE_LABELS} between parenthesis
102: * after the factory name.
103: */
104: private boolean attributes;
105:
106: /**
107: * Creates a new dependency tree for the specified factory.
108: */
109: public FactoryDependencies(final Factory factory) {
110: this .factory = factory;
111: }
112:
113: /**
114: * Returns {@code true} if syntax coloring is enabled.
115: * Syntax coloring is disabled by default.
116: */
117: public boolean isColorEnabled() {
118: return colorEnabled;
119: }
120:
121: /**
122: * Enables or disables syntax coloring on ANSI X3.64 (aka ECMA-48 and ISO/IEC 6429)
123: * compatible terminal. By default, syntax coloring is disabled.
124: */
125: public void setColorEnabled(final boolean enabled) {
126: colorEnabled = enabled;
127: }
128:
129: /**
130: * Returns {@code true} if attributes are to be printed.
131: * By default, attributes are not printed.
132: */
133: public boolean isAttributeEnabled() {
134: return attributes;
135: }
136:
137: /**
138: * Enables or disables the addition of attributes after factory names. Attributes
139: * are labels like "{@code crs}", "{@code datum}", <cite>etc.</cite> put between
140: * parenthesis. They give indications on the services implemented by the factory
141: * (e.g. {@link CRSAuthorityFactory}, {@link DatumAuthorityFactory}, <cite>etc.</cite>).
142: */
143: public void setAttributeEnabled(final boolean enabled) {
144: attributes = enabled;
145: }
146:
147: /**
148: * Prints the dependencies as a tree to the specified printer.
149: */
150: public void print(final PrintWriter out) {
151: out.print(OptionalDependencies.toString(asTree()));
152: }
153:
154: /**
155: * Prints the dependencies as a tree to the specified writer.
156: *
157: * @param out The writer where to print the tree.
158: * @throws IOException if an error occured while writting to the stream.
159: */
160: public void print(final Writer out) throws IOException {
161: out.write(OptionalDependencies.toString(asTree()));
162: }
163:
164: /**
165: * Returns the dependencies as a tree.
166: */
167: public TreeNode asTree() {
168: return createTree(factory, new HashSet());
169: }
170:
171: /**
172: * Returns the dependencies for the specified factory.
173: */
174: private MutableTreeNode createTree(final Factory factory,
175: final Set/*<Factory>*/done) {
176: final DefaultMutableTreeNode root = createNode(factory);
177: if (factory instanceof ReferencingFactory) {
178: final Collection dep = ((ReferencingFactory) factory)
179: .dependencies();
180: if (dep != null) {
181: for (final Iterator it = dep.iterator(); it.hasNext();) {
182: final Object element = it.next();
183: final MutableTreeNode child;
184: if (element instanceof Factory) {
185: final Factory candidate = (Factory) element;
186: if (!done.add(candidate)) {
187: continue;
188: }
189: child = createTree(candidate, done);
190: if (!done.remove(candidate)) {
191: throw new AssertionError(); // Should never happen.
192: }
193: } else {
194: child = OptionalDependencies
195: .createTreeNode(
196: String.valueOf(element),
197: element, false);
198: }
199: root.add(child);
200: }
201: }
202: }
203: return root;
204: }
205:
206: /**
207: * Creates a single node for the specified factory.
208: */
209: private DefaultMutableTreeNode createNode(final Factory factory) {
210: final StringBuffer buffer = new StringBuffer(Utilities
211: .getShortClassName(factory)).append('[');
212: if (factory instanceof AuthorityFactory) {
213: final Citation authority = ((AuthorityFactory) factory)
214: .getAuthority();
215: if (authority != null) {
216: final Collection identifiers = authority
217: .getIdentifiers();
218: if (identifiers != null && !identifiers.isEmpty()) {
219: boolean next = false;
220: for (final Iterator it = identifiers.iterator(); it
221: .hasNext();) {
222: if (next) {
223: buffer.append(", ");
224: }
225: appendIdentifier(buffer, (String) it.next());
226: next = true;
227: }
228: } else {
229: appendIdentifier(buffer, authority.getTitle());
230: }
231: }
232: } else {
233: if (colorEnabled)
234: buffer.append(X364.RED);
235: buffer.append("direct");
236: if (colorEnabled)
237: buffer.append(X364.DEFAULT);
238: }
239: buffer.append(']');
240: if (attributes) {
241: boolean hasFound = false;
242: for (int i = 0; i < TYPES.length; i++) {
243: final Class type = TYPES[i];
244: if (!type.isInstance(factory)) {
245: continue;
246: }
247: if (type.equals(Factory.class)) { // Special case.
248: if (!ReferencingFactoryFinder.isRegistered(factory)) {
249: continue;
250: }
251: }
252: buffer.append(hasFound ? ", " : " (");
253: if (colorEnabled) {
254: buffer.append(i < FACTORY_COUNT ? X364.GREEN
255: : X364.CYAN);
256: }
257: buffer.append(TYPE_LABELS[i]);
258: if (colorEnabled) {
259: buffer.append(X364.DEFAULT);
260: }
261: hasFound = true;
262: }
263: if (hasFound) {
264: buffer.append(')');
265: }
266: }
267: return OptionalDependencies.createTreeNode(buffer.toString(),
268: factory, true);
269: }
270:
271: /**
272: * Appends an identifier to the specified buffer.
273: */
274: private void appendIdentifier(final StringBuffer buffer,
275: final CharSequence identifier) {
276: if (colorEnabled)
277: buffer.append(X364.MAGENTA);
278: buffer.append('"').append(identifier).append('"');
279: if (colorEnabled)
280: buffer.append(X364.DEFAULT);
281: }
282: }
|