package org.skymaps; import java.io.BufferedReader; import java.io.File; import java.io.FilenameFilter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Vector; import java.util.TreeSet; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * The StarSearch Java program performs a search for data entries * conerning certain stars in text files in /smeidc/sk0/equ. The * entries that are located are outputted to text (.txt) files, one for each * star per camera and mode, in the directory of the user's choice. *

* The text files that are searched should contain data concerning stars * removed from sky maps. This program is meant to be a convenience utility * for locating and collating data concerning these removed stars. *

*

* StarSearch is meant to be called in the following manner (from * a console): *

*
* % java -cp /zshare/smei/java/common org.skymaps.StarSearch [Options] * star_name_1[:star_name_2:star_name_3:...] *
*

* Note that there may be a BASH alias for this program, such as * starsearch. *

*

* Options
* The following command-line options are allowed: *

*
*
*
-cs
*
Instructs StarSearch to perform a case-sensitive search. * This would force the program to match only those entries with star * names that are case-sensitively identical to the stars the user * specifies. By default, the search is case-insensitive.
*
-dest=dest_directory
*
Directs StarSearch to write text files to * dest_directory. This must be a valid directory, either * absolute or relative, and it must have write permissions enabled. * If this option is not specified, then the default write directory * is the user's current directory (the directory from which * StarSearch is called).
*
-file=star_name_file
*
Instructs StarSearch to parse the given file, * star_name_file, for additional star names. The star * names must be organized one per line in the specified file. Two or * more star names that appear on one line will collectively be treated * as one star name (which is obviously not desirable). Blank lines are * ignored. The default action should this option not be specified is * to only read in star names from the star name list at the command * prompt. This option may be specified more than once if more than * one star name file is to be supplied to StarSearch. This * option can also be used in conjunction with the star name list * following the options. *
-rdir=root_directory
*
Directs StarSearch to begin its search in * root_directory. It will then descend into its * subdirectories, which are specified in the initialization XML file * (more on this below), to search for text files to process. If this * option is not specified, then the default starting directory is * /smeidc/sky0/equ.
*
*
*

* If illegal or malformed command-line options are entered by the user, then * the program indicates the error and terminates normally. *

*

* Star Name List
* The list following the options is a colon separated list of star names. The * star names can have spaces within them, but they must be separated by * colons to be considered distinct. Star names cannot be repeated. If one * or more star names are repeated, then an error is generated. *

*

* The following is a list of examples of possible uses of options and star * lists: *

*
*
*
% java StarSearch
*
Prints the usage message and exits.
*
% java StarSearch HD 29763
*
Searches for the star HD 29763 in the default search * directory's subdirectories and outputs the resulting text files to the * user's current directory.
*
% java StarSearch -cs -rdir=/some/fake/directory * -dest=/another/fake/directory hd 29763
*
Searches for the star hd 29763 (case-sensitive) in the * subdirectories of /some/fake/directory and outputs the * resulting text files to /another/fake/directory.
*
% java StarSearch HD 29763:V* zet Tau : HD 74442
*
Searches for the stars HD 29763, * V* zet Tau, and HD 74442 in the default * search directory's subdirectories and outputs the resulting text * files to the user's current directory.
*
% java StarSearch hd 29763::v* zet tau:::: HD 74442: *
*
Same as the previous example
*
% java StarSearch -file=starnames.txt hd 29763::v* zet tau:::: * HD 74442:
*
Same as the previous example, except that additional star names * are inputted from the text file starnames.txt.
*
*
*

* Format of Inputted Text Files
* When StarSearch descends into a subdirectory, it searches only * within text (.txt) files that have filenames in the format * c(1+2+3)pnt_YYYY_DOY_HHMMSS.txt (case-insensitive), where * YYYY is the year, DOY is the day of the year, and HHMMSS is the hour, * minutes, and seconds of the date (this date should be in standard SMEI * format). Examples include c2pnt_2006_057_135219.txt, * C3PnT_2004_158_094551.TXT, and * c1PNT_2005_041_160854.tXt. *

*

* All inputted text files should have the same format. The first line is * a whitespace-separated list of column titles that describe the entries in * their respective columns, followed by lines containing entries for different * stars. The first entry should be the name of the star (11 characters long * maximum), and this name is compared against the names of the stars provided * by the user. If the names match, then the entire line is copied to its * respective output text file (depending on the name of the star to which it * matches). Examples of properly formatted input text files can be found * within the subdirectories of /smeidc/sky0/equ. *

