Organisation X has a new directive:
The rules are:
To this end, we need to create a new class, called OrgXFileNamer, which will be a subclass of the abstract Xena class, FileNamer. The Xena FileNamer class is quite simple, with only three abstract methods to be overriden:
We will create the OrgXFileNamer class in a new file called OrgXFileNamer.java, in the same directory as the OrgXPlugin.java file from the previous step.
Here is the skeleton of the OrgXFileNamer file, with the getName and makeFileFilter methods filled in:
package au.gov.naa.digipres.xena.demo.orgx;
import java.io.File;
import java.io.FileFilter;
import org.xml.sax.XMLReader;
import au.gov.naa.digipres.xena.kernel.XenaException;
import au.gov.naa.digipres.xena.kernel.XenaInputSource;
import au.gov.naa.digipres.xena.kernel.filenamer.FileNamer;
public class OrgXFileNamer extends FileNamer {
@Override String getName() {
return "Org X FileNamer";
}
@Override
public File makeNewXenaFile(XMLReader normaliser, XenaInputSource input, String extension, File destinationDir) throws XenaException {
// TODO Auto-generated method stub
return null;
}
@Override
public FileFilter makeFileFilter(String extension) {
// Return default FileFilter
return FileNamerManager.DEFAULT_FILE_FILTER;
}
}
Before we can implement the makeNewXenaFile method we need to determine how we are going to load the information we are going to use in the filename. We will be changing the way we retrieve this information in step 10 of this tutorial, so we will make it as modular as possible.
For this step of the How To we are only interested in the getUserName and getDepartmentCode methods, as these are the pieces of information that we will be inserting into our filenames.
Note: The InfoProvider interface will be implemented in a different way in step 10.
Here is the InfoProvider interface:
package au.gov.naa.digipres.xena.demo.orgx;
import java.io.File;
public interface InfoProvider {
public String getUserName();
public String getDepartmentCode();
public String getDepartmentName();
public boolean isInsertTimestamp();
public File getHeaderFile();
}
We will create a new file called InfoProvider.java in the same directory as OrgXFileNamer.java
Our implementation of the InfoProvider interface for this step will be called DemoInfoProvider, so we will create a file called DemoInfoProvider.java in the same directory as OrgXFileNamer.java and InfoProvider.java.
Here is the skeleton code for this class, with default implementations of our methods:
package au.gov.naa.digipres.xena.demo.orgx;
import java.io.File;
public class DemoInfoProvider implements InfoProvider {
public String getUserName() {
// TODO: Implement this method
return null;
}
public String getDepartmentCode() {
// TODO: Implement this method
return null;
}
public String getDepartmentName() {
return null;
}
public File getHeaderFile() {
return null;
}
public boolean isInsertTimestamp() {
return false;
}
}
We want to be able to see how different user names and department codes affect the filename, but we don't want to have to keep changing the code and we also want the code to be as simple as possible. The easiest way to accomplish this is to define a few options for the user names and department codes and use a random number generator to choose which options are inserted into the filename. We will seed our random number generator with a specific number (1234).
Here are the user name and department code options and the implementations of the getUserName and getDepartmentName methods:
private String userName;
private String departmentCode;
private String randomUserNames[] = {"Homer", "Karl", "Kenny", "Monty Burns", "Smithers"};
private String randomDepartmentCodes[] = {"S7G", "S7A", "COR", "ADM"};
private Random random = new Random(1234);
/**
* Return the username if it is set, or a random one from randomUserNames if it is not.
*/
public String getUserName() {
if (userName == null) {
userName = randomUserNames[random.nextInt(randomUserNames.length)];
}
return userName;
}
/**
* Return the departmentCode if it is set, or a random one from randomDepartmentCodes if it is not.
* @return the department code.
*/
public String getDepartmentCode() {
if (departmentCode == null) {
departmentCode = randomDepartmentCodes[random.nextInt(randomDepartmentCodes.length)];
}
return departmentCode;
}
So we have our InfoProvider interface and an implementation that will be used in this step.
Now we have to use the InfoProvider to construct our file names. So we will return to the OrgXFileNamer.java file to implement the makeNewXenaFile method.
1. Define a DemoInfoProvider, which we will use to obtain our randomised user name and department code.
2. Include a setInfoProvider method, so that we initialise which InfoProvider we are using at runtime.
3. Piece together the various components of the filename (from our DemoInfoProvider and the given XenaInputSource) to create a new file with this filename in the given directory.
Here is the finished OrgXFileNamer.java file:
package au.gov.naa.digipres.xena.demo.orgx;
import java.io.File;
import java.io.FileFilter;
import java.text.DecimalFormat;
import au.gov.naa.digipres.xena.kernel.XenaInputSource;
import au.gov.naa.digipres.xena.kernel.filenamer.AbstractFileNamer;
import au.gov.naa.digipres.xena.kernel.filenamer.FileNamerManager;
import au.gov.naa.digipres.xena.kernel.normalise.AbstractNormaliser;
public class OrgXFileNamer extends AbstractFileNamer {
private InfoProvider myInfoProvider = null;
private static char SEPARATOR_CHAR = '_';
public InfoProvider getInfoProvider() {
return myInfoProvider;
}
public void setInfoProvider(InfoProvider infoProvider) {
myInfoProvider = infoProvider;
}
@Override
public String getName() {
return "Org X FileNamer";
}
@Override
public File makeNewXenaFile(XenaInputSource xis, AbstractNormaliser normaliser, File destinationDir) {
String systemId = xis.getSystemId();
int startOfFileName = systemId.lastIndexOf('/');
String noSlashFileName = systemId.substring(startOfFileName == -1 ? 0 : startOfFileName);
startOfFileName = noSlashFileName.lastIndexOf('\\');
int id = 0;
DecimalFormat idFormatter = new DecimalFormat("0000");
//now to make an insanely long file name with all this stuff...
String outputFileName =
noSlashFileName + SEPARATOR_CHAR + getInfoProvider().getUserName() + SEPARATOR_CHAR + getInfoProvider().getDepartmentCode() + SEPARATOR_CHAR
+ idFormatter.format(id) + "." + FileNamerManager.DEFAULT_EXTENSION;
File outputFile = new File(destinationDir, outputFileName);
while (outputFile.exists()) {
outputFileName =
noSlashFileName + SEPARATOR_CHAR + getInfoProvider().getUserName() + SEPARATOR_CHAR + getInfoProvider().getDepartmentCode()
+ SEPARATOR_CHAR + idFormatter.format(++id) + "." + FileNamerManager.DEFAULT_EXTENSION;
outputFile = new File(destinationDir, outputFileName);
}
return outputFile;
}
@Override
public FileFilter makeFileFilter() {
return FileNamerManager.DEFAULT_FILE_FILTER;
}
}
Now that we have a FileNamer we need to ensure it is loaded in our OrgXPlugin. We will need to add the getFileNamers method in the OrgXPlugin.java file:
@Override
public List<AbstractFileNamer> getFileNamers() {
List<AbstractFileNamer> fileNamerList = new ArrayList<AbstractFileNamer>();
fileNamerList.add(new OrgXFileNamer());
return fileNamerList;
}
We have only developed one FileNamer. If it is loaded into Xena, it will automatically be used as the FileNamer for all normalised files. If more than one FileNamer is loaded then we would need to specify which one is to be used. We will test the OrgXFileNamer using the NormaliseTester we developed in step 4. We will modify the NormaliseTester.java file to load the OrgX plugin instead of the Foo plugin:
public class NormaliseTester {
public static void main(String[] argv) throws XenaException, IOException {
Xena xena = new Xena();
// our foo jar will already be on the class path, so load it by name...
Vector<String> pluginList = new Vector<String>();
pluginList.add("au.gov.naa.digipres.xena.demo.orgx.OrgXPlugin");
xena.loadPlugins(pluginList);
// set the base path to be the current working directory
xena.setBasePath(System.getProperty("user.dir"));
System.out.println(System.getProperty("user.dir"));
// create the new input source
File f = new File("../../../data/example_file.foo");
XenaInputSource xis = new XenaInputSource(f);
// guess its type
Guess fooGuess = xena.getBestGuess(xis);
//print the guess...
System.out.println("Here is the best guess returned by Xena: ");
System.out.println(fooGuess.toString());
System.out.println("-----------------------------------------");
// normalise the file!
NormaliserResults results = xena.normalise(xis);
System.out.println("Here are the results of the normalisation:");
System.out.println(results.getResultsDetails());
System.out.println("-----------------------------------------");
}
}
As we are not normalising our file with the Binary Normaliser, we are only interested in the name of the normalised file. Our user name and deparment code are randomised, so we cannot know the exact filenames we will get; running the NormaliserTester twice should produce two different output filenames:
# java -cp orgx.jar;../../../xena/xena.jar au.gov.naa.digipres.xena.demo.orgx.test.NormaliseTester
/home/dpuser/workspace/plugin-howto/07_file_namer/orgx_plugin/dist
Here is the best guess returned by Xena:
Guess... type: Binary
possible: Unknown
dataMatch:Unknown
magicNumber: Unknown
extensionMatch: Unknown
mimeMatch: Unknown
certain: Unknown
priority: LOW
-----------------------------------------
Here are the results of the normalisation:
Normalisation successful.
The input source name file:/home/dpuser/workspace/plugin-howto/07_file_namer/orgx_plugin/dist/../../../data/example_file.foo
normalised to: example_file.foo_Monty Burns_S7G_0000.xena
with normaliser: "Binary"
to the folder: /home/dpuser/workspace/plugin-howto/07_file_namer/orgx_plugin/dist
and the Xena id is: file:/../../../data/example_file.foo
-----------------------------------------
# java -cp orgx.jar;../../../xena/xena.jar au.gov.naa.digipres.xena.demo.orgx.test.NormaliseTester
/home/dpuser/workspace/plugin-howto/07_file_namer/orgx_plugin/dist
Here is the best guess returned by Xena:
Guess... type: Binary
possible: Unknown
dataMatch:Unknown
magicNumber: Unknown
extensionMatch: Unknown
mimeMatch: Unknown
certain: Unknown
priority: LOW
-----------------------------------------
Here are the results of the normalisation:
Normalisation successful.
The input source name file:/home/dpuser/workspace/plugin-howto/07_file_namer/orgx_plugin/dist/../../../data/example_file.foo
normalised to: example_file.foo_Homer_S7A_0000.xena
with normaliser: "Binary"
to the folder: /home/dpuser/workspace/plugin-howto/07_file_namer/orgx_plugin/dist
and the Xena id is: file:/../../../data/example_file.foo
-----------------------------------------
Now that we have control over the names of our normalised files it's time move on to step 10 and decide what goes into the metadata which wraps our normalised data.