Subversion Repositories DevTools

Rev

Rev 1695 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package com.erggroup.mass.ant.tasks;

import com.erggroup.mass.ant.tasks.util.CCITT;
import java.io.*;
import java.util.Vector;
import java.util.Iterator;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.BuildException;

/**
 * Creates an APMCFG payload using information passed to it in ANT 
 * 
 * @author bivey
 */
public class Apmcfg extends Task {

        private String dir;             // The directory in which to write the APMCFG file
        private int version;    // Specifies the overall software build version         
        private Vector devices; // A list of device types contained in the APMCFG
        private boolean valid;  // Indicates whether the payload has been validated
        
        public Apmcfg()
        {
                this.devices = new Vector();
                this.version = 0;
                this.dir = System.getProperty("user.dir");
                this.valid = false;             
        }
        
        /**
         * Main function executed by ANT task
         * 
         * @see org.apache.tools.ant.Task#execute()
         */
        public void execute() 
        {
                // First validate our entered data
                validatePayload();
                
                try
                {
                        // Now write the APMCFG file 
            String file = this.dir + File.separatorChar + "@APMCFG_1_" + this.version + ".mug";
                        FileOutputStream fos = new FileOutputStream(file);
                        DataOutputStream dos = new DataOutputStream(fos);
                        
                        this.writePayload(dos);
            log("Wrote APMCFG payload: " + file);

                        dos.close();
                        fos.close();
                }
                catch (Exception e)
                {
                        throw new BuildException(e);
                }
        }       
        
        // Attribute setters - called by ANT when attributes are provided
        public void setDir(String dir) { this.dir = dir; }
        public void setVersion(int version) { this.version = version; }
        
        /**
         * Validates data provided by ANT, ensuring a payload can be successfully created
         * 
         * @throws BuildException If invalid parameters are provided
         */
        public void validatePayload()
        {
                // Check the specified target directory exists
                File directory = new File(this.dir);
                if( !directory.isDirectory() )
                {
                        if( !directory.mkdirs() )
                        {
                                throw new BuildException("Unable to create directory: " + this.dir);
                        }
                }
                
                for (Iterator it = this.devices.iterator(); it.hasNext(); ) 
                {
                        Device device = (Device)it.next();
                        //if(device.version == 0)
                        {
                                // Assume our version was hexadecimal - this is a hacky workaround for
                                // the difficulty in converting between decimal-hex in an ANT script
                                device.setVersion(Integer.parseInt(Integer.toString(this.version), 16));
                                
                                //log("device.version = " + this.version);
                        }
                        device.validatePayload();
                }
                
                this.valid = true;
        }
        
        /**
         * Writes the payload contents to file
         * 
         * @param out The data output stream to write the payload to
         * @throws IOException On file write errors
         * @throws BuildException If payload contents have not been validated (see validatePayload())
         */
        public void writePayload(DataOutputStream out) throws IOException
        {
                if(!this.valid)
                {
                        throw new BuildException("Attempted to write an unvalidated APMCFG payload");
                }
                
                // Write DevCdApmcfgHeaderRecord_t
                out.writeInt(this.version);  // systemVer
                out.writeInt(this.devices.size());  // numDevTypes
                
                // Write DevCdApmcfgModuleSet_t for each contained device
                for (Iterator it = this.devices.iterator(); it.hasNext(); ) 
                {
                        Device device = (Device)it.next();
                        device.writePayload(out);
                }               
        }
        
        /**
         * Creates a new Device object instance
         * 
         * @return A new Device instance
         */
        public Device createDevice() 
        {
                Device device = new Device(this.version);
                this.devices.add(device);
                return device;
        }
        
        /**
         * A class defining device modules contained within the APMCFG payload 
         * 
         * @author bivey
         */
        public class Device
        {
                private int tier;                       // Where the device type is connected in the network hierarchy          
                private String type;            // Device type name
                private int version;            // Software release version for this device type        
                private Vector modules;         // A list of modules for this device type
                private boolean valid;          // Indicates whether the payload has been validated
                
                public Device(int version) 
                {
                        this.version = version;
                        this.tier = 3;
                        this.type = "";
                        this.modules = new Vector();
                        this.valid = false;
                }

                // Attribute setters - called by ANT when attributes are provided
                public void setTier(int tier) { this.tier = tier; }
                public void setType(String type) { this.type = type; }
                public void setVersion(int version) { this.version = version; }
                
                /**
                 * Validates data provided by ANT, ensuring a payload can be successfully created
                 * 
                 * @throws BuildException If invalid parameters are provided
                 */
                public void validatePayload()
                {
                        if(this.type == null || this.type.length() == 0)
                        {
                                throw new BuildException("Device 'type' attribute must be defined");
                        }
                        if(this.type.length() > 9)
                        {
                                throw new BuildException("Device 'type' attribute exceeds maximum of 9 characters: " 
                                                        + this.type );
                        }
                        
                        for (Iterator it = this.modules.iterator(); it.hasNext(); ) 
                        {
                                Module module = (Module)it.next();
                                //if(module.version == 0)
                                {
                                        module.setVersion(this.version);
                                        
                                        //log("module.version = " + this.version);
                                }                               
                                module.validatePayload();
                        }
                        
                        this.valid = true;
                }
                