*

* Format of Outputted Text Files
* The format of the outputted text files is identical to that of the * inputted text files, including the column title header line (the first * line of the inputted text files). The entries are sorted chronologically * by the date stored in each entry (the date has the standard SMEI format * YYYY_DOY_HHMMSS and is at character offset 54 (zero-based) from the * beginning of the line by default). Outputted file names have the filename * format starname_c(1+2+3)(e+s).txt, where (1+2+3) * is the camera number and (e+s) is the camera mode, either * engineering mode or scientific mode. *

*

* The XML Initialization File
* When StarSearch is run, its initialization file * starsearchinit.xml is parsed. This file should be located * in the same directory as StarSearch and has a corresponding * DTD file named starsearchinit.dtd. The initialization file * contains various kinds of information, but StarSearch only * parses information within the * <Directories></Directories> tag pair. This * holds entries corresponding to the subdirectories searched by * StarSearch, including the relative path of the subdirectory * from the starting search directory, the camera number it corresponds to * (either 1, 2, or 3), and the * mode of the camera (either e for engineering mode or * s for scientific mode). Subdirectories can be added or * removed by adding new Directory entries or removing them, * respectively. However, if the initialization file is modified, then it * must conform to its corresponding DTD, or unpredictable * errors may result. *

* * @author Jordan T. Vaughan * @version 1.1 * @see StarFormat */ public class StarSearch { /** * The default starting search directory */ public static final String DEFAULT_ROOT_DIR = "/smeidc/sky0/equ"; /** * The default output directory for writing text files */ public static final String DEFAULT_OUTPUT_DIR = "./"; private static final String RDIR_OPTION = "-rdir="; private static final String CS_OPTION = "-cs"; private static final String DEST_OPTION = "-dest="; private static final String FILE_OPTION = "-file="; /** * The path and name of the XML initialization file (which should be in * the same directory as the StarSearch .class file). Modify this value * (that is, recompile the code with a new value) if the directory of * the initialization file should change. */ public static final String INI_FILE = "/zshare/smei/java/common/org/" + "skymaps/starsearchinit.xml"; /** * The size of the star name field on a line of input text (the character * offset is zero by default) */ public static final int STAR_NAME_FIELD_SIZE = 11; /** * The character offset of the date entry in a line of input text */ public static final int DATE_OFFSET = 54; /** * The size of the date field, in characters */ public static final int DATE_SIZE = 15; /** * The starting method of the StarSearch program. The * command-line arguments are first parsed and checked for errors, then * the search is conducted. * * @param args An array of command-line argument strings. * @since 1.0 */ public static void main(String[] args) { // Relevant local variables. File rootDirectory = null; File destDirectory = null; boolean isCaseInsensitive = true; Vector starNameFiles = new Vector(); TreeSet starTree = new TreeSet(); HashMap> entryMap = null; Vector directories = new Vector(); // Are there any arguments? if(args.length == 0) { printUsageMessage(); return; } // Parse command-line options. int counter = 0; while(counter < args.length && args[counter].charAt(0) == '-') { if(args[counter].length() >= RDIR_OPTION.length() && args[counter].substring(0, RDIR_OPTION.length()). equalsIgnoreCase(RDIR_OPTION)) { // Setting the root directory for the search. if(rootDirectory != null) { System.out.println("ERROR: Root directory specified more" + " than once. Aborting.\n"); return; } args[counter] = args[counter].substring(RDIR_OPTION.length()); if(args[counter].length() == 0) { System.out.println("ERROR: No root search directory " + "given. Aborting.\n"); return; } rootDirectory = new File(args[counter]); if(!rootDirectory.exists()) { System.out.println("ERROR: Given directory does not " + "exist -- " + args[counter] + "\n"); return; } if(!rootDirectory.isDirectory()) { System.out.println("ERROR: Given directory is not a " + "directory -- " + args[counter] + "\n"); return; } } else if(args[counter].equalsIgnoreCase(CS_OPTION)) { // Setting the search to case-sensitive mode. if(!isCaseInsensitive) { System.out.println("ERROR: Case-sensitive search " + "specified more than once. Aborting.\n"); return; } isCaseInsensitive = false; } else if(args[counter].length() >= DEST_OPTION.length() && args[counter].substring(0, DEST_OPTION.length()). equalsIgnoreCase(DEST_OPTION)) { // Setting the destination directory for writing search // results. if(destDirectory != null) { System.out.println("ERROR: Output directory specified " + "more than once. Aborting.\n"); return; } args[counter] = args[counter].substring(DEST_OPTION.length()); if(args[counter].length() == 0) { System.out.println("ERROR: No output directory given. " + "Aborting.\n"); return; } destDirectory = new File(args[counter]); if(!destDirectory.exists()) { System.out.println("ERROR: Given directory does not " + "exist -- " + args[counter] + "\n"); return; } if(!destDirectory.isDirectory()) { System.out.println("ERROR: Given directory is not a " + "directory -- " + args[counter] + "\n"); return; } } else if(args[counter].length() >= FILE_OPTION.length() && args[counter].substring(0, FILE_OPTION.length()). equalsIgnoreCase(FILE_OPTION)) { // Reading in a file containing star names. args[counter] = args[counter].substring(FILE_OPTION.length()); if(args[counter].length() == 0) { System.out.println("ERROR: No star name file given. " + "Aborting.\n"); return; } File starNameFile = new File(args[counter]); if(!starNameFile.exists()) { System.out.println("ERROR: Given star name file does not "+ "exist -- " + args[counter] + "\n"); return; } if(!starNameFile.isFile()) { System.out.println("ERROR: Given star name file is not a "+ "file -- " + args[counter] + "\n"); return; } starNameFiles.add(starNameFile); } else { // Unrecognized command-line option. Display an error message. System.out.println("ERROR: Unrecognized option -- " + args[counter] + "\n"); return; } // Increment the counter argument. counter++; } // Create default directories if they were not already specified by // the user via the command line. if(rootDirectory == null) { rootDirectory = new File(DEFAULT_ROOT_DIR); if(!rootDirectory.exists()) { System.out.println("FATAL ERROR: Default root directory " + DEFAULT_ROOT_DIR + " does not exist.\nAborting.\n"); return; } if(!rootDirectory.isDirectory()) { System.out.println("FATAL ERROR: Default root directory " + DEFAULT_ROOT_DIR + " is not a directory.\n" + "Aborting.\n"); return; } } if(destDirectory == null) { destDirectory = new File(DEFAULT_OUTPUT_DIR); if(!destDirectory.exists()) { System.out.println("FATAL ERROR: Default output directory " + DEFAULT_OUTPUT_DIR + " does not exist.\nAborting.\n"); return; } if(!destDirectory.isDirectory()) { System.out.println("FATAL ERROR: Default output directory " + DEFAULT_OUTPUT_DIR + " is not a directory.\n" + "Aborting.\n"); return; } } // Parse star names. StringBuilder constructedStarName = new StringBuilder(); while(counter < args.length) { // Continue to build the current star name as a String. If a // colon is encountered, finish the current star name building and // add it to our collection of star names. while(args[counter].indexOf(':') != -1) { constructedStarName.append(args[counter].substring(0, args[counter].indexOf(':'))); args[counter] = args[counter].substring( args[counter].indexOf(':') + 1); if(constructedStarName.length() != 0) { if(!(isCaseInsensitive ? starTree.add(constructedStarName.toString(). toLowerCase().trim()): starTree.add(constructedStarName.toString().trim()))) { System.out.println("ERROR: Duplicate star name given" + " -- " + constructedStarName.toString() + "\n"); return; } constructedStarName.setLength(0); } } constructedStarName.append(args[counter] + " "); counter++; } // Handle leftover star name characters, if they exist. if(constructedStarName.length() != 0) { if(!(isCaseInsensitive ? starTree.add(constructedStarName.toString().toLowerCase(). trim()) : starTree.add(constructedStarName.toString().trim()))) { System.out.println("ERROR: Duplicate star name given -- " + constructedStarName.toString() + "\n"); return; } constructedStarName.setLength(0); } // If any star name files were given, read them in. for(File starNameFile: starNameFiles) { try { BufferedReader reader = new BufferedReader(new FileReader( starNameFile)); String line = reader.readLine().trim(); while(line != null) { if(line.length() > 0) { if(!(isCaseInsensitive ? starTree.add(line.toLowerCase()) : starTree.add(line))) { System.out.println("ERROR: Duplicate star name " + "given -- " + line + "\n"); return; } } line = reader.readLine(); } reader.close(); } catch(FileNotFoundException e) { // This should not occur. System.out.println("ERROR: File " + starNameFile + " does not exist. Skipping."); } catch(IOException e) { System.out.println("ERROR: An IO error occurred while reading"+ " from the file " + starNameFile + "\nSkipping."); } } // Do we have any stars to search for? if(starTree.size() == 0) { System.out.println("ERROR: No star names given."); printUsageMessage(); return; } /* Now that we have all the star names parsed, do the search. * Open the initialization file, parse the XML tree (while validating), * and retrieve the subdirectories that we will search. */ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); factory.setIgnoringComments(true); DocumentBuilder builder = null; try { builder = factory.newDocumentBuilder(); } catch(ParserConfigurationException e) { System.out.println("FATAL ERROR: Unable to instantiate an XML " + "parser to parse the\ninitialization file. Aborting.\n"); return; } Document rootNode = null; try { rootNode = builder.parse(new File(INI_FILE)); } catch(IOException e) { System.out.println("ERROR: An IO error occured while attempting " + "to read the initialization file.\nAborting.\n"); return; } catch(SAXException e) { System.out.println("ERROR: The initialization file is not a " + "well-formed XML file, or it\ndoes not conform to the " + "specifications provided in the associated DTD. Aborting.\n"); return; } // Read the Directory entries. NodeList directoryList = ((Element)rootNode.getDocumentElement(). getElementsByTagName("Directories").item(0)). getElementsByTagName("Directory"); for(counter = 0; counter < directoryList.getLength(); counter++) { Element directory = (Element)directoryList.item(counter); try { directories.add(new StarDirectory( directory.getAttribute("name"), Integer.parseInt(directory.getAttribute("camera")), directory.getAttribute("mode"))); } catch(NumberFormatException e) { System.out.println("ERROR: Initialization file contains a " + "Directory entry with an\ninvalid camera number. " + "Aborting.\n"); return; } catch(IllegalArgumentException e) { System.out.println("ERROR: Initialization file contains an " + "invalid Directory entry. The error follows:\n"); e.printStackTrace(); return; } } // Inform the user of what kind of search we're performing. System.out.print("\nPerforming a search for the stars\n "); for(String star: starTree) { System.out.print(star + " "); } System.out.print("\nfrom the base directory " + rootDirectory.getAbsolutePath() + " in the subdirectories\n "); for(counter = 0; counter < directories.size(); counter++) { System.out.print(directories.get(counter).getName() + " "); } System.out.println("\nThe output directory is " + destDirectory.getAbsolutePath() + " and the search will be " + (isCaseInsensitive ? "case-insensitive.\n" : "case-sensitive.\n")); /* Descend into the relevant subdirectories and search the files for * entries. */ for(counter = 0; counter < directories.size(); counter++) { File directory = new File(rootDirectory, directories.get(counter).getName()); String header = null; /* Does the directory exist within the starting directory? If not, * skip it. */ if(!directory.exists() || !directory.isDirectory()) { System.out.println(directory.getAbsolutePath() + " cannot be" + " found or is not a file. Skipping..."); continue; } /* Retrieve all files in the directory and create a new HashMap for * the star entries found within the files. Then iterate through * the files and search them for the star entries we are looking * for. */ File[] files = directory.listFiles(new StarFilenameFilter()); if(files == null) { System.out.println("ERROR: An IO error occurred while " + "attempting to access the\nfiles in subdirectory " + directory.getName() + ". Skipping..."); continue; } entryMap = new HashMap>(); System.out.println("Searching subdirectory " + directories.get(counter).getName() + " (" + files.length + " files)"); for(int j = 0; j < files.length; j++) { BufferedReader reader = null; try { /* Create the new file reader (buffered) and retrieve the * column titles (the "header") from the file. */ reader = new BufferedReader(new FileReader(files[j])); header = reader.readLine(); if(header == null) { reader.close(); continue; } /* Are we working with the new-style headers (starting with * semicolons) or the old-style headers (only one line of text * with the column titles on it)? */ if(header.charAt(0) == ';') { boolean nullLine = false; do { header = reader.readLine(); if(header == null) { nullLine = true; break; } } while(header.charAt(0) == ';'); if(nullLine) { continue; } } else { header = reader.readLine(); } /* Read each line and check to see if it belongs to a star * we are looking for. */ String line = header; while(line != null) { String starName = null; try { starName = line.substring(0, STAR_NAME_FIELD_SIZE). trim(); } catch(ArrayIndexOutOfBoundsException e) { continue; } /* Does the current line contain an entry for a star * we are looking for? Do the checking in a case- * sensitive or case-insensitive manner depending on * what the user desires. */ if((isCaseInsensitive ? starTree.contains(starName.toLowerCase()) : starTree.contains(starName))) { String lowercaseForm = starName.toLowerCase(); if(entryMap.containsKey(lowercaseForm)) { TreeSet oldSet = entryMap.get(lowercaseForm); oldSet.add(new StarEntry(line, line.substring(DATE_OFFSET, DATE_OFFSET + DATE_SIZE))); entryMap.put(lowercaseForm, oldSet); } else { TreeSet newSet = new TreeSet(); newSet.add(new StarEntry(line, line.substring(DATE_OFFSET, DATE_OFFSET + DATE_SIZE))); entryMap.put(starName.toLowerCase(), newSet); } } line = reader.readLine(); } reader.close(); } catch(FileNotFoundException e) { System.out.println("ERROR: This error should not occur, " + "but the file " + files[j].getAbsolutePath() + " does not exist. Skipping."); continue; } catch(IOException e) { System.out.println("ERROR: A general I/O error occurred " + "while attempting to read the file " + files[j].getAbsolutePath() + ". Aborting."); return; } } /* Now that the entry map has been filled with entries from this * directory, write the entries to files in the output directory. */ for(String starName: entryMap.keySet()) { StringBuilder outputFilename = new StringBuilder(); /* Begin with the name of the star with illegal filename * characters removed. */ for(int j = 0; j < starName.length(); j++) { char character = starName.charAt(j); if(character == ' ' || character == '\t') { outputFilename.append('_'); } else if(character == '*') { outputFilename.append('^'); } else { outputFilename.append(character); } } /* Append the rest of the filename and open a write stream to * it. */ outputFilename.append("_c" + directories.get(counter).getCamera() + directories.get(counter).getMode() + StarFilenameFilter.FILE_EXTENSION); PrintWriter writer = null; try { writer = new PrintWriter(new File( destDirectory, outputFilename.toString())); } catch(FileNotFoundException e) { System.out.println("ERROR: Cannot write results to the " + "file " + outputFilename.toString() + ". Skipping."); continue; } // Write the header and all entries for this star. writer.println(header); for(StarEntry entry: entryMap.get(starName)) { writer.println(entry.lineOfEntries); } writer.close(); // Tell the user that the file was written. System.out.println(" Wrote file: " + outputFilename.toString()); } } // All done! System.out.println("\nDone!"); } /** * Displays a usage message to the user on standard output. This should * only be displayed if an error occurs. * * @since 1.0 */ public static void printUsageMessage() { System.out.print( "Usage:\n" + " % starsearch [Options] star_name_1[:star_name_2:" + "star_name_3:...]\n\n" + "Options:\n" + " -cs Make star name search case sensitive" + " [default is\n" + " case-insensitive]\n" + " -dest=dest_directory Directory where outputted text files" + " will be written\n" + " [default is " + DEFAULT_OUTPUT_DIR + "]\n" + " -file=star_name_file Specifies a text file containing " + "star names,\n" + " one on each line in the file. This " + "option may be\n" + " specified more than once (duplicate " + "star names\n" + " not allowed).\n" + " -rdir=root_directory Base directory for the search, whose "+ "subdirectories\n" + " are searched for files [default=" + DEFAULT_ROOT_DIR + "]\n\n" + "Examples:\n" + " starsearch HD 29763\n" + " Searches for the star named HD 29763 in the default\n" + " search directory (" + DEFAULT_ROOT_DIR + ") and outputs\n" + " the results of the search to " + DEFAULT_OUTPUT_DIR + "/HD_29763.txt\n" + " starsearch HD 29763:V* zet tau\n" + " Searches the for stars named HD 29763 and V* zet tau in\n" + " the default search directory and outputs the results to\n" + " HD_29763.txt and V^_zet_tau.txt in the default output\n" + " directory.\n" + " starsearch -rdir=/smeidb -cs -dest=/home/soft/temp HD 29763\n"+ " Searches for HD 29763 (case-sensitive) starting in\n" + " /smeidb and writing the results to " + "/home/soft/temp/HD_29763.txt\n\n" + "Note Concerning Star Names:\n" + " Although any colon-separated list of star names can be\n" + " given, spaces and asterisks (*) in star names will be\n" + " replaced with underscores (_) and carats (^), respectfully,\n"+ " in output file names. No other characters are transformed." + "\n\n"); System.out.println(" Star files have titles of the form " + "c(1+2+3)pnt_YYYY_DOY_HHMMSS.txt,\n" + " and the output files have the form starname_c(1+2+3)(e+" + "s).txt."); } /* Represents a subdirectory from the starting search directory. This is * used to store information about the subdirectory that is read in from * the XML initialization file, such as the subdirectory's name, its * corresponding camera number (either 1, 2, or 3), and its corresponding * camera mode (either "e" for engineering mode or "s" for scientific * mode). The method names are self-explanatory. * * @author Jordan T. Vaughan * @since 1.0 */ private static class StarDirectory { public static final String MODE_E = "e"; public static final String MODE_S = "s"; private String name; private int camera; private String mode; public StarDirectory() { name = ""; camera = 1; mode = MODE_E; } public StarDirectory(String name, int camera, String mode) { this.name = name; if(camera < 1 || camera > 3) { throw new IllegalArgumentException("Invalid camera number " + "for Directory entry: " + camera); } this.camera = camera; if(!(mode.equals(MODE_E) || mode.equals(MODE_S))) { throw new IllegalArgumentException("Invalid camera mode for " + "Directory entry: " + mode); } this.mode = mode; } public int getCamera() { return camera; } public String getMode() { return mode; } public String getName() { return name; } public void setCamera(int camera) { if(camera < 1 || camera > 3) { throw new IllegalArgumentException("Invalid camera number " + "for Directory entry: " + camera); } this.camera = camera; } public void setMode(String mode) { if(!(mode.equals(MODE_E) || mode.equals(MODE_S))) { throw new IllegalArgumentException("Invalid camera mode for " + "Directory entry: " + mode); } this.mode = mode; } public void setName(String name) { if(name == null) { throw new NullPointerException(); } this.name = name; } } /* Represents a line from an inputted text file corresponding to a certain * star name. This is used to store lines of entries as strings and for * sorting by date in sorting data structures. The methods are self- * explanatory. * * @author Jordan T. Vaughan * @since 1.0 */ private static class StarEntry implements Comparable { public String lineOfEntries; public String date; public StarEntry(String lineOfEntries, String date) { this.lineOfEntries = lineOfEntries; this.date = date; } public int compareTo(StarEntry o) { return date.compareTo(o.date); } } /** * Filename filter used to determine which files in a given subdirectory * are valid as input text files. The format for these files is given * in the class documentation for StarSearch. The methods * are self-explanatory. * * @author Jordan T. Vaughan * @since 1.0 */ private static class StarFilenameFilter implements FilenameFilter { public static final String CAMERA1_FILE_PREFIX = "c1pnt_"; public static final String CAMERA2_FILE_PREFIX = "c2pnt_"; public static final String CAMERA3_FILE_PREFIX = "c3pnt_"; public static final String FILE_EXTENSION = ".txt"; public StarFilenameFilter() { } public boolean accept(File dir, String name) { if(name == null || name.length() == 0) { return false; } String prefix = name.substring(0, CAMERA1_FILE_PREFIX.length()); if(!(prefix.equalsIgnoreCase(CAMERA1_FILE_PREFIX) || prefix.equalsIgnoreCase(CAMERA2_FILE_PREFIX) || prefix.equalsIgnoreCase(CAMERA3_FILE_PREFIX))) { return false; } if(!java.util.regex.Pattern.matches( "\\d\\d\\d\\d_\\d\\d\\d_\\d\\d\\d\\d\\d\\d", name.substring(CAMERA1_FILE_PREFIX.length(), name.length() - FILE_EXTENSION.length()))) { return false; } if(!name.substring(name.length() - FILE_EXTENSION.length()). equalsIgnoreCase(FILE_EXTENSION)) { return false; } return true; } } }