/* ==================================================================== * Limited Evaluation License: * * This software is open source, but licensed. The license with this package * is an evaluation license, which may not be used for productive systems. If * you want a full license, please contact us. * * The exclusive owner of this work is the OpenRate project. * This work, including all associated documents and components * is Copyright of the OpenRate project 2006-2015. * * The following restrictions apply unless they are expressly relaxed in a * contractual agreement between the license holder or one of its officially * assigned agents and you or your organisation: * * 1) This work may not be disclosed, either in full or in part, in any form * electronic or physical, to any third party. This includes both in the * form of source code and compiled modules. * 2) This work contains trade secrets in the form of architecture, algorithms * methods and technologies. These trade secrets may not be disclosed to * third parties in any form, either directly or in summary or paraphrased * form, nor may these trade secrets be used to construct products of a * similar or competing nature either by you or third parties. * 3) This work may not be included in full or in part in any application. * 4) You may not remove or alter any proprietary legends or notices contained * in or on this work. * 5) This software may not be reverse-engineered or otherwise decompiled, if * you received this work in a compiled form. * 6) This work is licensed, not sold. Possession of this software does not * imply or grant any right to you. * 7) You agree to disclose any changes to this work to the copyright holder * and that the copyright holder may include any such changes at its own * discretion into the work * 8) You agree not to derive other works from the trade secrets in this work, * and that any such derivation may make you liable to pay damages to the * copyright holder * 9) You agree to use this software exclusively for evaluation purposes, and * that you shall not use this software to derive commercial profit or * support your business or personal activities. * * This software is provided "as is" and any expressed or impled warranties, * including, but not limited to, the impled warranties of merchantability * and fitness for a particular purpose are disclaimed. In no event shall * The OpenRate Project or its officially assigned agents be liable to any * direct, indirect, incidental, special, exemplary, or consequential damages * (including but not limited to, procurement of substitute goods or services; * Loss of use, data, or profits; or any business interruption) however caused * and on theory of liability, whether in contract, strict liability, or tort * (including negligence or otherwise) arising in any way out of the use of * this software, even if advised of the possibility of such damage. * This software contains portions by The Apache Software Foundation, Robert * Half International. * ==================================================================== */ package OpenRate.adapter.file; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import org.apache.oro.io.GlobFilenameFilter; import org.apache.oro.text.GlobCompiler; import OpenRate.CommonConfig; import OpenRate.OpenRate; import OpenRate.adapter.AbstractInputAdapter; import OpenRate.configurationmanager.ClientManager; import OpenRate.configurationmanager.IEventInterface; import OpenRate.exception.InitializationException; import OpenRate.exception.ProcessingException; import OpenRate.logging.LogUtil; import OpenRate.utils.PropertyUtils; import OpenRate.record.FlatRecord; import OpenRate.record.HeaderRecord; import OpenRate.record.IRecord; import OpenRate.record.TrailerRecord; /** * Generic Flat File InputAdapter (Non transactional Version) The basic function * of this flat file input adapter is to facilitate a reading of a flat file in * the batches, instead of reading a whole file in a single fetch. * * The file input adapter scans for files, and when found, opens them, reads * them and turns them into batches to maintain the load on the pipeline. * * Scanning and Processing ----------------------- * * The basic scanning and processing loop looks like this: - The loadBatch() * method is called regularly by the execution model, regardless of if there is * work in progress or not. - If we are not processing a file, we are allowed to * scan for a new file to process - If we are allowed to look for a new file to * process, we do this: - getInputAvailable() Scan to see if there is any work * to do - assignInput() marks the file as being in processing if we find work * to do open the input stream - Calculate the file names from the base name - * Open the file reader - Inject the synthetic HeaderRecord into the stream as * the first record to synchronise the processing down the pipe * * - If we are processing a stream, we do: - Read the records in from the * stream, creating a basic "FlatRecord" for each record we have read - When we * have finished reading the batch (either because we have reached the batch * limit or because there are no more records to read) call procValidRecord(), * which allows the user to perform preparation of the record (for example, * creating the user defined record from the generic FlatRecord, or performing * record compression on the incoming stream) - See if the file reader has run * out of records. It it has, this is the end of the stream. If it is the end of * the stream, we do: - Inject a trailer record into the stream - close the * input stream and reset the "file in processing" flag so that we can scan for * more files */ public abstract class FlatFileNTInputAdapter extends AbstractInputAdapter implements IEventInterface { // The buffer size is the size of the buffer in the buffered reader private static final int BUF_SIZE = 65536; // This is the locally cached base name that we have recovered from the // file name private static String IntBaseName; private String InputFilePath = null; private String DoneFilePath = null; private String ErrFilePath = null; private String InputFilePrefix = null; private String DoneFilePrefix = null; private String ErrFilePrefix = null; private String InputFileSuffix = null; private String DoneFileSuffix = null; private String ErrFileSuffix = null; // This tells us if we should look for a file to open // or continue reading from the one we have private boolean InputStreamOpen = false; // used to track the status of the stream processing private int InputRecordNumber = 0; // Used for simulating the transaction manager statistics private long TransactionStart = 0; private long TransactionEnd = 0; /* * Reader is initialized in the init() method and is kept open for loadBatch() * calls and then closed in cleanup(). This facilitates batching of input. */ private BufferedReader reader; // Used as the processing prefix private String ProcessingPrefix; // List of Services that this Client supports private static final String SERVICE_I_PATH = "InputFilePath"; private static final String SERVICE_D_PATH = "DoneFilePath"; private static final String SERVICE_E_PATH = "ErrFilePath"; private static final String SERVICE_I_PREFIX = "InputFilePrefix"; private static final String SERVICE_D_PREFIX = "DoneFilePrefix"; private static final String SERVICE_E_PREFIX = "ErrFilePrefix"; private static final String SERVICE_I_SUFFIX = "InputFileSuffix"; private static final String SERVICE_D_SUFFIX = "DoneFileSuffix"; private static final String SERVICE_E_SUFFIX = "ErrFileSuffix"; private static final String SERVICE_PROCPREFIX = "ProcessingPrefix"; /** * Default Constructor */ public FlatFileNTInputAdapter() { super(); } // ----------------------------------------------------------------------------- // --------------- Start of inherited Input Adapter functions ------------------ // ----------------------------------------------------------------------------- /** * Initialise the module. Called during pipeline creation. Initialise input * adapter. sets the filename to use & initialises the file reader. * * @param PipelineName The name of the pipeline this module is in * @param ModuleName The module symbolic name of this module * @throws OpenRate.exception.InitializationException */ @Override public void init(String PipelineName, String ModuleName) throws InitializationException { String ConfigHelper; // Register ourself with the client manager super.init(PipelineName, ModuleName); // Now we load the properties and use the event interface to initialise // the adapter. Note that this architecture will change to be completely // event driven in the near future. ConfigHelper = initGetInputFilePath(); processControlEvent(SERVICE_I_PATH, true, ConfigHelper); ConfigHelper = initGetDoneFilePath(); processControlEvent(SERVICE_D_PATH, true, ConfigHelper); ConfigHelper = initGetErrFilePath(); processControlEvent(SERVICE_E_PATH, true, ConfigHelper); ConfigHelper = initGetInputFilePrefix(); processControlEvent(SERVICE_I_PREFIX, true, ConfigHelper); ConfigHelper = initGetDoneFilePrefix(); processControlEvent(SERVICE_D_PREFIX, true, ConfigHelper); ConfigHelper = initGetErrFilePrefix(); processControlEvent(SERVICE_E_PREFIX, true, ConfigHelper); ConfigHelper = initGetInputFileSuffix(); processControlEvent(SERVICE_I_SUFFIX, true, ConfigHelper); ConfigHelper = initGetDoneFileSuffix(); processControlEvent(SERVICE_D_SUFFIX, true, ConfigHelper); ConfigHelper = initGetErrFileSuffix(); processControlEvent(SERVICE_E_SUFFIX, true, ConfigHelper); ConfigHelper = initGetProcPrefix(); processControlEvent(SERVICE_PROCPREFIX, true, ConfigHelper); // Check the file name scanning variables, throw initialisation exception // if something is wrong. initFileName(); } /** * loadBatch() is called regularly by the framework to either process records * or to scan for work to do, depending on whether we are already processing * or not. * * @return * @throws OpenRate.exception.ProcessingException */ @Override protected Collection<IRecord> loadBatch() throws ProcessingException { String tmpFileRecord; String procName = null; String baseName; int NumberOfInputFiles; Collection<IRecord> Outbatch; int ThisBatchCounter = 0; // The Record types we will have to deal with HeaderRecord tmpHeader; TrailerRecord tmpTrailer; FlatRecord tmpDataRecord; IRecord batchRecord; Outbatch = new ArrayList<>(); // This layer deals with opening the stream if we need to if (InputStreamOpen == false) { // There is a file available, so open it and rename it to // show that we are doing something NumberOfInputFiles = assignInput(); if (NumberOfInputFiles > 0) { // Now that we have the file name, try to open it from // the renamed file provided by assignInput try { // Start time for the statistics TransactionStart = System.currentTimeMillis(); // Get the name to work on baseName = GetBaseName(); procName = getProcFilePath(baseName); reader = new BufferedReader(new FileReader(procName), BUF_SIZE); InputStreamOpen = true; InputRecordNumber = 0; // Inject a stream header record into the stream tmpHeader = new HeaderRecord(); tmpHeader.setStreamName(baseName); // Increment the stream counter incrementStreamCount(); // Pass the header to the user layer for any processing that // needs to be done tmpHeader = procHeader(tmpHeader); Outbatch.add(tmpHeader); ThisBatchCounter++; } catch (FileNotFoundException exFileNotFound) { getPipeLog().error( "Application is not able to read file <" + procName + ">"); throw new ProcessingException("Application is not able to read file <" + procName + ">", exFileNotFound, getSymbolicName()); } } else { // No work to do - return the empty batch return Outbatch; } } if (InputStreamOpen) { try { // read from the file and prepare the batch while ((reader.ready()) & (ThisBatchCounter < batchSize)) { ThisBatchCounter++; tmpFileRecord = reader.readLine(); tmpDataRecord = new FlatRecord(tmpFileRecord, InputRecordNumber); InputRecordNumber++; // Call the user layer for any processing that needs to be done batchRecord = procValidRecord(tmpDataRecord); // Add the prepared record to the batch Outbatch.add(batchRecord); } // see the reason that we closed if (reader.ready() == false) { // we have finished InputStreamOpen = false; // get any pending records that are in the input handler batchRecord = purgePendingRecord(); // Add the prepared record to the batch, because of record compression // we may receive a null here. If we do, don't bother adding it if (batchRecord != null) { InputRecordNumber++; Outbatch.add(batchRecord); } //close the input file closeStream(); shutdownStreamProcessOK(); // Inject a stream header record into the stream tmpTrailer = new TrailerRecord(); tmpTrailer.setStreamName(GetBaseName()); // Pass the trailer to the user layer for any processing that // needs to be done tmpTrailer = procTrailer(tmpTrailer); Outbatch.add(tmpTrailer); ThisBatchCounter++; // print some statistics TransactionEnd = System.currentTimeMillis(); OpenRate.getOpenRateStatsLog().info("Stream closed"); OpenRate.getOpenRateStatsLog().info("Statistics: Records <" + InputRecordNumber + ">"); OpenRate.getOpenRateStatsLog().info( " Duration <" + (TransactionEnd - TransactionStart) + "> ms"); OpenRate.getOpenRateStatsLog().info( " Speed <" + ((InputRecordNumber * 1000) / (TransactionEnd - TransactionStart)) + "> records /sec"); } } catch (IOException ex) { getPipeLog().fatal("Error reading input file"); } } return Outbatch; } /** * Closes down the input stream after all the input has been collected * * @throws OpenRate.exception.ProcessingException */ public void closeStream() throws ProcessingException { String procName; try { reader.close(); } catch (IOException exFileNotFound) { procName = getProcFilePath(GetBaseName()); getPipeLog().error("Application is not able to close file <" + procName + ">"); throw new ProcessingException("Application is not able to read file <" + procName + ">", exFileNotFound, getSymbolicName()); } } /** * This is called when a data record is encountered. You should do any normal * processing here. * * @param r The record we are working on * @return The processed record * @throws ProcessingException */ public abstract IRecord procValidRecord(FlatRecord r) throws ProcessingException; /** * This is called when a data record with errors is encountered. You should do * any processing here that you have to do for error records, e.g. statistics, * special handling, even error correction! * * @param r The record we are working on * @return The processed record * @throws ProcessingException */ public abstract IRecord procErrorRecord(FlatRecord r) throws ProcessingException; /** * Allows any records to be purged at the end of a file * * @return The pending record */ public IRecord purgePendingRecord() { // default - do nothing return null; } // ----------------------------------------------------------------------------- // ------------- Start of inherited IEventInterface functions ------------------ // ----------------------------------------------------------------------------- /** * processControlEvent is the event processing hook for the External Control * Interface (ECI). This allows interaction with the external world. * * @param Command The command that we are to work on * @param Init True if the pipeline is currently being constructed * @param Parameter The parameter value for the command * @return The result message of the operation */ @Override public String processControlEvent(String Command, boolean Init, String Parameter) { int ResultCode = -1; if (Command.equalsIgnoreCase(SERVICE_I_PATH)) { if (Init) { InputFilePath = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return InputFilePath; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_D_PATH)) { if (Init) { DoneFilePath = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return DoneFilePath; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_E_PATH)) { if (Init) { ErrFilePath = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return ErrFilePath; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_I_PREFIX)) { if (Init) { InputFilePrefix = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return InputFilePrefix; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_D_PREFIX)) { if (Init) { DoneFilePrefix = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return DoneFilePrefix; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_E_PREFIX)) { if (Init) { ErrFilePrefix = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return ErrFilePrefix; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_I_SUFFIX)) { if (Init) { InputFileSuffix = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return InputFileSuffix; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_D_SUFFIX)) { if (Init) { DoneFileSuffix = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return DoneFileSuffix; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_E_SUFFIX)) { if (Init) { ErrFileSuffix = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return ErrFileSuffix; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (Command.equalsIgnoreCase(SERVICE_PROCPREFIX)) { if (Init) { ProcessingPrefix = Parameter; ResultCode = 0; } else { if (Parameter.equals("")) { return ProcessingPrefix; } else { return CommonConfig.NON_DYNAMIC_PARAM; } } } if (ResultCode == 0) { getPipeLog().debug(LogUtil.LogECIPipeCommand(getSymbolicName(), getPipeName(), Command, Parameter)); return "OK"; } else { // This is not our event, pass it up the stack return super.processControlEvent(Command, Init, Parameter); } } /** * registerClientManager registers this class as a client of the ECI listener * and publishes the commands that the plug in understands. The listener is * responsible for delivering only these commands to the plug in. * * @throws OpenRate.exception.InitializationException */ @Override public void registerClientManager() throws InitializationException { // Set the client reference and the base services first super.registerClientManager(); //Register services for this Client ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_I_PATH, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_D_PATH, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_E_PATH, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_I_PREFIX, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_D_PREFIX, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_E_PREFIX, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_I_SUFFIX, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_D_SUFFIX, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_E_SUFFIX, ClientManager.PARAM_NONE); ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_PROCPREFIX, ClientManager.PARAM_NONE); } // ----------------------------------------------------------------------------- // ------------------------ Start of custom functions -------------------------- // ----------------------------------------------------------------------------- /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetInputFilePath() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_I_PATH); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetDoneFilePath() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_D_PATH); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetErrFilePath() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_E_PATH); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetInputFilePrefix() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_I_PREFIX); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetDoneFilePrefix() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_D_PREFIX); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetErrFilePrefix() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_E_PREFIX); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetInputFileSuffix() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_I_SUFFIX); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetDoneFileSuffix() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_D_SUFFIX); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetErrFileSuffix() throws InitializationException { String tmpFile; tmpFile = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValue(getPipeName(), getSymbolicName(), SERVICE_E_SUFFIX); return tmpFile; } /** * Temporary function to gather the information from the properties file. Will * be removed with the introduction of the new configuration model. */ private String initGetProcPrefix() throws InitializationException { String tmpProcPrefix; tmpProcPrefix = PropertyUtils.getPropertyUtils().getBatchInputAdapterPropertyValueDef(getPipeName(), getSymbolicName(), SERVICE_PROCPREFIX, "tmp"); return tmpProcPrefix; } /** * Checks the file name from the input parameters. Called by init() so that * derived classes can still reuse most of the functionality provided by this * adapter and selectively change only the logic to pickup file for * processing. * * The method checks for validity of the input parameters that have been * configured, for example if the directory does not exist, an exception will * be thrown. * * Two methods of finding the file are supported: 1) You can specify a file * name and only that file will be read 2) You can specify a file path and a * regex prefix and suffix */ private void initFileName() throws InitializationException { File dir; /* * Validate the inputs we have received. We must end up with three * dustinct paths for input done and error files. We detect this by * checking the sum of the paramters. */ // Set default values if (InputFilePath == null) { InputFilePath = "."; message = "Input file path not set. Defaulting to <.>."; getPipeLog().warning(message); } // is the input file path valid? dir = new File(InputFilePath); if (!dir.isDirectory()) { message = "Input file path <" + InputFilePath + "> does not exist or is not a directory"; getPipeLog().fatal(message); throw new InitializationException(message, getSymbolicName()); } if (DoneFilePath == null) { DoneFilePath = "."; message = "Done file path not set. Defaulting to <.>."; getPipeLog().warning(message); } // is the input file path valid? dir = new File(DoneFilePath); if (!dir.isDirectory()) { message = "Done file path <" + DoneFilePath + "> does not exist or is not a directory"; getPipeLog().fatal(message); throw new InitializationException(message, getSymbolicName()); } if (ErrFilePath == null) { ErrFilePath = "."; message = "Error file path not set. Defaulting to <.>."; getPipeLog().warning(message); } // is the input file path valid? dir = new File(ErrFilePath); if (!dir.isDirectory()) { message = "Error file path <" + ErrFilePath + "> does not exist or is not a directory"; getPipeLog().fatal(message); throw new InitializationException(message, getSymbolicName()); } // Check that there is some variance in what we have received if ((DoneFilePath + DoneFilePrefix + DoneFileSuffix).equals(ErrFilePath + ErrFilePrefix + ErrFileSuffix)) { // These look suspiciously similar message = "Done file and Error file cannot be the same"; getPipeLog().fatal(message); throw new InitializationException(message, getSymbolicName()); } // Check that there is some variance in what we have received if ((InputFilePath + InputFilePrefix + InputFileSuffix).equals(ErrFilePath + ErrFilePrefix + ErrFileSuffix)) { // These look suspiciously similar message = "Input file and Error file cannot be the same"; getPipeLog().fatal(message); throw new InitializationException(message, getSymbolicName()); } // Check that there is some variance in what we have received if ((DoneFilePath + DoneFilePrefix + DoneFileSuffix).equals(InputFilePath + InputFilePrefix + InputFileSuffix)) { // These look suspiciously similar message = "Input file and Input file cannot be the same"; getPipeLog().fatal(message); throw new InitializationException(message, getSymbolicName()); } } // ----------------------------------------------------------------------------- // ---------------------- Start stream handling functions ---------------------- // ----------------------------------------------------------------------------- /** * Selects input from the pending list for processing and marks it as being in * processing. Assign the FileReader object to the chosen file Rename the * input to the temp name * * @return The number of files assigned * @throws OpenRate.exception.ProcessingException */ public int assignInput() throws ProcessingException { String procName; String[] FileNames; File dir; FilenameFilter filter; int FilesAssigned = 0; // This is the current filename we are working on String fileName; String baseName; // get the first file name from the directory that matches the dir = new File(InputFilePath); filter = new GlobFilenameFilter(InputFilePrefix + "*" + InputFileSuffix, GlobCompiler.STAR_CANNOT_MATCH_NULL_MASK); FileNames = dir.list(filter); // if we have a file, add it to the list of transaction files if (FileNames.length > 0) { // get the first file in the list fileName = FileNames[0]; FilesAssigned = 1; baseName = fileName.replaceAll("^" + InputFilePrefix, ""); baseName = baseName.replaceAll(InputFileSuffix + "$", ""); getPipeLog().info("File base name is <" + baseName + ">"); // Create the new transaction to hold the information. This is done in // The transactional layer - we just trigger it here SetBaseName(baseName); procName = getProcFilePath(baseName); fileName = getInputFilePath(baseName); // rename the input file to show that its our little piggy now File f = new File(fileName); f.renameTo(new File(procName)); } return FilesAssigned; } /** * shutdownStreamProcessOK closes down the processing and renames the input * file to show that we have done with it. It then completes the transaction * from the point of view of the Transaction Manager. This represents the * successful completion of the transaction. */ public void shutdownStreamProcessOK() { String procName; String doneName; String baseName; // get the file information for the transaction baseName = GetBaseName(); // Calculate the part of the name that will be constant // during the processing doneName = InputFilePath + System.getProperty("file.separator") + DoneFilePrefix + baseName + DoneFileSuffix; procName = getProcFilePath(baseName); // rename the input file to show that it is no longer under the TMs control File f = new File(procName); f.renameTo(new File(doneName)); } /** * shutdownStreamProcessERR closes down the processing and renames the input * file to show that we have done with it. It then completes the transaction * from the point of view of the Transaction Manager. This represents the * failed completion of the transaction, and should leave everything as it was * before the transaction started. */ public void shutdownStreamProcessERR() { String procName; String origName; String baseName; // get the file information for the transaction baseName = GetBaseName(); // Calculate the part of the name that will be constant // during the processing origName = InputFilePath + System.getProperty("file.separator") + InputFilePrefix + baseName + InputFileSuffix; procName = getProcFilePath(baseName); // rename the input file to show that it is no longer under the TMs control File f = new File(procName); f.renameTo(new File(origName)); } // ----------------------------------------------------------------------------- // ------------------------ Start of utility functions ------------------------- // ----------------------------------------------------------------------------- /** * Calculate and return the processing file path for the given base name. This * is the name the file will have during the processing. */ private String getProcFilePath(String baseName) { return InputFilePath + System.getProperty("file.separator") + ProcessingPrefix + InputFilePrefix + baseName + InputFileSuffix; } /** * Calculate and return the input file path for the given base name. */ private String getInputFilePath(String baseName) { return InputFilePath + System.getProperty("file.separator") + InputFilePrefix + baseName + InputFileSuffix; } /** * Provides reader created during init() * * @return The buffered reader */ public BufferedReader getFileReader() { return reader; } /** * Get the internal cache of the base name that we are using. */ private String GetBaseName() { return IntBaseName; } /** * Set the internal cache of the base name that we are using. Note that we * will include this information in the Header *and* the trailer record, in * order to save the processing or output adapters having to store this state * information. */ private void SetBaseName(String baseName) { IntBaseName = baseName; } /** * Provides a second level file name filter for files - may be overridden by * the implementation class * * @param fileNameToFilter The name of the file to filter * @return true if the file is to be processed, otherwise false */ public boolean filterFileName(String fileNameToFilter) { // Filter out files that already have the processing prefix return (fileNameToFilter.startsWith(ProcessingPrefix) == false); } }