/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.resolver.filesystem;
// Java 2 standard packages
import java.io.*;
import java.net.URI;
import java.util.*;
import java.text.SimpleDateFormat;
// Third party packages
import org.jrdf.graph.*;
import org.jrdf.graph.mem.*;
import org.jrdf.vocabulary.RDF;
import org.apache.log4j.Logger; // Apache Log4J
import org.mulgara.resolver.filesystem.exception.MetaDataException;
import org.mulgara.resolver.filesystem.exception.MetaIOException;
import org.mulgara.resolver.filesystem.exception.VocabularyException;
import org.mulgara.resolver.filesystem.util.GraphUtil;
/**
* Extends the standard java File class to allow for a file that can retrieve
* its metadata as well as link to the siblings files in its directory.
*
* @created 2004-11-25
*
* @author Mark Ludlow
*
* @version $Revision: 1.8 $
*
* @modified $Date: 2005/01/05 04:58:27 $ @maintenanceAuthor $Author: newmana $
*
* @company <a href="mailto:info@PIsoftware.com">Plugged In Software</a>
*
* @copyright © 2004 <a href="http://www.PIsoftware.com/">Plugged In
* Software Pty Ltd</a>
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class MetaFile extends File {
private static final long serialVersionUID = -6912916007828365901L;
/** Logger. */
private static final Logger log = Logger.getLogger(MetaFile.class);
/** A graph containing the metadata for the file data */
private Graph graph;
/** The previous sibling */
private MetaFile previousSibling;
/** The next sibling */
private MetaFile nextSibling;
/**
* Constructor.
*
* @param uri The uri of the file this object represents
*
* @throws MetaIOException
*/
MetaFile(URI uri) throws MetaIOException {
// Create a file with the given uri
super(uri);
try {
// Initialise the graph to be a memory based graph
graph = new GraphImpl();
} catch (GraphException graphException) {
throw new MetaIOException("Unable to create a new graph object.",
graphException);
}
}
/**
* Retrieves the next sibling of this metafile.
*
* @return The next sibling file to this one
*/
public MetaFile nextSibling() {
return nextSibling;
}
/**
* Retrieves the previous sibling of this metafile.
*
* @return The previous sibling file to this one
*/
public MetaFile previousSibling() {
return previousSibling;
}
/**
* Sets the metafile's next sibling.
*
* @param sibling The next sibling along from this metafile
*/
public void setNextSibling(MetaFile sibling) {
// Store the new next sibling
nextSibling = sibling;
}
/**
* Sets the metafile's previous sibling.
*
* @param sibling The previous sibling from this metafile
*/
public void setPreviousSibling(MetaFile sibling) {
// Store the new previous sibling
previousSibling = sibling;
}
/**
* Retrieves the children of this metafile if it is a directory. This will
* also set up the sibling relationships of the descendants of this file.
*
* @return The list of children files of this directory
*
* @throws MetaIOException
*/
public MetaFile[] listChildren() throws MetaIOException {
// Obtain the list of children files
File[] children = this.listFiles();
// Sort the array of child files by name
Arrays.sort(children, new Comparator<File>() {
public int compare(File file1, File file2) {
// Return the natural comparison of the file names
return file1.getName().compareTo(file2.getName());
}
});
// Create a mirror array of children metafiles
MetaFile[] metaChildren = new MetaFile[children.length];
for (int i = 0; i < metaChildren.length; i++) {
// Create a new metafile from the matching children array entry
metaChildren[i] = new MetaFile(children[i].toURI());
if (i > 0) {
// If we are past the first entry then link the file to the previous
// entry
metaChildren[i].setPreviousSibling(metaChildren[i - 1]);
// Link the previous entry to this sibling
metaChildren[i - 1].setNextSibling(metaChildren[i]);
}
}
return metaChildren;
}
/**
* Retrieves the children of this metafile if it is a directory. It uses a
* filefilter to constrain the children that are contained in the list.
* This will also set up the sibling relationships of the filtered descendants
* of this file.
*
* @return The list of children files of this directory
*
* @throws MetaIOException
*/
public MetaFile[] listChildrenByFilter(FileFilter filter) throws
MetaIOException {
if (log.isDebugEnabled()) {
log.debug("Filtering children of " + this.toURI());
}
// Obtain the list of children files using the filter
File[] children = this.listFiles(filter);
if (children.length > 0) {
// We can only produce a list of children if we found any fitting the
// filter
// Sort the array of filtered child files by name
Arrays.sort(children, new Comparator<File>() {
public int compare(File file1, File file2) {
// Return the natural comparison of the file names
return file1.getName().compareTo(file2.getName());
}
});
// Create a mirror array of children metafiles
MetaFile[] metaChildren = new MetaFile[children.length];
for (int i = 0; i < metaChildren.length; i++) {
// Create a new metafile from the matching children array entry
metaChildren[i] = new MetaFile(children[i].toURI());
if (i > 0) {
// If we are past the first entry then link the file to the previous
// entry
metaChildren[i].setPreviousSibling(metaChildren[i - 1]);
// Link the previous entry to this sibling
metaChildren[i - 1].setNextSibling(metaChildren[i]);
}
}
return metaChildren;
}
return new MetaFile[0];
}
/**
* Store the metadata for the given file in the graph.
*
* @return The graph containing the metadata for this file
*
* @throws MetaDataException
* @throws MetaIOException
*/
public Graph getMetadata() throws MetaDataException, MetaIOException {
// Flag to indicate if the graph is empty (Assumed false)
boolean empty = false;
try {
// Check if the graph is empty
empty = graph.isEmpty();
} catch (GraphException graphException) {
throw new MetaIOException("Unable to check if graph was empty.",
graphException);
}
if (graph != null && empty) {
// The guard prevents unnecessary repetition of the metadata extraction
// by checking if the graph is already populated.
if (log.isDebugEnabled()) {
log.debug("Obtaining metadata for file: " + getAbsolutePath());
}
// Obtain the element factory
GraphElementFactory elementFactory = graph.getElementFactory();
// Containers for our subject, predicate, and object nodes
SubjectNode subject = null;
PredicateNode predicate = null;
ObjectNode object = null;
try {
// Create the subject using the file URI
subject = (SubjectNode) elementFactory.createResource(toURI());
} catch (GraphElementFactoryException graphElementFactoryException) {
throw new MetaDataException("Failed to create subject node for " +
getAbsolutePath(),
graphElementFactoryException);
}
// Create the RDF type predicate
predicate = GraphUtil.createPredicateFromURI(RDF.TYPE, elementFactory);
if (isDirectory()) {
try {
// If the file is a directory then set its type to a directory
object = GraphUtil.createObjectResource(
FileSystemVocab.getPredicate(FileSystemVocab.DIRECTORY_TYPE),
elementFactory);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.DIRECTORY_TYPE,
vocabularyException);
}
} else if (isHidden()) {
try {
// If the file is a hidden file then set its type to a hidden file
object = GraphUtil.createObjectResource(
FileSystemVocab.getPredicate(FileSystemVocab.HIDDEN_TYPE),
elementFactory);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.HIDDEN_TYPE,
vocabularyException);
}
} else if (!canWrite() && canRead()) {
try {
// If the file is read only then set its type to read only
object = GraphUtil.createObjectResource(
FileSystemVocab.getPredicate(FileSystemVocab.READ_ONLY_TYPE),
elementFactory);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.READ_ONLY_TYPE,
vocabularyException);
}
} else {
try {
// The default type is file
object = GraphUtil.createObjectResource(
FileSystemVocab.getPredicate(FileSystemVocab.FILE_TYPE),
elementFactory);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.FILE_TYPE,
vocabularyException);
}
}
// Add the type triple
GraphUtil.addTriple(subject, predicate, object, graph);
// Container for predicate URIs
URI predicateURI = null;
try {
// Obtain the filename predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.FILENAME);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.FILENAME,
vocabularyException);
}
// Create the filename predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI, elementFactory);
// Create the filename object
object = GraphUtil.createObjectLiteral(getName(), elementFactory);
// Add the filename triple
GraphUtil.addTriple(subject, predicate, object, graph);
if (isFile()) {
// Only files have extensions
try {
// Obtain the extension predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.EXTENSION);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.EXTENSION,
vocabularyException);
}
// Create the extension predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI,
elementFactory);
// Get the file name
String extension = getName();
if (extension.indexOf(".") >= 0) {
// Obtain the extension (if there is one)
extension = extension.substring(extension.lastIndexOf(".") + 1,
extension.length());
} else {
// If there is no extension then use the empty string
extension = "";
}
// Create the extension object
object = GraphUtil.createObjectLiteral(extension, elementFactory);
// Add the extension triple
GraphUtil.addTriple(subject, predicate, object, graph);
}
try {
// Obtain the path predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.PATH);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.PATH, vocabularyException);
}
// Create the path predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI, elementFactory);
// Create the path object
object = GraphUtil.createObjectResource(toURI(), elementFactory);
// Add the path triple
GraphUtil.addTriple(subject, predicate, object, graph);
try {
// Obtain the modified predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.MODIFIED);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.MODIFIED,
vocabularyException);
}
// Create the modified predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI, elementFactory);
// Create the modified object
object = GraphUtil.createObjectLiteral(asDate(lastModified()),
elementFactory);
// Add the modified triple
GraphUtil.addTriple(subject, predicate, object, graph);
try {
// Obtain the parent predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.PARENT);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.PARENT, vocabularyException);
}
// Create the parent predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI, elementFactory);
// Create the parent object
object = GraphUtil.createObjectResource(getParentFile().toURI(),
elementFactory);
// Add the parent triple
GraphUtil.addTriple(subject, predicate, object, graph);
if (isFile()) {
// Obtain the size of files
try {
// Obtain the modified predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.SIZE);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.SIZE, vocabularyException);
}
// Create the size predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI,
elementFactory);
// Create the size object
object = GraphUtil.createObjectLiteral("" + length(), elementFactory);
// Add the size triple
GraphUtil.addTriple(subject, predicate, object, graph);
}
try {
// Obtain the canRead predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.CAN_READ);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.CAN_READ,
vocabularyException);
}
// Create the canRead predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI, elementFactory);
// Create the canRead object
object = GraphUtil.createObjectLiteral("" + canRead(), elementFactory);
// Add the canRead triple
GraphUtil.addTriple(subject, predicate, object, graph);
try {
// Obtain the canWrite predicate URI
predicateURI = FileSystemVocab.getPredicate(FileSystemVocab.CAN_WRITE);
} catch (VocabularyException vocabularyException) {
throw new MetaDataException("Failed to find predicate for " +
FileSystemVocab.CAN_WRITE,
vocabularyException);
}
// Create the canWrite predicate
predicate = GraphUtil.createPredicateFromURI(predicateURI, elementFactory);
// Create the canWrite object
object = GraphUtil.createObjectLiteral("" + canWrite(), elementFactory);
// Add the canWrite triple
GraphUtil.addTriple(subject, predicate, object, graph);
// JNI implementations are required for the creation date, last accessed,
// owner and canExecute fields
}
if (log.isDebugEnabled()) {
log.debug("Completed obtaining metadata for file: " + getAbsolutePath());
}
return graph;
}
/**
* Converts the given date (as a long) to a string representation in the
* dateTime XSD datatype format.
*
* @param dateTime The date and time as a long
*
* @return The dateTime string in XSD schema format
*/
private String asDate(long dateTime) {
// Obtain a calendar object
Calendar calendar = Calendar.getInstance();
// Set the time of the calendar to the date time passed in
calendar.setTimeInMillis(dateTime);
// create a formatter to process the date/time representation
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
return formatter.format(calendar.getTime());
}
/**
* Closes a file that has been opened for metadata purposes. Effectively
* clears the graph and other resources that consume memory unnecessarily.
*
* @throws IOException
*/
public void close() {
// Close the graph
((GraphImpl) graph).close();
}
}