1 /*
2 * The TM4J Software License
3 *
4 *
5 * Copyright (c) 2000, 2001, 2002 The TM4J Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by
22 * The TM4J Project (http://sourceforge.net/projects/tm4j)
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
25 *
26 * 4. The names "TM4J" and "The TM4J Project" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact kal@techquila.com.
30 *
31 * 5. Products derived from this software may not be called "TM4J",
32 * nor may "TM4J" appear in their name, without prior written
33 * permission of the TM4J Project.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE TM4J PROJECT OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 */
50
51 /*
52 * $Header: /cvsroot/tm4j/tm4j/examples/src/examples/basic/ParseTopicMap.java,v 1.2 2003/01/06 21:30:27 kal_ahmed Exp $
53 */
54
55 package examples.basic;
56
57 import org.tm4j.topicmap;
58 import org.tm4j.net.Locator;
59 import org.tm4j.topicmap.utils.TopicMapBuilder;
60 import org.tm4j.topicmap.utils.XTMBuilder;
61 import org.tm4j.topicmap.utils.LTMBuilder;
62
63 import java.util;
64 import java.net.URL;
65 import java.net.MalformedURLException;
66
67 import java.io.File;
68 import java.io.FileNotFoundException;
69 import java.io.InputStream;
70 import java.io.FileInputStream;
71
72 /**
73 * Example command-line application which loads a topic map into a topic map provider
74 * and then prints out the topics that it contains.
75 *
76 * This example shows:
77 * 1) How different back-ends can be used without changing the source code
78 * 2) How to parse an XTM or LTM file from the local file system or from a URL
79 * 3) How to create an XTM 'consistent' topic map.
80 *
81 * This application can be invoked as follows:
82 * java [-Dbackend_option=value] examples.basic.ParseTopicMap <i>input_address</i> [<i>backend_class_name</i>]
83 *
84 * where:
85 * <ul>
86 * <li><i>backend_option</i> is any back-end configuration option that is supported by the back-end and <i>value</i> is the value for that option (note, this may be repeated any number of times).</li>
87 * <li><i>input_address</i> is either a file name or a URL for the topic map to be read. An address ending in '.txt' or '.ltm' will be parsed as an LTM file. An address ending in any other characters will be parsed as an XTM file.</li>
88 * <li><i>backend_class_name</i> is the full Java class name of the TopicMapProviderFactory implementation to be used to connect to the back-end. The default value is <code>org.tm4j.topicmap.memory.TopicMapProviderFactoryImpl</code>.</li>
89 * </ul>
90 */
91
92 public class ParseTopicMap
93 {
94 private URL m_inputURL;
95 private File m_inputFile;
96 private TopicMapProviderFactory m_providerFactory;
97 private TopicMapProvider m_provider;
98 private boolean m_isLTM = false;
99
100 public static void main(String []args)
101 {
102 if (args.length < 1)
103 {
104 usage();
105 }
106
107 Properties backendProps = System.getProperties();
108 String inputAddress = args[0];
109 String backendClassName = "org.tm4j.topicmap.memory.TopicMapProviderFactoryImpl";
110
111 if (args.length > 1)
112 {
113 backendClassName = args[1];
114 }
115
116 try
117 {
118 ParseTopicMap theApp = new ParseTopicMap(inputAddress, backendClassName, backendProps);
119 theApp.run();
120 }
121 catch(Exception ex)
122 {
123 ex.printStackTrace();
124 System.out.println("Error encountered: " + ex.toString());
125 System.out.println("Stack trace follows...");
126 System.out.flush();
127 ex.printStackTrace();
128 }
129 }
130
131 public static void usage()
132 {
133 System.out.println("Usage: java examples.basic.ParseTopicMap input_address [backend_class_name]");
134 System.out.println(" where: ");
135 System.out.println(" input_address = either the file name or the URL for the topic map to be parsed.");
136 System.out.println(" backend_class_name = the full Java class name of the TopicMapProviderFactory implementation to be used to create a connection to the back-end.");
137 System.out.println("Any configuration properties needed to make the back-end connection should be passed to the JVM by using -Doption=value parameters.");
138 }
139
140 /**
141 * Constructor for the application which validates the input parameters
142 * and creates a connection to the back-end to be used for parsing the topic map.
143 */
144 public ParseTopicMap(String inputAddress, String backendClassName, Properties backendProps)
145 throws Exception
146 {
147 // Assume that the input file is LTM if the file extension is .txt or .ltm
148 String ext = inputAddress.substring(inputAddress.length() - 4);
149 if (ext.equalsIgnoreCase(".ltm") || ext.equalsIgnoreCase(".txt"))
150 {
151 m_isLTM = true;
152 }
153
154 // Extract either a URL or a local File object from the input address
155 // This code first attempts to parse the address as a URL and if that fails,
156 // falls back on trying to open the specified location as a local file (which
157 // must exist).
158 try
159 {
160 m_inputURL = new URL(inputAddress);
161 }
162 catch(java.net.MalformedURLException ex)
163 {
164 m_inputFile = new File(inputAddress);
165 if (!m_inputFile.exists())
166 {
167 throw new FileNotFoundException("Could not locate the specified input file. It is either an invalid URL or an invalid file name.");
168 }
169 }
170
171 // Create the specified TopicMapProviderFactory instance which will be used
172 // to store the topic map we later parse.
173 // Note, this pattern can be used in your applications wherever you would like
174 // the user to be able to specify the back-end that your application will use.
175 try
176 {
177 Class backendClass = Class.forName(backendClassName);
178 m_providerFactory = (TopicMapProviderFactory)backendClass.newInstance();
179 }
180 catch(ClassCastException ex)
181 {
182 throw new IllegalArgumentException("Specified backend class does not implement the org.tm4j.topicmap.TopicMapProviderFactory interface.");
183 }
184
185 // Create the connection to the back-end:
186 m_provider = m_providerFactory.createTopicMapProvider(backendProps);
187 }
188
189 /**
190 * The main application processing
191 */
192 public void run()
193 throws Exception
194 {
195 TopicMapBuilder builder = new org.tm4j.topicmap.utils.XTMBuilder();
196 if (m_isLTM) {
197 builder = new org.tm4j.topicmap.utils.LTMBuilder();
198 } else {
199 builder = new org.tm4j.topicmap.utils.XTMBuilder();
200 }
201
202 // Create the "base" URI of the topic map
203 String baseURI = getInputURI();
204 Locator baseLocator = m_provider.getLocatorFactory().createLocator("URI", baseURI);
205
206 // Get the input stream to be read
207 InputStream input = getInputStream();
208
209 // Parse the topic map
210 System.out.println("Parsing topic map: " + baseLocator.getAddress() + " as " +
211 (m_isLTM ? "LTM" : "XTM"));
212 TopicMap tm = m_provider.addTopicMap(input, baseLocator, null, builder);
213 System.out.println("Base topic map loaded!");
214
215 resolveExternalReferences(tm);
216
217 dumpTopics(tm);
218 }
219
220 /**
221 * Returns the URI address string of the input to be parsed.
222 * If the input source is a URL, then the URL address is returned.
223 * If the input source is a File, then the file location is converted to a URL and
224 * that address string is returned.
225 */
226 private String getInputURI()
227 throws Exception
228 {
229 if (m_inputFile != null)
230 {
231 return m_inputFile.toURL().toString();
232 }
233 else
234 {
235 return m_inputURL.toString();
236 }
237 }
238
239 /**
240 * Returns the source topic map to be parsed as a Java InputStream.
241 * For a File source, this will be a FileInputStream, for URL sources,
242 * this will be the input stream retrived from the URLConnection.
243 */
244 private InputStream getInputStream()
245 throws Exception
246 {
247 if (m_inputFile != null)
248 {
249 return new FileInputStream(m_inputFile);
250 }
251 else
252 {
253 return m_inputURL.openStream();
254 }
255 }
256
257 /**
258 * Attempts to load all of the topic maps which are referenced from <code>tm</code>
259 * and merge them into <code>tm</code>.
260 * @param tm the TopicMap for which external references are to be resolved. This TopicMap will be modified in place by the merging of the externally referenced topic maps.
261 */
262 private void resolveExternalReferences(TopicMap tm)
263 throws Exception
264 {
265 // First merge in those topic maps referenced from mergeMap elements.
266 while (!tm.getMergeMapLocators().isEmpty())
267 {
268 Locator mmLoc = (Locator)tm.getMergeMapLocators().iterator().next();
269
270 // Each mergeMap may have some "added themes" which need to be passed
271 // to the provider as it merges in the topic map.
272 Scope mmAddThemes = tm.getMergeMapAddedThemes(mmLoc);
273
274 System.out.println("Merging mergeMap reference: " + mmLoc.getAddress());
275 // Do the merge. This method also removes the topic map from the
276 // mergeMapLocators property.
277 m_provider.mergeTopicMap(tm, mmLoc, mmAddThemes);
278 }
279
280 // Merge in those topic maps which contain topics referenced from
281 // topicRef elements.
282 Scope emptyScope = tm.createScope(null);
283 while(!tm.getExternalRefs().isEmpty())
284 {
285 Locator extRef = (Locator)tm.getExternalRefs().iterator().next();
286 System.out.println("Merging topic map containing topic reference(s): " + extRef.getAddress());
287 m_provider.mergeTopicMap(tm, extRef, emptyScope);
288 }
289 }
290
291 private void dumpTopics(TopicMap tm)
292 {
293 // NOTE: For some backends, getting the iterator directly
294 // may be more efficient than calling tm.getTopics().iterator() as it may
295 // avoid the overhead of constructing a large Collection object.
296
297 Iterator topics = tm.getTopicsIterator();
298 while(topics.hasNext())
299 {
300 dumpTopic((Topic)topics.next());
301 }
302 }
303
304 /**
305 * A simple text dump of a topic, listing its resource address;
306 * subject indicators; types and names
307 */
308 private void dumpTopic(Topic t)
309 {
310 if (t.getResourceLocator() != null)
311 {
312 System.out.println("Topic: " + t.getResourceLocator().getAddress());
313 }
314 else
315 {
316 System.out.println("Internal Topic: " + t.getID());
317 }
318
319 if (!t.getSubjectIndicators().isEmpty())
320 {
321 System.out.println(" Subject Indicators: ");
322 Iterator it = t.getSubjectIndicators().iterator();
323 while (it.hasNext())
324 {
325 Locator si = (Locator)it.next();
326 System.out.println(" " + si.getAddress());
327 }
328 }
329
330 if (!t.getTypes().isEmpty())
331 {
332 System.out.println(" Types:");
333 Iterator it = t.getTypes().iterator();
334 while (it.hasNext())
335 {
336 Topic type = (Topic)it.next();
337 System.out.println(" " + type.getResourceLocator().getAddress());
338 }
339 }
340
341 if (!t.getNames().isEmpty())
342 {
343 System.out.println(" Names:");
344 Iterator it = t.getNames().iterator();
345 while (it.hasNext())
346 {
347 BaseName bn = (BaseName)it.next();
348 System.out.println(" " + bn.getData());
349 }
350 }
351
352 System.out.println("");
353 }
354 }
355
356 /*
357 * $Log: ParseTopicMap.java,v $
358 * Revision 1.2 2003/01/06 21:30:27 kal_ahmed
359 * Removed use of deprecated method. Tidied up output when parsing topic maps.
360 *
361 * Revision 1.1 2003/01/06 17:33:06 kal_ahmed
362 * Intial version
363 *
364 */