org.apache.jena.tdb.base.file.MetaFile Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jena-tdb Show documentation
Show all versions of jena-tdb Show documentation
TDB is a storage subsystem for Jena and ARQ, it is a native triple store providing persistent storage of triples/quads.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.jena.tdb.base.file;
import java.io.ByteArrayOutputStream ;
import java.io.File ;
import java.io.FileNotFoundException ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.PrintStream ;
import java.util.Comparator ;
import java.util.Objects;
import java.util.Properties ;
import java.util.SortedSet ;
import java.util.TreeSet ;
import org.apache.jena.atlas.lib.* ;
import org.apache.jena.tdb.TDBException ;
import org.apache.jena.tdb.sys.Names ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
/** Abstraction and many convenience operations on metadata.
* Metadata is recorded in Java properties style - not RDF - because it's relative to the file or context used.
* Keys and values are always strings.
*/
public class MetaFile implements Sync, Closeable
{
private static Comparator comparator = new ComparatorKeys() ;
private static Logger log = LoggerFactory.getLogger(MetaFile.class) ;
private String metaFilename = null ;
private Properties properties = null ;
private String label = null ;
private boolean changed = false ;
private boolean closed = false ;
/** Create a MetaFile
*
* @param label Convenience label.
* @param fn On disk filename @link{Names.mem} for in-memory
*/
public MetaFile(String label, String fn)
{
this.label = label ;
this.metaFilename = fn ;
if ( fn == null || Names.isMem(fn) )
// In-memory.
return ;
// Make absolute (current directory may change later)
if ( ! fn.endsWith(Names.extMeta) )
fn = fn+"."+Names.extMeta ;
File f = new File(fn) ;
this.metaFilename = f.getAbsolutePath() ;
// Does not load the details yet.
// JDI
ensureInit() ;
}
private void ensureInit()
{
if ( properties == null )
{
properties = new PropertiesSorted(comparator) ;
if ( metaFilename != null )
loadProperties() ;
}
}
/** Does this metafile exist on disk? (In-memory MetaFiles always exist) */
public boolean existsMetaData()
{
if ( isMem() )
return true ;
File f = new File(metaFilename) ;
if ( f.isDirectory() )
log.warn("Metadata file clashes with a directory") ;
return f.exists() && f.isFile() ;
}
public String getFilename() { return metaFilename ; }
/** Test for the presence of a property */
public boolean hasProperty(String key)
{
return _getProperty(key, null) != null ;
}
/** Get the property value or null. */
public String getProperty(String key)
{
return _getProperty(key, null) ;
}
/** Get the property value or return supplied default. */
public String getProperty(String key, String defaultString)
{
return _getProperty(key, defaultString) ;
}
/** Get the property value and parse as an integer */
public int getPropertyAsInteger(String key)
{
return Integer.parseInt(_getProperty(key, null)) ;
}
/** Get the property value and parse as an integer or return default value. */
public int getPropertyAsInteger(String key, int defaultValue)
{
String x = getProperty(key) ;
if ( x == null )
return defaultValue ;
return Integer.parseInt(x) ;
}
/** Get property as a string and split on ",". */
public String[] getPropertySplit(String key)
{
String str = getProperty(key) ;
if ( str == null )
return null ;
return str.split(",") ;
}
/** Get property as a string and split on ",", using the default string if not present in the MetaFile. */
public String[] getPropertySplit(String key, String defaultString)
{
String str = getProperty(key, defaultString) ;
return str.split(",") ;
}
/** Set property */
public void setProperty(String key, String value)
{
_setProperty(key, value) ;
}
/** Set property, turning integer into a string. */
public void setProperty(String key, int value)
{
_setProperty(key, Integer.toString(value)) ;
}
/** Test whether a property has a value. Null tests equal to not present. */
public boolean propertyEquals(String key, String value)
{
return Objects.equals(getProperty(key), value) ;
}
/** Set property if not already set. */
public void ensurePropertySet(String key, String expected)
{
getOrSetDefault(key, expected) ;
}
/** Get property or the default value - also set the default value if not present */
public String getOrSetDefault(String key, String expected)
{
String x = getProperty(key) ;
if ( x == null )
{
setProperty(key, expected) ;
x = expected ;
}
return x ;
}
/** Check property is an expected value or set if missing */
public void checkOrSetMetadata(String key, String expected)
{
String x = getProperty(key) ;
if ( x == null )
{
setProperty(key, expected) ;
return ;
}
if ( x.equals(expected) )
return ;
inconsistent(key, x, expected) ;
}
/** Check property has the value given - throw exception if not. */
public void checkMetadata(String key, String expected)
{
String value = getProperty(key) ;
if ( ! Objects.equals(value, value) )
inconsistent(key, value, expected) ;
}
private static void inconsistent(String key, String actual, String expected)
{
String msg = String.format("Inconsistent: key=%s value=%s expected=%s",
key,
(actual==null?"":actual),
(expected==null?"":expected) ) ;
throw new MetaFileException(msg) ;
}
/** Clear all properties. */
public void clear()
{
_clear() ;
}
// ---- All get/set access through these operations
private String _getProperty(String key, String dft)
{
ensureInit() ;
return properties.getProperty(key, dft) ;
}
private void _setProperty(String key, String value)
{
ensureInit() ;
properties.setProperty(key, value) ;
changedEvent() ;
}
/** Clear all properties. */
private void _clear()
{
ensureInit() ;
properties.clear() ;
changedEvent() ;
}
private void changedEvent() { changed = true ; }
// ----
private boolean isMem() { return Names.isMem(metaFilename) ; }
/** Write to backing file if changed */
public void flush()
{
if ( log.isDebugEnabled() )
log.debug("Flush metadata ("+changed+"): "+this.label) ;
if ( ! changed )
return ;
if ( log.isDebugEnabled() )
{
ByteArrayOutputStream out = new ByteArrayOutputStream() ;
PrintStream ps = new PrintStream(out) ;
properties.list(ps) ;
ps.flush() ;
log.debug("\n"+out.toString()) ;
}
//properties.list(System.out) ;
saveProperties() ;
changed = false ;
}
private void saveProperties()
{
if ( isMem() )
return ;
String str = label ;
if ( str == null )
str = metaFilename ;
str = "Metadata: "+str ;
try {
PropertyUtils.storeToFile(properties, str, metaFilename) ;
}
catch (IOException ex)
{
log.error("Failed to store properties: "+metaFilename, ex) ;
}
}
private void loadProperties()
{
if ( isMem() )
{
properties = new Properties() ;
return ;
}
if ( properties == null )
properties = new Properties() ;
// if ( metaFilename == null )
InputStream in = null ;
try {
// Copes with UTF-8 for Java5.
PropertyUtils.loadFromFile(properties, metaFilename) ;
}
catch (FileNotFoundException ex) {}
catch (IOException ex)
{
log.error("Failed to load properties: "+metaFilename, ex) ;
}
}
/** Debugging */
public void dump(PrintStream output)
{
output.println("Metafile: "+metaFilename) ;
output.println("Label: "+label) ;
output.println("Status: "+(changed?"changed":"unchanged")) ;
if ( properties == null )
{
output.println("#") ;
return ;
}
// properties.list() ;
SortedSet