/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
package net.ontopia.topicmaps.cmdlineutils.rdbms;
import java.io.File;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import java.util.Properties;
import org.xml.sax.InputSource;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.core.TopicMapImporterIF;
import net.ontopia.topicmaps.impl.rdbms.RDBMSTopicMapStore;
import net.ontopia.topicmaps.impl.rdbms.TopicMap;
import net.ontopia.topicmaps.utils.DuplicateSuppressionUtils;
import net.ontopia.topicmaps.utils.ImportExportUtils;
import net.ontopia.topicmaps.xml.XTMTopicMapReader;
import net.ontopia.utils.CmdlineOptions;
import net.ontopia.utils.CmdlineUtils;
import net.ontopia.utils.PropertyUtils;
import net.ontopia.xml.AbstractXMLFormatReader;
/**
* PUBLIC: Command line utility for importing topic map files into a
* relational database system. Topic map files can either be imported
* into an existing topic map or imported as separated topic maps in
* the database.
*
* <p>Run the class with no arguments to see how to use it.
*/
public class RDBMSImport {
public static void main(String[] argv) throws Exception {
// initialize logging
CmdlineUtils.initializeLogging();
// register logging options
CmdlineOptions options = new CmdlineOptions("RDBMSImport", argv);
OptionsListener ohandler = new OptionsListener();
CmdlineUtils.registerLoggingOptions(options);
options.addLong(ohandler, "tmid", 'i', true);
options.addLong(ohandler, "title", 't', true);
options.addLong(ohandler, "comments", 'c', true);
options.addLong(ohandler, "validate", 'v', true);
options.addLong(ohandler, "suppress", 's', true);
options.addLong(ohandler, "loadExternal", 'e', true);
options.addLong(ohandler, "validate", 'v', true);
options.addLong(ohandler, "jdbcspy", 'j', true);
options.addLong(ohandler, "progress", 'p', true);
// parse command line options
try {
options.parse();
} catch (CmdlineOptions.OptionsException e) {
System.err.println("Error: " + e.getMessage());
System.exit(1);
}
// get command line arguments
String[] args = options.getArguments();
if (args.length < 2) {
usage();
System.exit(3);
}
// load properties file
Properties props = PropertyUtils.loadProperties(new File(args[0]));
// override shared cache property
props.put("net.ontopia.topicmaps.impl.rdbms.Cache.shared", "false");
RDBMSTopicMapStore store = new RDBMSTopicMapStore(PropertyUtils.toMap(props), ohandler.topicMapId);
TopicMapIF tm = store.getTopicMap();
// set topic map title
if (ohandler.topicMapTitle != null)
((TopicMap)tm).setTitle(ohandler.topicMapTitle);
// set topic map comments
if (ohandler.topicMapComments != null)
((TopicMap)tm).setComments(ohandler.topicMapComments);
for (int i=1; i < args.length; i++) {
String filename = args[i];
TopicMapImporterIF importer = ImportExportUtils.getImporter(filename);
// disable XTM validation
if (importer instanceof XTMTopicMapReader && !ohandler.validate)
((XTMTopicMapReader)importer).setValidation(false);
// disable following external topicRefs
if (importer instanceof XTMTopicMapReader && !ohandler.loadExternal)
((XTMTopicMapReader)importer).setFollowTopicRefs(false);
System.out.println("Importing " + filename + " into " + tm.getObjectId());
long start = System.currentTimeMillis();
if (ohandler.progress) {
// user has asked for a progress report, so we do all this
// complicated stuff to make it happen. the basic idea is that
// we create the input stream ourselves, instead of letting
// the parser do it, and use a subclass of FileIS which outputs
// status reports as the parser reads from it.
File file = new File(filename);
if (importer instanceof AbstractXMLFormatReader &&
file.exists()) {
FileInputStream fis = new WrappedFileInputStream(file);
InputSource src = ((AbstractXMLFormatReader) importer).getInputSource();
src.setByteStream(fis);
} else
System.out.println("Cannot produce progress report!");
}
importer.importInto(tm);
if (ohandler.suppress)
DuplicateSuppressionUtils.removeDuplicates(tm);
store.commit();
long end = System.currentTimeMillis();
System.out.println("Done. " + (end - start) + " ms.");
}
if (ohandler.jdbcspyFile != null) {
try {
Class<?> spyDriverClass = Class.forName("net.ontopia.persistence.jdbcspy.SpyDriver");
Method method = spyDriverClass.getMethod("writeReport", String.class);
method.invoke(null, ohandler.jdbcspyFile);
} catch (ClassNotFoundException cnfe) {
System.out.println("JDBC-Spy driver was not found on the classpath, make sure you have the"
+ " ontopia-jdbcspy jar of the correct java version on your classpath");
}
}
// close store (and database connection)
store.close();
}
private static void usage() {
System.out.println("java net.ontopia.topicmaps.cmdlineutils.rdbms.RDBMSImport [options] <dbprops> <tmfile1> [<tmfile2>] ...");
System.out.println("");
System.out.println(" Imports topic map files into a topic map in a database.");
System.out.println("");
System.out.println(" Options:");
CmdlineUtils.printLoggingOptionsUsage(System.out);
System.out.println(" --tmid=<topic map id> : existing TM to import into (creates new TM by default)");
System.out.println(" --title=<topic map title> : persistent name of topic map");
System.out.println(" --comments=<topic map comments> : persistent comments about topic map");
System.out.println(" --validate=true|false : if true topic map document will be validated (default: true)");
System.out.println(" --suppress=true|false: suppress duplicate characteristics (default: false)");
System.out.println(" --loadExternal=true|false : if true external topic references will be resolved (default: true)");
System.out.println(" --jdbcspy=<filename> : write jdbcspy report to the given file");
System.out.println(" --progress=true|false: write progress report while importing (default: false)");
System.out.println("");
System.out.println(" <dbprops>: the database configuration file");
System.out.println(" <tmfile#>: the topic map files to import");
System.out.println("");
}
private static class OptionsListener implements CmdlineOptions.ListenerIF {
long topicMapId = -1;
boolean validate = true;
boolean suppress = false;
boolean loadExternal = true;
String jdbcspyFile;
String topicMapTitle;
String topicMapComments;
boolean progress;
public void processOption(char option, String value) {
if (option == 'i') topicMapId = ImportExportUtils.getTopicMapId(value);
if (option == 'v') validate = Boolean.valueOf(value).booleanValue();
if (option == 'e') loadExternal = Boolean.valueOf(value).booleanValue();
if (option == 's') suppress = Boolean.valueOf(value).booleanValue();
if (option == 'j') jdbcspyFile = value;
if (option == 't') topicMapTitle = value;
if (option == 'c') topicMapComments = value;
if (option == 'p') progress = Boolean.valueOf(value).booleanValue();
}
}
private static class WrappedFileInputStream extends FileInputStream {
private long filesize;
private int prevperc;
private FileChannel fc;
private boolean hasComplained;
private WrappedFileInputStream(File file) throws FileNotFoundException {
super(file);
this.filesize = file.length();
this.prevperc = -1;
this.fc = getChannel();
}
public int read() throws IOException {
int res = super.read();
status();
return res;
}
public int read(byte[] b) throws IOException {
int res = super.read(b);
status();
return res;
}
public int read(byte[] b, int off, int len) throws IOException {
int res = super.read(b, off, len);
status();
return res;
}
public long skip(long n) throws IOException {
long res = super.skip(n);
status();
return res;
}
private void status() {
try {
int perc = (int) (((float) fc.position() / (float) filesize) * 100.0);
if (perc != prevperc) {
System.out.println("" + perc + "%");
prevperc = perc;
}
} catch (IOException e) {
if (!hasComplained) {
e.printStackTrace();
hasComplained = true;
}
}
}
}
}