
jena.schemagen Maven / Gradle / Ivy
Show all versions of jena Show documentation
/*****************************************************************************
* Source code information
* -----------------------
* Original author Ian Dickinson, HP Labs Bristol
* Author email [email protected]
* Package Jena 2
* Web http://sourceforge.net/projects/jena/
* Created 14-Apr-2003
* Filename $RCSfile: schemagen.java,v $
* Revision $Revision: 1.13 $
* Release status $State: Exp $
*
* Last modified on $Date: 2010/06/11 00:08:07 $
* by $Author: ian_dickinson $
*
* (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
* (see footer for full conditions)
*****************************************************************************/
// Package
///////////////
package jena;
// Imports
///////////////
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.apache.xerces.util.XMLChar;
import org.slf4j.LoggerFactory;
import com.hp.hpl.jena.ontology.*;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.shared.JenaException;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.util.iterator.*;
import com.hp.hpl.jena.vocabulary.*;
/**
*
* A vocabulary generator, that will consume an ontology or other vocabulary file,
* and generate a Java file with the constants from the vocabulary compiled in.
* Designed to be highly flexible and customisable.
*
*
* @author Ian Dickinson
* (email)
* @version CVS $Id: schemagen.java,v 1.13 2010/06/11 00:08:07 ian_dickinson Exp $
*/
public class schemagen {
// Constants
//////////////////////////////////
/** The namespace for the configuration model is {@value} */
public static final String NS = "http://jena.hpl.hp.com/2003/04/schemagen#";
/** The default location of the configuration model is {@value} */
public static final String DEFAULT_CONFIG_URI = "file:schemagen.rdf";
/** The default marker string for denoting substitutions is {@value} */
public static final String DEFAULT_MARKER = "%";
/** Default template for writing out value declarations */
public static final String DEFAULT_TEMPLATE = "public static final %valclass% %valname% = m_model.%valcreator%( \"%valuri%\" );";
/** Default template for writing out individual declarations */
public static final String DEFAULT_INDIVIDUAL_TEMPLATE = "public static final %valclass% %valname% = m_model.%valcreator%( \"%valuri%\", %valtype% );";
/** Default template for writing out individual declarations for non-ontology vocabularies */
public static final String DEFAULT_RDFS_INDIVIDUAL_TEMPLATE = "public static final %valclass% %valname% = m_model.%valcreator%( \"%valuri%\" );";
/** Default template for the file header */
public static final String DEFAULT_HEADER_TEMPLATE = "/* CVS $" + "Id: $ */%nl%%package% %nl%%imports% %nl%/**%nl% * Vocabulary definitions from %sourceURI% %nl% * @author Auto-generated by schemagen on %date% %nl% */";
/** Default line length for comments before wrap */
public static final int COMMENT_LENGTH_LIMIT = 80;
/** List of Java reserved keywords, see this list. */
public static final String[] JAVA_KEYWORDS = {
"abstract", "continue", "for", "new", "switch",
"assert", "default", "goto", "package", "synchronized",
"boolean", "do", "if", "private", "this",
"break", "double", "implements", "protected", "throw",
"byte", "else", "import", "public", "throws",
"case", "enum", "instanceof", "return", "transient",
"catch", "extends", "int", "short", "try",
"char", "final", "interface", "static", "void",
"class", "finally", "long", "strictfp", "volatile",
"const", "float", "native", "super", "while"
};
// Static variables
//////////////////////////////////
private static List KEYWORD_LIST;
static {
KEYWORD_LIST = Arrays.asList( JAVA_KEYWORDS );
}
// Instance variables
//////////////////////////////////
/** Schemagen options interface */
protected SchemagenOptions m_options;
/** The model that contains the input source */
protected OntModel m_source;
/** The output stream we write to */
protected PrintStream m_output;
/** Option definitions */
/** Stack of replacements to apply */
protected List m_replacements = new ArrayList();
/** Output file newline char - default is Unix, override with --dos */
protected String m_nl = "\n";
/** Size of indent step */
protected int m_indentStep = 4;
/** Set of names used so far */
protected Set m_usedNames = new HashSet();
/** Map from resources to java names */
protected Map m_resourcesToNames = new HashMap();
/** List of allowed namespace URI strings for admissible values */
protected List m_includeURI = new ArrayList();
// Constructors
//////////////////////////////////
// External signature methods
//////////////////////////////////
/* Main entry point. See Javadoc for details of the many command line arguments */
public static void main( String[] args ) {
try {
new schemagen().go( args );
}
catch (SchemagenException e) {
System.err.println( "Schemagen failed to run:" );
System.err.println( e.getMessage() );
if (e.getCause() != null) {
System.err.println( "Caused by: " + e.getCause().getMessage() );
}
System.exit( 1 );
}
}
// Internal implementation methods
//////////////////////////////////
/** Read the configuration parameters and do setup */
protected void go( String[] args ) {
go( new SchemagenOptionsImpl( args ) );
}
/** Handle initial configuration options, then initiate processing */
protected void go( SchemagenOptions options ) {
m_options = options;
// check for user requesting help
if (m_options.hasHelpOption()) {
usage();
}
// got the configuration, now we can begin processing
processInput();
}
/** The sequence of steps to process an entire file */
protected void processInput() {
addIncludes();
determineLanguage();
selectInput();
selectOutput();
setGlobalReplacements();
processHeader();
writeClassDeclaration();
writeInitialDeclarations();
writeProperties();
writeClasses();
writeIndividuals();
writeClassClose();
processFooter();
closeOutput();
}
/** Add the included files */
protected void addIncludes() {
// add any extra uri's that are allowed in the filter
m_includeURI.addAll( m_options.getIncludeOption() );
}
/** Create the source model after determining which input language */
protected void determineLanguage() {
OntModelSpec s = null;
if (m_options.hasLangDamlOption()) {
// DAML language specified
if (m_options.hasUseInfOption()) {
s = OntModelSpec.DAML_MEM_RULE_INF;
}
else {
s = OntModelSpec.DAML_MEM;
}
}
else if (m_options.hasLangRdfsOption()) {
// RDFS language specified
if (m_options.hasUseInfOption()) {
s = OntModelSpec.RDFS_MEM_RDFS_INF;
}
else {
s = OntModelSpec.RDFS_MEM;
}
}
else {
// owl is the default
// s = OntModelSpec.getDefaultSpec( ProfileRegistry.OWL_LANG );
if (m_options.hasUseInfOption()) {
s = OntModelSpec.OWL_MEM_RULE_INF;
}
else {
s = OntModelSpec.OWL_MEM;
}
}
m_source = ModelFactory.createOntologyModel( s, null );
m_source.getDocumentManager().setProcessImports( false );
// turn off strict checking on request
if (m_options.hasNoStrictOption()) {
m_source.setStrictMode( false );
}
}
/** Identify the URL that is to be read in and translated to a vocabulary file, and load the source into the source model */
protected void selectInput() {
if (!m_options.hasInputOption()) {
usage();
}
String input = SchemagenUtils.urlCheck( m_options.getInputOption().getURI() );
String syntax = m_options.getEncodingOption();
try {
FileManager.get().readModel( m_source, input, syntax );
}
catch (JenaException e) {
abort( "Failed to read input source " + input, e );
}
}
/** Identify the file we are to write the output to */
protected void selectOutput() {
String outFile = m_options.getOutputOption();
if (outFile == null) {
m_output = System.out;
}
else {
try {
// check for package name
String packageName = m_options.getPackagenameOption();
if (packageName != null) {
String packagePath = "";
// build the package path (e.g. com.foo.bar -> /com/foo/bar)
for (String p: packageName.split( "\\." )) {
packagePath = packagePath + File.separator + p;
}
if (!outFile.endsWith( packagePath )) {
outFile = outFile + packagePath;
}
}
File out = new File( outFile );
if (!out.exists() && !outFile.endsWith( ".java" )) {
// create the directory if needed
out.mkdirs();
}
if (out.isDirectory()) {
// create a file in this directory named classname.java
String fileName = outFile + File.separator + getClassName() + ".java";
out = new File( fileName );
}
m_output = new PrintStream( new FileOutputStream( out ) );
}
catch (Exception e) {
abort( "I/O error while trying to open file for writing: " + outFile, e );
}
}
// check for DOS line endings
if (m_options.hasDosOption()) {
m_nl = "\r\n";
}
}
/** Process the header at the start of the file, if defined */
protected void processHeader() {
String header = m_options.hasHeaderOption() ? m_options.getHeaderOption() : DEFAULT_HEADER_TEMPLATE;
// user can turn of header processing, default is to have it on
if (!m_options.hasNoheaderOption()) {
writeln( 0, substitute( header ) );
}
else {
// we have to do the imports at least
writeln( 0, "import com.hp.hpl.jena.rdf.model.*;" );
if (m_options.hasOntologyOption()) {
writeln( 0, "import com.hp.hpl.jena.ontology.*;" );
}
if (m_options.hasIncludeSourceOption()) {
writeln( 0, "import java.io.ByteArrayInputStream;" );
}
}
}
/** Process the footer at the end of the file, if defined */
protected void processFooter() {
String footer = m_options.getFooterOption();
if (footer != null) {
writeln( 0, substitute( footer ) );
}
}
/** The list of replacements that are always available */
protected void setGlobalReplacements() {
addReplacementPattern( "date", new SimpleDateFormat( "dd MMM yyyy HH:mm").format( new Date() ) );
addReplacementPattern( "package", m_options.hasPackagenameOption() ? ("package " + m_options.getPackagenameOption() + ";") : "" );
addReplacementPattern( "imports", getImports() );
addReplacementPattern( "classname", getClassName() );
addReplacementPattern( "nl", m_nl );
// protect \ in Windows file pathnames
// looks for file:.* or C:.* (or variants thereof)
String source = m_options.getInputOption().getURI();
if (source.matches( "(file:|[A-Za-z]:).*$" )) {
source = source.replace( "\\", "\\\\" );
}
addReplacementPattern( "sourceURI", source );
}
/** Add a pattern-value pair to the list of available patterns */
protected void addReplacementPattern( String key, String replacement ) {
if (replacement != null && key != null) {
String marker = m_options.getMarkerOption();
marker = (marker == null) ? DEFAULT_MARKER : marker;
try {
m_replacements.add( new Replacement( Pattern.compile( marker + key + marker ),
replacement ) );
}
catch (PatternSyntaxException e) {
abort( "Malformed regexp pattern " + marker + key + marker, e );
}
}
}
/** Pop n replacements off the stack */
protected void pop( int n ) {
for (int i = 0; i < n; i++) {
m_replacements.remove( m_replacements.size() - 1 );
}
}
/** Close the output file */
protected void closeOutput() {
m_output.flush();
m_output.close();
}
/** Abort due to exception */
protected void abort( String msg, Exception cause ) {
throw new SchemagenException( msg, cause );
}
/** Print usage message and abort */
protected void usage() {
System.err.println( "Usage:" );
System.err.println( " java jena.schemagen [options ...]" );
System.err.println();
System.err.println( "Commonly used options include:" );
System.err.println( " -i the source document as a file or URL." );
System.err.println( " -n the name of the created Java class." );
System.err.println( " -a the namespace URI of the source document." );
System.err.println( " -o the file to write the generated class into." );
System.err.println( " -o the directory in which the generated Java class is created." );
System.err.println( " By default, output goes to stdout." );
System.err.println( " -e the encoding of the input document (N3, RDF/XML, etc)." );
System.err.println( " -c a filename or URL for an RDF document containing " );
System.err.println( " configuration parameters." );
System.err.println();
System.err.println( "Many other options are available. See the schemagen HOWTO in the " );
System.err.println( "Jena documentation for full details." );
System.exit( 1 );
}
/** Use the current replacements list to do the subs in the given string */
protected String substitute( String sIn ) {
String s = sIn;
for (Iterator i = m_replacements.iterator(); i.hasNext(); ) {
Replacement r = i.next();
s = r.pattern.matcher( s ).replaceAll( r.sub );
}
return s;
}
/** Add the appropriate indent to a buffer */
protected int indentTo( int i, StringBuffer buf ) {
int indent = i * m_indentStep;
for (int j = 0; j < indent; j++) {
buf.append( ' ' );
}
return indent;
}
/** Write a blank line, with indent and newline */
protected void writeln( int indent ) {
writeln( indent, "" );
}
/** Write out the given string with n spaces of indent, with newline */
protected void writeln( int indent, String s ) {
write( indent, s );
m_output.print( m_nl );
}
/** Write out the given string with n spaces of indent */
protected void write( int indentLevel, String s ) {
for (int i = 0; i < (m_indentStep * indentLevel); i++) {
m_output.print( " " );
}
m_output.print( s );
}
/** Determine the list of imports to include in the file */
protected String getImports() {
StringBuffer buf = new StringBuffer();
buf.append( "import com.hp.hpl.jena.rdf.model.*;" );
buf.append( m_nl );
if (useOntology()) {
buf.append( "import com.hp.hpl.jena.ontology.*;" );
buf.append( m_nl );
}
if (includeSource()) {
buf.append( "import java.io.ByteArrayInputStream;" );
buf.append( m_nl );
}
return buf.toString();
}
/** Determine the class name of the vocabulary from the URI */
protected String getClassName() {
// if a class name is given, just use that
if (m_options.hasClassnameOption()) {
return m_options.getClassnameOption();
}
// otherwise, we generate a name based on the URI
String uri = m_options.getInputOption().getURI();
// remove any suffixes
uri = (uri.endsWith( "#" )) ? uri.substring( 0, uri.length() - 1 ) : uri;
uri = (uri.endsWith( ".daml" )) ? uri.substring( 0, uri.length() - 5 ) : uri;
uri = (uri.endsWith( ".owl" )) ? uri.substring( 0, uri.length() - 4 ) : uri;
uri = (uri.endsWith( ".rdf" )) ? uri.substring( 0, uri.length() - 4 ) : uri;
uri = (uri.endsWith( ".rdfs" )) ? uri.substring( 0, uri.length() - 5 ) : uri;
uri = (uri.endsWith( ".n3" )) ? uri.substring( 0, uri.length() - 3 ) : uri;
uri = (uri.endsWith( ".xml" )) ? uri.substring( 0, uri.length() - 4 ) : uri;
uri = (uri.endsWith( ".ttl" )) ? uri.substring( 0, uri.length() - 4 ) : uri;
// now work back to the first non name character from the end
int i = uri.length() - 1;
for (; i > 0; i--) {
if (!Character.isUnicodeIdentifierPart( uri.charAt( i ) ) &&
uri.charAt( i ) != '-') {
i++;
break;
}
}
String name = uri.substring( i );
// optionally add name suffix
if (m_options.hasClassnameSuffixOption()) {
name = name + m_options.getClassnameSuffixOption();
}
// now we make the name into a legal Java identifier
return asLegalJavaID( name, true );
}
/** Answer true if we are using ontology terms in this vocabulary */
protected boolean useOntology() {
return m_options.hasOntologyOption();
}
/** Answer true if all comments are suppressed */
protected boolean noComments() {
return m_options.hasNoCommentsOption();
}
/** Answer true if ontology source code is to be included */
protected boolean includeSource() {
return m_options.hasIncludeSourceOption();
}
/** Convert s to a legal Java identifier; capitalise first char if cap is true */
protected String asLegalJavaID( String s, boolean cap ) {
StringBuffer buf = new StringBuffer();
int i = 0;
// treat the first character specially - must be able to start a Java ID, may have to up-case
try {
for (; !Character.isJavaIdentifierStart( s.charAt( i )); i++) { /**/ }
}
catch (StringIndexOutOfBoundsException e) {
System.err.println( "Could not identify legal Java identifier start character in '" + s + "', replacing with __" );
return "__";
}
buf.append( cap ? Character.toUpperCase( s.charAt( i ) ) : s.charAt( i ) );
// copy the remaining characters - replace non-legal chars with '_'
for (++i; i < s.length(); i++) {
char c = s.charAt( i );
buf.append( Character.isJavaIdentifierPart( c ) ? c : '_' );
}
// check for illegal keyword
if (KEYWORD_LIST.contains( buf.toString() )) {
buf.append( '_' );
}
return buf.toString();
}
/** The opening class declaration */
protected void writeClassDeclaration() {
write( 0, "public class " );
write( 0, getClassName() );
write( 0, " " );
if (m_options.hasClassdecOption()) {
write( 0, m_options.getClassdecOption() );
}
writeln( 0, "{" );
}
/** The close of the class decoration */
protected void writeClassClose() {
writeln( 0, "}" );
}
/** Write the declarations at the head of the class */
protected void writeInitialDeclarations() {
writeModelDeclaration();
writeSource();
writeNamespace();
if (m_options.hasDeclarationsOption()) {
writeln( 0, m_options.getDeclarationsOption() );
}
}
/** Write the declaration of the model */
protected void writeModelDeclaration() {
if (useOntology()) {
String lang = "OWL";
if (m_options.hasLangDamlOption()) {
lang = "DAML";
}
else if (m_options.hasLangRdfsOption()) {
lang = "RDFS";
}
writeln( 1, "/** The ontology model that holds the vocabulary terms
*/" );
writeln( 1, "private static OntModel m_model = ModelFactory.createOntologyModel( OntModelSpec." + lang + "_MEM, null );" );
}
else {
writeln( 1, "/** The RDF model that holds the vocabulary terms
*/" );
writeln( 1, "private static Model m_model = ModelFactory.createDefaultModel();" );
}
writeln( 1 );
}
/** Write the source code of the input model into the file itself */
protected void writeSource() {
if (includeSource()) {
// first save a copy of the source in compact form into a buffer
ByteArrayOutputStream bos = new ByteArrayOutputStream();
m_source.write( bos, "N3" );
String output = bos.toString();
// now we embed each line of the source in the output
writeln( 1, "private static final String SOURCE = " );
boolean first = true;
StringTokenizer st = new StringTokenizer( output, "\n" );
while (st.hasMoreTokens()) {
String tok = st.nextToken();
if (tok.endsWith( "\r" )) {
tok = tok.substring( 0, tok.length() - 1 );
}
write( 2, first ? " " : " + " );
write( 0, "\"" );
write( 0, protectQuotes( tok ) );
writeln( 2, "\\n\"" );
first = false;
}
// then we reference the string constant when reading the source
// note that we avoid StringReader due to charset encoding issues
writeln( 1, ";" );
writeln( 0, "" );
writeln( 1, "/** Read the ontology definition into the source model */ " );
writeln( 1, "static { " );
writeln( 2, "m_model.read( new ByteArrayInputStream( SOURCE.getBytes() ), null, \"N3\" );" );
writeln( 1, "}" );
writeln( 0, "" );
}
}
/** Protect any double quotes in the given string so that it's a legal Java String */
private String protectQuotes( String s ) {
int nDquote = 0;
for (int i = 0; i < s.length(); i++ ) {
if (s.charAt( i ) == '"' ) {
nDquote++;
}
}
if (nDquote == 2) {
// need to protect the begin and end quote chars
return s.replaceAll( "\"", "\\\\\"" );
}
else if (nDquote > 2) {
// embedded quote chars in the string
// N3 convention is to use triple-quote blocks
int qStart = s.indexOf( '"' );
int qEnd = s.lastIndexOf( '"' );
StringBuffer s0 = new StringBuffer( s.length() );
for (int i = 0; i < s.length(); i++ ) {
char c = s.charAt( i );
if (c == '"' ) {
// protect embedded " characters, treating the outer pair differently
// than any inner quotes
if (i == qStart || i == qEnd) {
s0.append( "\\\"\\\"\\\"" );
}
else {
s0.append( "\\\"" );
}
}
else if (c == '\\' ) {
// protect embedded \ characters
s0.append( "\\\\" );
}
else {
s0.append( c );
}
}
return s0.toString();
}
else {
return s;
}
}
/** Write the string and resource that represent the namespace */
protected void writeNamespace() {
String nsURI = determineNamespaceURI();
writeln( 1, "/** The namespace of the vocabulary as a string
*/" );
writeln( 1, "public static final String NS = \"" + nsURI + "\";" );
writeln( 1 );
writeln( 1, "/** The namespace of the vocabulary as a string
" );
writeln( 1, " * @see #NS */" );
writeln( 1, "public static String getURI() {return NS;}" );
writeln( 1 );
writeln( 1, "/** The namespace of the vocabulary as a resource
*/" );
writeln( 1, "public static final Resource NAMESPACE = m_model.createResource( NS );" );
writeln( 1 );
}
/** Determine what the namespace URI for this vocabulary is */
protected String determineNamespaceURI() {
// we have a sequence of strategies for determining the ontology namespace
String ns = getOptionNamespace();
if (ns == null) {
ns = getDefaultPrefixNamespace();
}
if (ns == null) {
ns = getOntologyElementNamespace();
}
if (ns == null) {
ns = guessNamespace();
}
// did we get one?
if (ns == null) {
abort( "Could not determine the base URI for the input vocabulary", null );
}
m_includeURI.add( ns );
return ns;
}
/** User has set namespace via a schemagen option */
protected String getOptionNamespace() {
return m_options.hasNamespaceOption() ? m_options.getNamespaceOption().getURI() : null;
}
/** Document has set an empty prefix for the model */
protected String getDefaultPrefixNamespace() {
// alternatively, the default namespace may be set in the prefix mapping read from the input document
String defaultNS = m_source.getNsPrefixURI( "" );
if (defaultNS == null) {
defaultNS = m_source.getBaseModel().getNsPrefixURI( "" );
}
return defaultNS;
}
/** Document has an owl:Ontology or daml:Ontology element */
protected String getOntologyElementNamespace() {
// if we are using an ontology model, we can get the namespace URI from the ontology element
String uri = null;
StmtIterator i = m_source.getBaseModel()
.listStatements( null, RDF.type, m_source.getProfile().ONTOLOGY() );
if (i.hasNext()) {
Resource ont = i.nextStatement().getSubject();
uri = ont.getURI();
// ensure ends with namespace separator char
char ch = uri.charAt( uri.length() - 1 );
boolean endsWithNCNameCh = XMLChar.isNCName( ch );
uri = endsWithNCNameCh ? uri + "#" : uri;
// check for ambiguous answers
if (i.hasNext()) {
System.err.println( "Warning: ambiguous default namespace - there is more than one owl:Ontology element." );
System.err.println( "Picking first choice: " + uri + ". Other choices are:" );
while (i.hasNext()) {
System.err.print( " " );
System.err.print( i.nextStatement().getString() );
}
System.err.println();
System.err.println( "Use the -a option to specify a particular namespace if required." );
}
}
return uri;
}
/** Guess the URI from the most prevalent URI */
protected String guessNamespace() {
Map nsCount = new HashMap();
// count all of the namespaces used in the model
for (StmtIterator i = m_source.listStatements(); i.hasNext(); ) {
Statement s = i.next();
countNamespace( s.getSubject(), nsCount );
countNamespace( s.getPredicate(), nsCount );
if (s.getObject().isResource()) {
countNamespace( s.getResource(), nsCount );
}
}
// now find the maximal element
String ns = null;
int max = 0;
for (Iterator i = nsCount.keySet().iterator(); i.hasNext(); ) {
String nsKey = i.next();
// we ignore the usual suspects
if (! (OWL.getURI().equals( nsKey ) ||
RDF.getURI().equals( nsKey ) ||
RDFS.getURI().equals( nsKey ) ||
XSD.getURI().equals( nsKey ))) {
// not an ignorable namespace
int count = nsCount.get( nsKey ).intValue();
if (count > max) {
// highest count seen so far
max = count;
ns = nsKey;
}
}
}
return ns;
}
/** Record a use of the given namespace in the count map */
private void countNamespace( Resource r, Map nsCount ) {
if (!r.isAnon()) {
String ns = r.getNameSpace();
// increment the count for this namespace
Integer count = nsCount.containsKey( ns ) ? (Integer) nsCount.get( ns ) : new Integer( 0 );
Integer count1 = new Integer( count.intValue() + 1 );
nsCount.put( ns, count1 );
}
}
/** Write the list of properties */
protected void writeProperties() {
if (m_options.hasNopropertiesOption()) {
return;
}
if (m_options.hasPropertySectionOption()) {
writeln( 0, m_options.getPropertySectionOption());
}
if (useOntology()) {
writeObjectProperties();
writeDatatypeProperties();
writeAnnotationProperties();
// we also write out the RDF properties, to mop up any props that are not stated as
// object, datatype or annotation properties
writeRDFProperties( true );
}
else {
writeRDFProperties( false );
}
}
/** Write any object properties in the vocabulary */
protected void writeObjectProperties() {
String template = m_options.hasPropTemplateOption() ? m_options.getPropTemplateOption() : DEFAULT_TEMPLATE;
if (!m_options.hasLangRdfsOption()) {
for (Iterator extends RDFNode> i = sorted( m_source.listObjectProperties() ); i.hasNext(); ) {
writeValue( (Resource) i.next(), template, "ObjectProperty", "createObjectProperty", "_PROP" );
}
}
}
/** Write any datatype properties in the vocabulary */
protected void writeDatatypeProperties() {
String template = m_options.hasPropTemplateOption() ? m_options.getPropTemplateOption() : DEFAULT_TEMPLATE;
if (!m_options.hasLangRdfsOption()) {
for (Iterator extends RDFNode> i = sorted( m_source.listDatatypeProperties() ); i.hasNext(); ) {
writeValue( (Resource) i.next(), template, "DatatypeProperty", "createDatatypeProperty", "_PROP" );
}
}
}
/** Write any annotation properties in the vocabulary */
protected void writeAnnotationProperties() {
String template = m_options.hasPropTemplateOption() ? m_options.getPropTemplateOption() : DEFAULT_TEMPLATE;
if (!m_options.hasLangRdfsOption()) {
for (Iterator extends RDFNode> i = sorted( m_source.listAnnotationProperties() ); i.hasNext(); ) {
writeValue( (Resource) i.next(), template, "AnnotationProperty", "createAnnotationProperty", "_PROP" );
}
}
}
/** Write any vanilla RDF properties in the vocabulary */
protected void writeRDFProperties( boolean useOntProperty ) {
String template = m_options.hasPropTemplateOption() ? m_options.getPropTemplateOption() : DEFAULT_TEMPLATE;
String propType = useOntProperty ? "OntProperty" : "Property";
// select the appropriate properties based on the language choice
Resource[] props;
if (m_options.hasLangOwlOption()) {
props = new Resource[] {OWL.ObjectProperty, OWL.DatatypeProperty, RDF.Property};
}
else if (m_options.hasLangDamlOption()) {
props = new Resource[] {DAML_OIL.ObjectProperty, DAML_OIL.DatatypeProperty, RDF.Property};
}
else {
props = new Resource[] {RDF.Property};
}
// collect the properties to be written
List propertyResources = new ArrayList();
for (int j = 0; j < props.length; j++) {
for (StmtIterator i = m_source.listStatements( null, RDF.type, props[j] ); i.hasNext(); ) {
propertyResources.add( i.nextStatement().getSubject() );
}
}
// now write the properties
for (Iterator extends RDFNode> i = sorted( propertyResources ); i.hasNext(); ) {
writeValue( (Resource) i.next(), template, propType, "create" + propType, "_PROP" );
}
}
/** Write any classes in the vocabulary */
protected void writeClasses() {
if (m_options.hasNoclassesOption()) {
return;
}
if (m_options.hasClassSectionOption()) {
writeln( 0, m_options.getClassSectionOption());
}
if (useOntology()) {
writeOntClasses();
}
else {
writeRDFClasses();
}
}
/** Write classes as ontology terms */
protected void writeOntClasses() {
String template = m_options.hasClassTemplateOption() ? m_options.getClassTemplateOption() : DEFAULT_TEMPLATE;
for (Iterator extends RDFNode> i = sorted( m_source.listClasses() ); i.hasNext(); ) {
writeValue( (Resource) i.next(), template, "OntClass", "createClass", "_CLASS" );
}
}
/** Write classes as vanilla RDF terms */
protected void writeRDFClasses() {
String template = m_options.hasClassTemplateOption() ? m_options.getClassTemplateOption() : DEFAULT_TEMPLATE;
// make sure we're looking for the appropriate type of class
Resource cls = OWL.Class;
if (m_options.hasLangDamlOption()) {
cls = DAML_OIL.Class;
}
else if (m_options.hasLangRdfsOption()) {
cls = RDFS.Class;
}
// collect the classes to list
List classes = m_source.listStatements( null, RDF.type, cls ).mapWith( new Map1() {
public Resource map1( Statement s ) {
return s.getSubject();
}}
).toList();
for (Iterator extends RDFNode> i = sorted( classes ); i.hasNext(); ) {
writeValue( (Resource) i.next(), template, "Resource", "createResource", "_CLASS" );
}
}
/** Write any instances (individuals) in the vocabulary */
protected void writeIndividuals() {
if (m_options.hasNoindividualsOption()) {
return;
}
if (m_options.hasIndividualsSectionOption()) {
writeln( 0, m_options.getIndividualsSectionOption() );
}
if (useOntology()) {
writeOntIndividuals();
}
else {
writeRDFIndividuals();
}
}
/** Write individuals as ontology terms */
protected void writeOntIndividuals() {
String template = m_options.hasIndividualTemplateOption() ? m_options.getIndividualTemplateOption() : DEFAULT_INDIVIDUAL_TEMPLATE;
for (Iterator extends RDFNode> i = selectIndividuals(); i.hasNext(); ) {
Individual ind = ((Resource) i.next()).as( Individual.class );
// do we have a local class resource
Resource cls = ind.getOntClass();
if (cls == null) { cls = OWL.Thing; }
String varName = m_resourcesToNames.get( cls );
String valType = (varName != null) ? varName : "m_model.createClass( \"" + cls.getURI() + "\" )";
// push the individuals type onto the stack
addReplacementPattern( "valtype", valType );
writeValue( ind, template, "Individual", "createIndividual", "_INSTANCE" );
pop( 1 );
}
}
/** Write individuals as vanilla RDF terms */
protected void writeRDFIndividuals() {
String template = m_options.hasIndividualTemplateOption() ? m_options.getIndividualTemplateOption() : DEFAULT_RDFS_INDIVIDUAL_TEMPLATE;
for (Iterator extends RDFNode> i = selectIndividuals(); i.hasNext(); ) {
writeValue( (Resource) i.next(), template, "Resource", "createResource", "_INSTANCE" );
}
}
/** Answer an iterator over the individuals selected for output */
protected ExtendedIterator extends RDFNode> selectIndividuals() {
List candidates = new ArrayList();
for (StmtIterator i = m_source.listStatements( null, RDF.type, (RDFNode) null ); i.hasNext(); ) {
Statement candidate = i.nextStatement();
if (candidate.getObject().isResource()) {
Resource candObj = candidate.getResource();
Resource candSubj = candidate.getSubject();
// ignore RDFS and OWL builtins
if (!candObj.isAnon()) {
String candTypeURI = candObj.getURI();
if (candTypeURI.startsWith( RDF.getURI() ) ||
candTypeURI.startsWith( OWL.getURI() ) ||
candTypeURI.startsWith( RDFS.getURI() )) {
continue;
}
}
// note that whether candSubj is included is tested later on by {@link #filter}
if (!candSubj.isAnon() && (isIncluded( candObj ) || isIncluded( candSubj )) && !candidates.contains( candSubj )) {
candidates.add( candSubj );
}
}
}
return sorted( candidates );
}
/**
* Answer true if the given resource is accepted for presentation in the output, which
* is true iff it is a URI node, whose namespace is one of the accepted namespaces in
* {@link #m_includeURI}.
* @param r A resource to test
* @return True if the resource is to be included in the generated output
*/
protected boolean isIncluded( Resource r ) {
boolean accepted = false;
if (!r.isAnon()) {
String uri = r.getURI();
for (Iterator j = m_includeURI.iterator(); !accepted && j.hasNext(); ) {
accepted = uri.startsWith( j.next() );
}
}
return accepted;
}
/** Write the value declaration out using the given template, optionally creating comments */
protected void writeValue( Resource r, String template, String valueClass, String creator, String disambiguator ) {
if (!filter( r )) {
if (!noComments() && hasComment( r )) {
writeln( 1, formatComment( getComment( r ) ) );
}
// push the local bindings for the substitution onto the stack
addReplacementPattern( "valuri", r.getURI() );
addReplacementPattern( "valname", getValueName( r, disambiguator ));
addReplacementPattern( "valclass", valueClass );
addReplacementPattern( "valcreator", creator );
// write out the value
writeln( 1, substitute( template ) );
writeln( 1 );
// pop the local replacements off the stack
pop( 4 );
}
}
/** Answer true if the given resource has an rdf:comment or daml:comment */
protected boolean hasComment( Resource r ) {
return r.hasProperty( RDFS.comment ) || r.hasProperty( DAML_OIL.comment );
}
/** Answer all of the commentary on the given resource, as a string */
protected String getComment( Resource r ) {
StringBuffer comment = new StringBuffer();
// collect any RDFS or DAML comments attached to the node
for (NodeIterator ni = m_source.listObjectsOfProperty( r, RDFS.comment ); ni.hasNext(); ) {
RDFNode n = ni.nextNode();
if (n instanceof Literal) {
comment.append( ((Literal) n).getLexicalForm().trim() );
}
else {
LoggerFactory.getLogger( getClass() ).debug( "Not a literal: " + n );
}
}
for (NodeIterator ni = m_source.listObjectsOfProperty( r, DAML_OIL.comment ); ni.hasNext(); ) {
comment.append( ((Literal) ni.nextNode()).getLexicalForm().trim() );
}
return comment.toString();
}
/** Format the comment as Javadoc, and limit the line width */
protected String formatComment( String comment ) {
StringBuffer buf = new StringBuffer();
buf.append( "/** " );
boolean inSpace = false;
int pos = buf.length();
boolean singleLine = true;
// now format the comment by compacting whitespace and limiting the line length
// add the prefix to the start of each line
for (int i = 0; i < comment.length(); i++ ) {
char c = comment.charAt( i );
// compress whitespace
if (Character.isWhitespace( c )) {
if (inSpace) {
continue; // more than one space is ignored
}
else {
c = ' '; // map all whitespace to 0x20
inSpace = true;
}
}
else {
inSpace = false;
}
// escapes?
if (c == '\\') {
c = comment.charAt( ++i );
switch (c) {
case 'n':
buf.append( m_nl );
pos = indentTo( 1, buf );
buf.append( " * " );
pos += 3;
singleLine = false;
break;
default:
// add other escape sequences above
break;
}
}
else if (c == '<') {
buf.append( "<" );
pos += 4;
}
else if (c == '>') {
buf.append( ">" );
pos += 4;
}
else if (c == '&') {
buf.append( "&" );
pos += 5;
}
else {
// add the char
buf.append( c );
pos++;
}
// wrap any very long lines at 120 chars
if ((pos > COMMENT_LENGTH_LIMIT) && (inSpace)) {
buf.append( m_nl );
pos = indentTo( 1, buf );
buf.append( " * " );
pos += 3;
singleLine = false;
}
}
buf.append( "
" );
buf.append( singleLine ? "" : m_nl );
indentTo( singleLine ? 0 : 1, buf );
buf.append( " */" );
return buf.toString();
}
/** Answer true if resource r does not show in output */
protected boolean filter( Resource r ) {
if (r.isAnon()) {
return true;
}
// if we've already processed this resource once, ignore it next time
if (m_resourcesToNames.containsKey( r )) {
return true;
}
// search the allowed URI's
for (Iterator i = m_includeURI.iterator(); i.hasNext(); ) {
String uri = i.next();
if (r.getURI().startsWith( uri )) {
// in
return false;
}
}
// we allow individuals whose class is not in the included NS's, unless opt strict-individuals is true */
if (!m_options.hasStrictIndividualsOption()) {
for (StmtIterator j = r.listProperties( RDF.type ); j.hasNext(); ) {
// we search the rdf:types of this resource
Resource typeRes = j.nextStatement().getResource();
if (!typeRes.isAnon()) {
String typeURI = typeRes.getURI();
// for any type that is in a permitted NS
for (Iterator i = m_includeURI.iterator(); i.hasNext(); ) {
String uri = i.next();
if (typeURI.startsWith( uri )) {
// in
return false;
}
}
}
}
}
// default is out
return true;
}
/** Answer the Java value name for the URI */
protected String getValueName( Resource r, String disambiguator ) {
// the id name is basically the local name of the resource, possibly in upper case
String name = m_options.hasUcNamesOption() ? getUCValueName( r ) : r.getLocalName();
// must be legal java
name = asLegalJavaID( name, false );
// must not clash with an existing name
int attempt = 0;
String baseName = name;
while (m_usedNames.contains( name )) {
name = (attempt == 0) ? (name + disambiguator) : (baseName + disambiguator + attempt);
attempt++;
}
// record this name so that we don't use it again (which will stop the vocabulary from compiling)
m_usedNames.add( name );
// record the mapping from resource to name
m_resourcesToNames.put( r, name );
return name;
}
/** Answer the local name of resource r mapped to upper case */
protected String getUCValueName( Resource r ) {
StringBuffer buf = new StringBuffer();
String localName = r.getLocalName();
char lastChar = 0;
for (int i = 0; i < localName.length(); i++) {
char c = localName.charAt(i);
if (Character.isLowerCase(lastChar) && Character.isUpperCase(c)) {
buf.append( '_' );
}
buf.append( Character.toUpperCase(c) );
lastChar = c;
}
return buf.toString();
}
/** Answer an iterator that contains the elements of the given list, but sorted by URI */
protected ExtendedIterator extends RDFNode> sorted( ExtendedIterator extends RDFNode> i ) {
return sorted( i.toList() );
}
/** Answer an iterator that contains the elements of the given iterator, but sorted by URI */
protected ExtendedIterator extends RDFNode> sorted( List extends RDFNode> members ) {
Collections.sort( members, new Comparator() {
public int compare( RDFNode n0, RDFNode n1 ) {
if (n0.isLiteral() || n1.isLiteral()) {
if (n0.isLiteral() && n1.isLiteral()) {
// two literals
Literal l0 = (Literal) n0;
Literal l1 = (Literal) n1;
return l0.getLexicalForm().compareTo( l1.getLexicalForm() );
}
else {
return n0.isLiteral() ? -1 : 1;
}
}
else {
Resource r0 = (Resource) n0;
Resource r1 = (Resource) n1;
if (r0.isAnon() && r1.isAnon()) {
// two anonID's - the order is important as long as its consistent
return r0.getId().toString().compareTo( r1.getId().toString() );
}
else if (r0.isAnon()) {
return -1;
}
else if (r1.isAnon()) {
return 1;
}
else {
// two named resources
return r0.getURI().compareTo( r1.getURI() );
}
}
}} );
return WrappedIterator.create( members.iterator() );
}
//==============================================================================
// Inner class definitions
//==============================================================================
public interface SchemagenOptions {
/* Constants for the various options we can set */
public enum OPT {
/** Select an alternative config file; use -c <filename>
on command line */
CONFIG_FILE,
/** Turn off all comment output; use --nocomments
on command line; use sgen:noComments
in config file */
NO_COMMENTS,
/** Nominate the URL of the input document; use -i <URL>
on command line; use sgen:input
in config file */
INPUT,
/** Specify that the language of the source is DAML+OIL; use --daml
on command line; use sgen:daml
in config file */
LANG_DAML,
/** Specify that the language of the source is OWL (the default); use --owl
on command line; use sgen:owl
in config file */
LANG_OWL,
/** Specify that the language of the source is RDFS; use --rdfs
on command line; use sgen:rdfs
in config file */
LANG_RDFS,
/** Specify that destination file; use -o <fileName>
on command line; use sgen:output
in config file */
OUTPUT,
/** Specify the file header; use --header "..."
on command line; use sgen:header
in config file */
HEADER,
/** Specify the file footer; use --footer "..."
on command line; use sgen:footer
in config file */
FOOTER,
/** Specify the uri of the configuration root node; use --root <URL>
on command line */
ROOT,
/** Specify the marker string for substitutions, default is '%'; use -m "..."
on command line; use sgen:marker
in config file */
MARKER,
/** Specify the packagename; use --package <packagename>
on command line; use sgen:package
in config file */
PACKAGENAME,
/** Use ontology terms in preference to vanilla RDF; use --ontology
on command line; use sgen:ontology
in config file */
ONTOLOGY,
/** The name of the generated class; use -n <classname>
on command line; use sgen:classname
in config file */
CLASSNAME,
/** Additional decoration for class header (such as implements); use --classdec <classname>
on command line; use sgen:classdec
in config file */
CLASSDEC,
/** The namespace URI for the vocabulary; use -a <uri>
on command line; use sgen:namespace
in config file */
NAMESPACE,
/** Additional declarations to add at the top of the class; use --declarations <...>
on command line; use sgen:declarations
in config file */
DECLARATIONS,
/** Section declaration for properties section; use --propSection <...>
on command line; use sgen:propSection
in config file */
PROPERTY_SECTION,
/** Section declaration for class section; use --classSection <...>
on command line; use sgen:classSection
in config file */
CLASS_SECTION,
/** Section declaration for individuals section; use --individualsSection <...>
on command line; use sgen:individualsSection
in config file */
INDIVIDUALS_SECTION,
/** Option to suppress properties in vocab file; use --noproperties <...>
on command line; use sgen:noproperties
in config file */
NOPROPERTIES,
/** Option to suppress classes in vocab file; use --noclasses <...>
on command line; use sgen:noclasses
in config file */
NOCLASSES,
/** Option to suppress individuals in vocab file; use --noindividuals <...>
on command line; use sgen:noindividuals
in config file */
NOINDIVIDUALS,
/** Option for no file header; use --noheader <...>
on command line; use sgen:noheader
in config file */
NOHEADER,
/** Template for writing out property declarations; use --propTemplate <...>
on command line; use sgen:propTemplate
in config file */
PROP_TEMPLATE,
/** Template for writing out class declarations; use --classTemplate <...>
on command line; use sgen:classTemplate
in config file */
CLASS_TEMPLATE,
/** Template for writing out individual declarations; use --individualTemplate <...>
on command line; use sgen:individualTemplate
in config file */
INDIVIDUAL_TEMPLATE,
/** Option for mapping constant names to uppercase; use --uppercase <...>
on command line; use sgen:uppercase
in config file */
UC_NAMES,
/** Option for including non-local URI's in vocabulary; use --include <uri>
on command line; use sgen:include
in config file */
INCLUDE,
/** Option for adding a suffix to the generated class name; use --classnamesuffix <uri>
on command line; use sgen:classnamesuffix
in config file */
CLASSNAME_SUFFIX,
/** Option for the presentation syntax (encoding) of the file; use -e encoding
on command line; use sgen:encoding
in config file */
ENCODING,
/** Option to show the usage message; use --help on command line */
HELP,
/** Option to generate an output file with DOS (\r\n) line endings. Default is Unix line endings. */
DOS,
/** Option to generate to force the model to perform inference, off by default. */
USE_INF,
/** Option to exclude instances of classes in the allowed namespaces, where the individuals themselves are in other namespaces; use --strictIndividuals
on command line; use sgen:strictIndividuals
in config file */
STRICT_INDIVIDUALS,
/** Option to include the ontology source code in the generated file */
INCLUDE_SOURCE,
/** Option to turn off strict checking in .a() */
NO_STRICT
}
public static final Object[][] m_optionDefinitions = new Object[][] {
{OPT.CONFIG_FILE, new OptionDefinition( "-c", "configFile" ) },
{OPT.ROOT, new OptionDefinition( "-r", "root" ) },
{OPT.NO_COMMENTS, new OptionDefinition( "--nocomments", "noComments" ) },
{OPT.INPUT, new OptionDefinition( "-i", "input" ) },
{OPT.LANG_DAML, new OptionDefinition( "--daml", "daml" ) },
{OPT.LANG_OWL, new OptionDefinition( "--owl", "owl" ) },
{OPT.LANG_RDFS, new OptionDefinition( "--rdfs", "rdfs" ) },
{OPT.OUTPUT, new OptionDefinition( "-o", "output" ) },
{OPT.HEADER, new OptionDefinition( "--header", "header" ) },
{OPT.FOOTER, new OptionDefinition( "--footer", "footer" ) },
{OPT.MARKER, new OptionDefinition( "--marker", "marker" ) },
{OPT.PACKAGENAME, new OptionDefinition( "--package", "package" ) },
{OPT.ONTOLOGY, new OptionDefinition( "--ontology", "ontology" ) },
{OPT.CLASSNAME, new OptionDefinition( "-n", "classname" ) },
{OPT.CLASSDEC, new OptionDefinition( "--classdec", "classdec" ) },
{OPT.NAMESPACE, new OptionDefinition( "-a", "namespace" ) },
{OPT.DECLARATIONS, new OptionDefinition( "--declarations", "declarations" ) },
{OPT.PROPERTY_SECTION, new OptionDefinition( "--propSection", "propSection" ) },
{OPT.CLASS_SECTION, new OptionDefinition( "--classSection", "classSection" ) },
{OPT.INDIVIDUALS_SECTION, new OptionDefinition( "--individualsSection", "individualsSection" ) },
{OPT.NOPROPERTIES, new OptionDefinition( "--noproperties", "noproperties" ) },
{OPT.NOCLASSES, new OptionDefinition( "--noclasses", "noclasses" ) },
{OPT.NOINDIVIDUALS, new OptionDefinition( "--noindividuals", "noindividuals" ) },
{OPT.PROP_TEMPLATE, new OptionDefinition( "--propTemplate", "propTemplate" ) },
{OPT.CLASS_TEMPLATE, new OptionDefinition( "--classTemplate", "classTemplate" ) },
{OPT.INDIVIDUAL_TEMPLATE, new OptionDefinition( "--individualTemplate", "individualTemplate" ) },
{OPT.UC_NAMES, new OptionDefinition( "--uppercase", "uppercase" ) },
{OPT.INCLUDE, new OptionDefinition( "--include", "include" ) },
{OPT.CLASSNAME_SUFFIX, new OptionDefinition( "--classnamesuffix", "classnamesuffix" )},
{OPT.NOHEADER, new OptionDefinition( "--noheader", "noheader" )},
{OPT.ENCODING, new OptionDefinition( "-e", "encoding" )},
{OPT.HELP, new OptionDefinition( "--help", "help" )},
{OPT.DOS, new OptionDefinition( "--dos", "dos" )},
{OPT.USE_INF, new OptionDefinition( "--inference", "inference" )},
{OPT.STRICT_INDIVIDUALS, new OptionDefinition( "--strictIndividuals", "strictIndividuals" )},
{OPT.INCLUDE_SOURCE, new OptionDefinition( "--includeSource", "includeSource" )},
{OPT.NO_STRICT, new OptionDefinition( "--nostrict", "noStrict")},
};
public boolean hasConfigFileOption();
public String getConfigFileOption();
public boolean hasRootOption();
public String getRootOption();
public boolean hasNoCommentsOption();
public String getNoCommentsOption();
public boolean hasInputOption();
public Resource getInputOption();
public boolean hasLangDamlOption();
public String getLangDamlOption();
public boolean hasLangOwlOption();
public String getLangOwlOption();
public boolean hasLangRdfsOption();
public String getLangRdfsOption();
public boolean hasOutputOption();
public String getOutputOption();
public boolean hasHeaderOption();
public String getHeaderOption();
public boolean hasFooterOption();
public String getFooterOption();
public boolean hasMarkerOption();
public String getMarkerOption();
public boolean hasPackagenameOption();
public String getPackagenameOption();
public boolean hasOntologyOption();
public String getOntologyOption();
public boolean hasClassnameOption();
public String getClassnameOption();
public boolean hasClassdecOption();
public String getClassdecOption();
public boolean hasNamespaceOption();
public Resource getNamespaceOption();
public boolean hasDeclarationsOption();
public String getDeclarationsOption();
public boolean hasPropertySectionOption();
public String getPropertySectionOption();
public boolean hasClassSectionOption();
public String getClassSectionOption();
public boolean hasIndividualsSectionOption();
public String getIndividualsSectionOption();
public boolean hasNopropertiesOption();
public boolean hasNoclassesOption();
public boolean hasNoindividualsOption();
public boolean hasPropTemplateOption();
public String getPropTemplateOption();
public boolean hasClassTemplateOption();
public String getClassTemplateOption();
public boolean hasIndividualTemplateOption();
public String getIndividualTemplateOption();
public boolean hasUcNamesOption();
public boolean hasIncludeOption();
public List getIncludeOption();
public boolean hasClassnameSuffixOption();
public String getClassnameSuffixOption();
public boolean hasNoheaderOption();
public boolean hasEncodingOption();
public String getEncodingOption();
public boolean hasHelpOption();
public String getHelpOption();
public boolean hasDosOption();
public boolean hasUseInfOption();
public boolean hasStrictIndividualsOption();
public boolean hasIncludeSourceOption();
public boolean hasNoStrictOption();
}
public static class SchemagenOptionsImpl
implements SchemagenOptions
{
// Instance variables
/** The list of command line arguments */
private List m_cmdLineArgs = new ArrayList();
/** The root of the options in the config file */
private Resource m_root;
/** The model that contains the configuration information */
private Model m_config = ModelFactory.createDefaultModel();
// Constructor
public SchemagenOptionsImpl( String[] args ) {
m_cmdLineArgs = Arrays.asList( args );
// check to see if there's a specified config file
String configURL = DEFAULT_CONFIG_URI;
if (hasConfigFileOption()) {
// check for protocol; add file: if not specified
configURL = SchemagenUtils.urlCheck( getConfigFileOption() );
}
// ensure we have a root URI for the configuration model
determineConfigRoot();
// try to read the config URI
try {
FileManager.get().readModel( m_config, configURL );
}
catch (Exception e) {
// if the user left the default config URI in place, it's not an error to fail to read it
if (!configURL.equals( DEFAULT_CONFIG_URI )) {
throw new SchemagenException( "Failed to read configuration from URL: " + configURL, e );
}
}
}
/**
* Return the configuration model used to hold config information
* @return
*/
protected Model getConfigModel() {
return m_config;
}
/**
* Return the root resource to which configuration information is attached
* @return
*/
protected Resource getConfigRoot() {
if (m_root == null) {
determineConfigRoot();
}
return m_root;
}
// Internal implementation methods
/** Determine the root resource in the configuration file */
protected void determineConfigRoot() {
if (hasValue( OPT.ROOT )) {
m_root = m_config.getResource( getStringValue( OPT.ROOT ) );
}
else {
// no specified root, we assume there is only one with type sgen:Config
StmtIterator i = m_config.listStatements( null, RDF.type, m_config.getResource( NS + "Config" ) );
if (i.hasNext()) {
m_root = i.nextStatement().getSubject();
}
else {
// no configuration root, so we invent one
m_root = m_config.createResource();
}
}
}
/** Answer true if the given option is set to true */
protected boolean isTrue( OPT option ) {
return getOpt( option ).isTrue( m_cmdLineArgs, m_root );
}
/** Answer true if the given option has value */
protected boolean hasValue( OPT option ) {
return getOpt( option ).hasValue( m_cmdLineArgs, m_root );
}
/** Answer the value of the option or null */
protected RDFNode getValue( OPT option ) {
return getOpt( option ).getValue( m_cmdLineArgs, m_root );
}
/** Answer the String value of the option or null */
protected String getStringValue( OPT option ) {
return getOpt( option ).getStringValue( m_cmdLineArgs, m_root );
}
/** Answer true if the given option has a resource value */
protected boolean hasResourceValue( OPT option ) {
return getOpt( option ).hasResourceValue( m_cmdLineArgs, m_root );
}
/** Answer the value of the option or null */
protected Resource getResource( OPT option ) {
return getOpt( option ).getResource( m_cmdLineArgs, m_root );
}
/** Answer all values for the given options as Strings */
protected List getAllValues( OPT option ) {
List values = new ArrayList();
OptionDefinition opt = getOpt( option );
// look in the command line arguments
for (Iterator i = m_cmdLineArgs.iterator(); i.hasNext(); ) {
String s = i.next();
if (s.equals( opt.m_cmdLineForm )) {
// next iterator value is the arg value
values.add( i.next() );
}
}
// now look in the config file
for (StmtIterator i = m_root.listProperties( opt.m_prop ); i.hasNext(); ) {
Statement s = i.nextStatement();
if (s.getObject() instanceof Literal) {
values.add( s.getString() );
}
else {
values.add( s.getResource().getURI() );
}
}
return values;
}
/** Answer the option object for the given option */
protected OptionDefinition getOpt( OPT option ) {
for (int i = 0; i < m_optionDefinitions.length; i++) {
if (m_optionDefinitions[i][0] == option) {
return (OptionDefinition) m_optionDefinitions[i][1];
}
}
return null;
}
// External interface methods
public boolean hasConfigFileOption() { return hasValue( OPT.CONFIG_FILE ); }
public String getConfigFileOption() { return getStringValue( OPT.CONFIG_FILE ); }
public boolean hasRootOption() { return hasValue( OPT.ROOT ); }
public String getRootOption() { return getStringValue( OPT.ROOT ); }
public boolean hasNoCommentsOption() { return isTrue( OPT.NO_COMMENTS ); }
public String getNoCommentsOption() { return getStringValue( OPT.NO_COMMENTS ); }
public boolean hasInputOption() { return hasValue( OPT.INPUT ); }
public Resource getInputOption() { return getResource( OPT.INPUT ); }
public boolean hasLangDamlOption() { return isTrue( OPT.LANG_DAML ); }
public String getLangDamlOption() { return getStringValue( OPT.LANG_DAML ); }
public boolean hasLangOwlOption() { return isTrue( OPT.LANG_OWL ); }
public String getLangOwlOption() { return getStringValue( OPT.LANG_OWL ); }
public boolean hasLangRdfsOption() { return isTrue( OPT.LANG_RDFS ); }
public String getLangRdfsOption() { return getStringValue( OPT.LANG_RDFS ); }
public boolean hasOutputOption() { return hasValue( OPT.OUTPUT ); }
public String getOutputOption() { return getStringValue( OPT.OUTPUT ); }
public boolean hasHeaderOption() { return isTrue( OPT.HEADER ); }
public String getHeaderOption() { return getStringValue( OPT.HEADER ); }
public boolean hasFooterOption() { return isTrue( OPT.FOOTER ); }
public String getFooterOption() { return getStringValue( OPT.FOOTER ); }
public boolean hasMarkerOption() { return hasValue( OPT.MARKER ); }
public String getMarkerOption() { return getStringValue( OPT.MARKER ); }
public boolean hasPackagenameOption() { return hasValue( OPT.PACKAGENAME ); }
public String getPackagenameOption() { return getStringValue( OPT.PACKAGENAME ); }
public boolean hasOntologyOption() { return isTrue( OPT.ONTOLOGY ); }
public String getOntologyOption() { return getStringValue( OPT.ONTOLOGY ); }
public boolean hasClassnameOption() { return hasValue( OPT.CLASSNAME ); }
public String getClassnameOption() { return getStringValue( OPT.CLASSNAME ); }
public boolean hasClassdecOption() { return hasValue( OPT.CLASSDEC ); }
public String getClassdecOption() { return getStringValue( OPT.CLASSDEC ); }
public boolean hasNamespaceOption() { return hasValue( OPT.NAMESPACE ); }
public Resource getNamespaceOption() { return getResource( OPT.NAMESPACE ); }
public boolean hasDeclarationsOption() { return hasValue( OPT.DECLARATIONS ); }
public String getDeclarationsOption() { return getStringValue( OPT.DECLARATIONS ); }
public boolean hasPropertySectionOption() { return hasValue( OPT.PROPERTY_SECTION ); }
public String getPropertySectionOption() { return getStringValue( OPT.PROPERTY_SECTION ); }
public boolean hasClassSectionOption() { return hasValue( OPT.CLASS_SECTION ); }
public String getClassSectionOption() { return getStringValue( OPT.CLASS_SECTION ); }
public boolean hasIndividualsSectionOption() { return hasValue( OPT.INDIVIDUALS_SECTION ); }
public String getIndividualsSectionOption() { return getStringValue( OPT.INDIVIDUALS_SECTION ); }
public boolean hasNopropertiesOption() { return isTrue( OPT.NOPROPERTIES ); }
public boolean hasNoclassesOption() { return isTrue( OPT.NOCLASSES ); }
public boolean hasNoindividualsOption() { return isTrue( OPT.NOINDIVIDUALS ); }
public boolean hasPropTemplateOption() { return hasValue( OPT.PROP_TEMPLATE ); }
public String getPropTemplateOption() { return getStringValue( OPT.PROP_TEMPLATE ); }
public boolean hasClassTemplateOption() { return hasValue( OPT.CLASS_TEMPLATE ); }
public String getClassTemplateOption() { return getStringValue( OPT.CLASS_TEMPLATE ); }
public boolean hasIndividualTemplateOption() { return hasValue( OPT.INDIVIDUAL_TEMPLATE ); }
public String getIndividualTemplateOption() { return getStringValue( OPT.INDIVIDUAL_TEMPLATE ); }
public boolean hasUcNamesOption() { return isTrue( OPT.UC_NAMES ); }
public boolean hasIncludeOption() { return hasValue( OPT.INCLUDE ); }
public List getIncludeOption() { return getAllValues( OPT.INCLUDE ); }
public boolean hasClassnameSuffixOption() { return hasValue( OPT.CLASSNAME_SUFFIX ); }
public String getClassnameSuffixOption() { return getStringValue( OPT.CLASSNAME_SUFFIX ); }
public boolean hasNoheaderOption() { return isTrue( OPT.NOHEADER ); }
public boolean hasEncodingOption() { return hasValue( OPT.ENCODING ); }
public String getEncodingOption() { return getStringValue( OPT.ENCODING ); }
public boolean hasHelpOption() { return hasValue( OPT.HELP ); }
public String getHelpOption() { return getStringValue( OPT.HELP ); }
public boolean hasDosOption() { return isTrue( OPT.DOS ); }
public boolean hasUseInfOption() { return isTrue( OPT.USE_INF ); }
public boolean hasStrictIndividualsOption() { return isTrue( OPT.STRICT_INDIVIDUALS ); }
public boolean hasIncludeSourceOption() { return isTrue( OPT.INCLUDE_SOURCE ); }
public boolean hasNoStrictOption() { return isTrue( OPT.NO_STRICT ); }
}
/** An option that can be set either on the command line or in the RDF config */
public static class OptionDefinition
{
protected String m_cmdLineForm;
protected Property m_prop;
protected OptionDefinition( String cmdLineForm, String name ) {
m_cmdLineForm = cmdLineForm;
if (name != null) {
m_prop = ResourceFactory.createProperty( NS, name );
}
}
/**
* Return the RDF property that is used when configuring this option
* via a {@link Model}
* @return The declaration property, or null
*/
public Property getDeclarationProperty() {
return m_prop;
}
/**
* Return the command line form of this option
* @return The command line form as a String
*/
public String getCommandLineForm() {
return m_cmdLineForm;
}
/**
* Answer true if this option is set to true, either on the command line
* or in the config model
*
* @return boolean
*/
protected boolean isTrue( List cmdLineArgs, Resource confRoot ) {
if (cmdLineArgs.contains( m_cmdLineForm )) {
return true;
}
if (confRoot.hasProperty( m_prop )) {
return confRoot.getRequiredProperty( m_prop ).getBoolean();
}
return false;
}
/**
* Answer the string value of the parameter if set, or null otherwise. Note command line
* has precedence.
*
* @return String
*/
protected String getStringValue( List cmdLineArgs, Resource confRoot ) {
RDFNode n = getValue( cmdLineArgs, confRoot );
return (n == null) ? null : (n.isLiteral() ? n.asLiteral().getLexicalForm() : n.toString() );
}
/**
* Return the value of the parameter if set, or null otherwise. Note command line
* has precedence.
*
* @return The argument value as an RDFNode
*/
protected RDFNode getValue( List cmdLineArgs, Resource confRoot ) {
int index = cmdLineArgs.indexOf( m_cmdLineForm );
if (index >= 0) {
try {
return ResourceFactory.createPlainLiteral( cmdLineArgs.get( index + 1 ) );
}
catch (IndexOutOfBoundsException e) {
throw new SchemagenException( "Value for parameter " + m_cmdLineForm + " not set! Aborting.", e );
}
}
if (m_prop != null && confRoot != null && confRoot.hasProperty( m_prop )) {
return confRoot.getRequiredProperty( m_prop ).getObject();
}
// not set
return null;
}
/**
* Answer true if the parameter has a value at all.
*
* @return boolean
*/
protected boolean hasValue( List cmdLineArgs, Resource confRoot ) {
return getValue( cmdLineArgs, confRoot ) != null;
}
/**
* Answer the resource value of the parameter if set, or null otherwise.
*
* @return String
*/
protected Resource getResource( List cmdLineArgs, Resource confRoot ) {
int index = cmdLineArgs.indexOf( m_cmdLineForm );
if (index >= 0) {
try {
return confRoot.getModel().getResource( cmdLineArgs.get( index + 1 ) );
}
catch (IndexOutOfBoundsException e) {
System.err.println( "Value for parameter " + m_cmdLineForm + " not set! Aborting.");
}
}
if (m_prop != null && confRoot.hasProperty( m_prop )) {
return confRoot.getRequiredProperty( m_prop ).getResource();
}
// not set
return null;
}
/**
* Answer true if the parameter has a value at all.
*
* @return boolean
*/
protected boolean hasResourceValue( List cmdLineArgs, Resource confRoot ) {
return getResource( cmdLineArgs, confRoot ) != null;
}
} // end inner class OptionDefinition
/** A pairing of pattern and substitution we want to apply to output */
protected class Replacement
{
protected String sub;
protected Pattern pattern;
protected Replacement( Pattern pattern, String sub) {
this.sub = sub;
this.pattern = pattern;
}
} // end inner class Replacement
/**
* Schemagen runtime exception
*/
public static class SchemagenException
extends RuntimeException
{
public SchemagenException( String msg, Throwable cause ) {
super( msg, cause );
}
}
/** Utility method container */
public static class SchemagenUtils
{
/** Return a URI formed from the given string, unchanged if it's already a URI or
* converted to a file URI otherwise. If not recognisable as a URL, abort.
*/
public static String urlCheck( String uriOrFile ) {
boolean legal = true;
String url = uriOrFile;
// is it a URI already? to check, we make a URL and see what happens!
try {
new URL( url );
}
catch (MalformedURLException ignore) {
legal = false;
}
// if not a legal url, assume it's a file
if (!legal) {
legal = true;
String slash = System.getProperty( "file.separator" );
url = "file:" + (uriOrFile.startsWith( slash ) ? (slash + slash) : "") + uriOrFile;
try {
new URL( url );
}
catch (MalformedURLException ignore) {
legal = false;
}
}
if (!legal) {
throw new SchemagenException( "Could not parse " + uriOrFile + " as a legal URL or a file reference. Aborting.", null );
}
return url;
}
} /* End class SchemagenUtils */
}
/*
(c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Hewlett-Packard Development Company, LP
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/