Copyright © TIBCO Software Inc. All Rights Reserved
Copyright © TIBCO Software Inc. All Rights Reserved


Appendix B Developing gXML Applications : Developing gXML Applications

Developing gXML Applications
This section illustrates one way of using gXML. All gXML processors, including custom processing, run within a GxProcessingContext instance that provides necessary meta data. A GxProcessingContext instance in turn is created through a GxApplication instance. It is your responsibility to write a class that provides an instance of GxApplication. The best way to do this is to write an abstract class that implements all but the newProcessingContext method of GxApplication. This approach will allow you to write your application generically and then inject the choice of parameterization as late as possible for maximum code reuse and flexibility.
This, of course, is not the only way to use gXML. An existing architecture may force the choice of parameterization and create silos of XML processing. The degree of integration in this case may be less that is possible with a homogeneous solution.
Whatever the approach, the best way to use gXML is to write generic, parameterized, and XML processing code whenever possible.
Implementing GxApplication
001 package org.gxml.book.common;
002
003 import java.io.StringWriter;
004 import java.net.URI;
005 import java.net.URISyntaxException;
006
007 import junit.framework.TestCase;
008
009 import org.gxml.sa.GxApplication;
010 import org.gxml.sa.GxModel;
011 import org.gxml.sa.GxNameBridge;
012 import org.gxml.sa.GxProcessingContext;
013 import org.gxml.sa.GxSequenceHandler;
014 import org.gxml.xdm.Resolver;
015
016 import com.tibco.gxml.sa.api.common.util.PreCondition;
017 import com.tibco.gxml.sa.processor.serialization.api.GxSerializerFactory;
018 import com.tibco.gxml.sa.processor.serialization.impl.SerializerFactory;
019
020 public abstract class SampleApp<I, U, N extends I, A extends I, S, T, X> extends TestCase implements GxApplication<I, U, N, A, S, T, X>
021 {
022 public Resolver getResolver()
023 {
024 try
025 {
026 return new SampleResolver(new URI("../../plugins/org.gxml.book/resources/foo.xml"));
027 }
028 catch (final URISyntaxException e)
029 {
030 throw new AssertionError(e);
031 }
032 }
033
034 protected String serialize(final N node, final GxProcessingContext<I, U, N, A, S, T, X> pcx)
035 {
036 final GxSerializerFactory<I, U, N, A, S, T, X> sf = new SerializerFactory<I, U, N, A, S, T, X>(pcx);
037
038 // Configure for "pretty" printing.
039 sf.setIndent(Boolean.TRUE);
040
041 final StringWriter w = new StringWriter();
042
043 final GxSequenceHandler<A, S, T> handler = sf.newSerializer(w);
044
045 final GxModel<N, A, S, T> model = pcx.getModel();
046
047 handler.startDocument(null);
048 try
049 {
050 model.stream(node, true, true, handler);
051 }
052 finally
053 {
054 handler.endDocument();
055 }
056
057 return w.toString();
058 }
059
060 /**
061 * Some bridge implementations may use {@link String} directly for symbols. They must make them behave according to
062 * symbol semantics (==,toString).
063 */
064 public void assertNodeSymbolSemantics(final N node, final GxProcessingContext<I, U, N, A, S, T, X> pcx)
065 {
066 final GxModel<N, A, S, T> model = pcx.getModel();
067 final GxNameBridge<S> nameBridge = pcx.getNameBridge();
068
069 switch (model.getNodeKind(node))
070 {
071 case ELEMENT:
072 {
073 assertSymbolSemantics(model.getNamespaceURI(node), nameBridge);
074 assertSymbolSemantics(model.getLocalName(node), nameBridge);
075 }
076 case TEXT:
077 case DOCUMENT:
078 {
079
080 }
081 break;
082 default:
083 {
084 throw new AssertionError(model.getNodeKind(node));
085 }
086 }
087 }
088
089 public void assertSymbolSemantics(final S symbol, final GxNameBridge<S> nameBridge)
090 {
091 PreCondition.assertArgumentNotNull(symbol, "symbol");
092 PreCondition.assertArgumentNotNull(nameBridge, "nameBridge");
093 assertSame(symbol, nameBridge.symbolize(symbol.toString()));
094 assertSame(symbol, nameBridge.symbolize(copy(symbol.toString())));
095 }
096
097 /**
098 * Do anything to manufacture a String that is equal, but not identical (the same), as the original.
099 * <p>
100 * This method has the post-condition that the strings are equal but not the same.
101 * </p>
102 *
103 * @param original
104 * The original.
105 * @return A copy of the original string.
106 */
107 private String copy(final String original)
108 {
109 final String copy = original.concat("junk").substring(0, original.length());
110 // Post-conditions verify that this actually works and isn't "optimized" out.'
111 assertEquals(original, copy);
112 assertNotSame(original, copy);
113 // Be Paranoid
114 assertTrue(original.equals(copy));
115 assertFalse(original == copy);
116 // OK. That'll do.'
117 return copy;
118 }
119 }
Implementing GxCatalog
A catalog provides the means to isolate your application from the physical location of file resources. Writing a catalog simply means implementing the GxCatalog interface, so that it maps from the logical locations specified in code or XML resources to the corresponding physical location.
001 package org.gxml.book.common;
002
003 public class SampleCatalog
004 {
005
006 }
Implementing GxResolver
A resolver takes a base-uri and an href and uses these two values to return a stream.
001 package org.gxml.book.common;
002
003 import java.io.File;
004 import java.io.FileNotFoundException;
005 import java.io.IOException;
006 import java.io.InputStream;
007 import java.net.URI;
008 import java.net.URISyntaxException;
009 import java.net.URL;
010
011 import org.gxml.xdm.Resolved;
012 import org.gxml.xdm.Resolver;
013
014 import com.tibco.gxml.sa.api.common.util.PreCondition;
015
016 public final class SampleResolver implements Resolver
017 {
018 final URI baseURI;
019
020 public SampleResolver(final URI baseURI)
021 {
022 this.baseURI = PreCondition.assertArgumentNotNull(baseURI, "baseURI");
023 }
024
025 /**
026 * Convert a URI relative to a base URI into an input source.
027 * <p/>
028 * This default implementation requires that neither parameter be null, and performs the expected action to retrieve
029 * the input source (which may involve network access).
030 *
031 * @param baseURI
032 * the base URI against which the target is to be resolved; must not be null
033 * @param location
034 * the URI to resolve; must not be null
035 * @return a pair of InputStream and resolved URI.
036 */
037 public Resolved<InputStream> resolveInputStream(final URI location) throws IOException
038 {
039 PreCondition.assertArgumentNotNull(location, "uri");
040 if (location.isAbsolute())
041 {
042 return retrieve(location, location);
043 }
044 else
045 {
046 PreCondition.assertArgumentNotNull(baseURI, "baseURI");
047
048 final URI base = baseURI.normalize();
049 final URI resolved = base.resolve(location);
050
051 return retrieve(location, resolved);
052 }
053 }
054
055 private Resolved<InputStream> retrieve(final URI location, final URI uri) throws IOException
056 {
057 PreCondition.assertArgumentNotNull(uri, "uri");
058
059 final URL toRetrieve;
060
061 if (!uri.isAbsolute()) // assume local file
062 {
063 final File canonFile = new File(uri.toString()).getCanonicalFile();
064 toRetrieve = canonFile.toURI().toURL();
065 }
066 else
067 {
068 toRetrieve = uri.toURL();
069 }
070
071 if (toRetrieve == null)
072 {
073 throw new FileNotFoundException(uri.toString());
074 }
075
076 final InputStream stream = toRetrieve.openStream();
077 if (stream == null)
078 {
079 throw new FileNotFoundException(toRetrieve.toString());
080 }
081 try
082 {
083 return new Resolved<InputStream>(location, stream, toRetrieve.toURI());
084 }
085 catch (final URISyntaxException e)
086 {
087 throw new AssertionError(e);
088 }
089 }
090 }
 
