package gr.ntua.ivml.athena.db;
import gr.ntua.ivml.athena.util.StringUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import org.apache.log4j.Logger;
import org.hibernate.StatelessSession;
/**
* Maintain a list of all namespaces in the system and give each a unique
* prefix independent of the input. It will use an existing connection from
* a stateless session to do db storing. It will not close it.
*
*
*
* @author Arne Stabenau
* Its my opinion that its not safe to rely on global unique prefixes for
* the mappings. If they get corrupt, all mappings become invalid. Mappings
* should rely on URIs so a re-import of XML would make them valid again.
*
* Basically mappings are only valid for a certain application state? Not my favorite
* solution, albeit easy on the other people.
*/
public class GlobalPrefixStore {
private static HashMap<String, String> namespaces;
private static HashMap<String, String> prefixes;
public static Logger log = Logger.getLogger( GlobalPrefixStore.class );
static {
namespaces = new HashMap<String,String>();
prefixes = new HashMap<String,String>();
StatelessSession ss = DB.getStatelessSession();
ResultSet rs = null;
try {
Connection c = ss.connection();
rs = c.createStatement().executeQuery("select uri, prefix from global_namespaces");
while( rs.next()) {
namespaces.put( rs.getString(1), rs.getString(2));
prefixes.put( rs.getString( 2), rs.getString(1));
}
} catch( Exception e ) {
log.error( "Problem with global prefixes.", e);
} finally {
try {
if( rs!= null) rs.close();
} catch( Exception e){}
log.debug( "Closing session");
DB.closeStatelessSession();
log.debug( "Session closed");
}
}
/**
* Create global prefixes during import.
* @param uri
* @param preferredPrefix
* @return
*/
public static synchronized String createPrefix( String uri, String preferredPrefix ) {
String prefix = namespaces.get( uri );
if( prefix == null ) {
if( StringUtils.empty(preferredPrefix))
preferredPrefix = prefixFromUri(uri);
prefix = createPrefix( preferredPrefix );
storePrefix( uri, prefix );
}
return prefix;
}
/**
* Use this version when you KNOW the namespace is in the system.
* (After the import was successful)
* @param uri
* @return
*/
public static String getPrefix( String uri ) {
return namespaces.get( uri );
}
/**
* Add numbers to the preferred prefix until it is unique
* @param preferred
* @return
*/
private static String createPrefix( String preferred ) {
String prefix = preferred;
int count = 0;
while( true ) {
if( count > 0 ) {
prefix = preferred+""+count;
} else {
prefix = preferred;
}
if( !prefixes.containsKey( prefix )) break;
count += 1;
}
return prefix;
}
private static String prefixFromUri( String uri ) {
if(uri.equals("http://www.w3.org/XML/1998/namespace")) return "xml";
String[] candidates = uri.split( "[^a-zA-Z0-9]");
for( String part: candidates ) {
if( part.length()<3) continue;
if( part.toLowerCase().contains("www")) continue;
if( part.toLowerCase().matches("com|org|edu|biz|gov|http|uri|urn|url|xml|zip|xsl")) continue;
return part;
}
return "def";
}
/**
* Put it in database ..
* @param uri
* @param prefix
*/
private static void storePrefix( String uri, String prefix ) {
StatelessSession ss = DB.getStatelessSession();
Connection c = ss.connection();
try {
PreparedStatement ps = c.prepareStatement( "insert into global_namespaces(uri, prefix) values( ?,? )");
ps.setString( 1, uri);
ps.setString( 2, prefix );
ps.execute();
c.commit();
namespaces.put( uri, prefix);
prefixes.put( prefix, uri);
} catch( Exception e ) {
log.error( "Storing failed.");
}
}
}