                /**
                 * Writes the payload contents to file
                 * 
                 * @param out The data output stream to write the payload to
                 * @throws IOException On file write errors
                 * @throws BuildException If payload contents have not been validated (see validatePayload())
                 */
                public void writePayload(DataOutputStream out) throws IOException
                {
                        if(!this.valid)
                        {
                                throw new BuildException("Attempted to write an unvalidated device payload");
                        }
                        
                        // Write DevCdSoftwareModuleSetHeaderRecord_t
                        out.write(this.type.getBytes());  // devType
                        out.write(new byte[9-this.type.length()]);
                        out.writeByte(0);  // reserved
                        out.writeInt(this.version);  // version
                        out.writeInt(this.tier);  //tier
                        out.writeInt(this.modules.size());  //numMods
                        out.writeShort(0);  // deleteBitmap
                        
                        // Write DevCdApmcfgModuleDescriptionRecord_t for each contained module
                        for (Iterator it = modules.iterator(); it.hasNext(); ) 
                        {
                                Module module = (Module)it.next();
                                module.writePayload(out);
                        }                               
                }
        
                /**
                 * Creates a new Module object instance
                 * 
                 * @return A new Module instance
                 */
                public Module createModule() 
                {
                        Module module = new Module(this.version);
                        this.modules.add(module);
                        return module;
                }

                /**
                 * A class defining modules for the parent device type within the APMCFG payload 
                 * 
                 * @author bivey
                 */
                public class Module 
                {
                        private String tag;             // Software module name
                        private int version;    // Software module version
                        private byte type;              // A bitmap controlling the software module loading process
                        private byte special;   // Indicates if the software module has special memory requirements
                        private String file;    // The file associated with this module
                        private int crc;                // Software module checksum                     
                        private int size;               // Software module size (number of bytes)
                        private boolean valid;  // Indicates whether the payload has been validated
                        
                        public Module(int version) 
                        {
                                this.version = version;
                                this.valid = false;
                                this.tag = "";
                                this.type = 0;
                                this.special = 0;
                                this.crc = 0;
                                this.size = 0;
                        }

                        // Attribute setters - called by ANT when attributes are provided
                        public void setFile(String file) { this.file = file; }
                        public void setSpecial(byte special) { this.special = special; }
                        public void setTag(String tag) { this.tag = tag; }
                        public void setType(byte type) { this.type = type; }
                        public void setVersion(int version) { this.version = version; }
                        
                        /**
                         * Validates data provided by ANT, ensuring a payload can be successfully created
                         * 
                         * @throws BuildException If invalid parameters are provided
                         */
                        private void validatePayload()
                        {
                                if(this.file == null || this.file.length() == 0)
                                {
                                        throw new BuildException("Module 'file' attribute must be defined");
                                }
                                
                                // Extract required file information
                                try
                                {
                                        CCITT crc = new CCITT();
                                        FileInputStream fis = new FileInputStream(this.file);
                                        BufferedInputStream bis = new BufferedInputStream(fis);                                 
                                
                                int len = 0;
                                byte[] buffer = new byte[8192];
                                while ((len = bis.read(buffer)) > -1) 
                                {
                                        crc.update(buffer, 0, len);
                                }
                                
                                this.crc = (short)crc.getValue();
                                this.size = (int)crc.getLength();
                                
                                bis.close();
                                fis.close();
                                }
                                catch(FileNotFoundException e)
                                {
                                        throw new BuildException("Unable to read file: " + file);
                                }
                                catch(IOException e)
                                {
                                        throw new BuildException(e);
                                }

                                // Check tag or form one if it was not provided
                                if( this.tag.length() > 8 )
                                {
                                        throw new BuildException("Module 'tag' attribute exceeds maximum of 8 characters: " 
                                                        + this.tag );
                                }
                                else if( this.tag.length() == 0 )
                                {
                                        // Extract the tag from the typical filename format of 'PATH\TAG_VERSION.mug'
                                        int index = 0;
                                        int start = 0;
                                        int end = this.file.length();
                                        
                                        if( (index = this.file.lastIndexOf('\\')) != -1 ) start = index;
                                        if( (index = this.file.lastIndexOf('/')) > start ) start = index;
                                        if( (index = this.file.indexOf('.', start)) != -1 ) end = index;
                                        if( ((index = this.file.indexOf('_', start)) != -1) && (index < end) ) end = index;
                                        if( (end - start) > 8 ) end = (start + 8);
                                        
                                        this.tag = this.file.substring(start, end);
                                }
                                this.tag = this.tag.toUpperCase();
                                
                                this.valid = true;
                        }
                        
                        /**
                         * Writes the payload contents to file
                         * 
                         * @param out The data output stream to write the payload to
                         * @throws IOException On file write errors
                         * @throws BuildException If payload contents have not been validated (see validatePayload())
                         */
                        private void writePayload(DataOutputStream out) throws IOException
                        {
                                if(!this.valid)
                                {
                                        throw new BuildException("Attempted to write an unvalidated module payload");
                                }
                                
                                // Write DevCdApmcfgModuleDescriptionRecord_t
                                out.write(this.tag.getBytes());  // tag
                                out.write(new byte[8-this.tag.length()]);
                                out.writeShort(this.version);  // version
                                out.writeShort(this.crc); // crc
                                out.writeInt(this.size);  // size
                                out.writeByte(this.type);  // type
                                out.writeByte(this.special);  // special
                                out.writeShort(0);      // reserved
                        }
                }               
        }
}