Injecting DOM
The final task in providing a concrete GxApplication class is to implement the newProcessingContext method on a derived class. This is where you get to choose the tree, atomic values, meta data and symbols that your application will use. In many cases, you will use an off-the-shelf processing context class, but it is also possible to assemble your own variety or build one entirely from scratch.
If you are going to use gXML with org.w3c.dom.Node, you still have choices for the atomic values that your system will use as well as the meta data implementation. This example uses atomic values that are mostly Java Wrapper types and the reference sequence type implementation, SmSequenceType.
 
001 package org.gxml.book.parsing;
002
003 import org.gxml.sa.GxMetaBridge;
004 import org.gxml.sa.GxNameBridge;
005 import org.gxml.sa.mutable.GxApplicationMutable;
006 import org.gxml.sa.mutable.GxProcessingContextMutable;
007 import org.gxml.xs.SmMetaBridge;
008 import org.gxml.xs.SmSequenceType;
009 import org.w3c.dom.Node;
010
011 import com.tibco.gxml.sa.api.common.datatype.StringNameBridge;
012 import com.tibco.gxml.sa.common.atom.AtomBridge;
013 import com.tibco.gxml.sa.common.helpers.GxMetaBridgeOnSmMetaBridgeAdapter;
014 import com.tibco.gxml.sa.common.helpers.SmAtomBridgeOnGxAtomBridgeAdapter;
015 import com.tibco.gxml.sa.xdm.dom.DomProcessingContext;
016 import com.tibco.gxml.xs.SmMetaBridgeFactory;
017
018 /**
019 * Demonstration of constructing a concrete GxApplication(Mutable) implementation using the DOM processing context.
020 */
021 public final class DomValidatingParsingSample extends BookValidatingParsingSample<Object, Object, Node, Object, String, SmSequenceType<Object, String>, Object> implements GxApplicationMutable<Object, Object, Node, Object, String, SmSequenceType<Object, String>, Object>
022 {
023 public final GxProcessingContextMutable<Object, Object, Node, Object, String, SmSequenceType<Object, String>, Object> newProcessingContext()
024 {
025 // The name bridge is created along with the processing context for maximum concurrency.
026 final GxNameBridge<String> nameBridge = new StringNameBridge();
027 final AtomBridge<String> atomBridge = new AtomBridge<String>(nameBridge);
028 final SmMetaBridge<Object, String> cache = new SmMetaBridgeFactory<Object, String>(new SmAtomBridgeOnGxAtomBridgeAdapter<Object, String>(atomBridge)).newMetaBridge();
029 final GxMetaBridge<Object, String, SmSequenceType<Object, String>> metaBridge = new GxMetaBridgeOnSmMetaBridgeAdapter<Object, String>(cache, atomBridge);
030
031 final DomProcessingContext<Object, SmSequenceType<Object, String>> pcx = new DomProcessingContext<Object, SmSequenceType<Object, String>>(this, metaBridge, cache);
032
033 // Set the "owning" processing context on the atom bridge.
034 atomBridge.setProcessingContext(pcx);
035
036 // Return the newly constructed processing context.
037 return pcx;
038 }
039 }

Copyright © TIBCO Software Inc. All Rights Reserved
Copyright © TIBCO Software Inc. All Rights Reserved