Friday, November 13, 2015

The Jira Auto Filer

This code uses the JIRA Rest API to gather information about issue types.  It also builds curl commands as well as links for bug filing.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
//Include dependency in pom.xml file
//<dependency>
//<groupId>net.sourceforge.htmlunit</groupId>
//<artifactId>htmlunit</artifactId>
//<version>2.13</version>
//</dependency>
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
//Include dependency in pom.xml file
//<dependency>
//    <groupId>org.json</groupId>
//    <artifactId>json</artifactId>
//    <version>20080701</version>
//</dependency>
import org.json.JSONArray;
import org.json.JSONObject;

public class JiraAutoFiler {
    public static String JIRA_HOST = "jira.com";
    public static String JIRA_USERNAME = "myusername";
    public static String JIRA_PASSWORD = "password";

    public static IssueTypeAttributes addJIRAIssueInformation(String projectKey, String issueTypeID) {
        IssueTypeAttributes issueTypeAttributes = new IssueTypeAttributes();
        issueTypeAttributes.projectKey = projectKey;
        issueTypeAttributes.issueTypeID = issueTypeID;

        try {
            System.out.println("Step 1a: Setup Authentication Information");
    
            System.out.println("Step 1b: Install SSL Certificate");        
            SSLHandler.setupSSLContextByInstallingCertification(JIRA_HOST);
    
            System.out.println("Step 2: Query Server for Projects");    
            HttpGet httpGet = new HttpGet("https://"+JIRA_HOST+"/rest/api/2/issue/createmeta?projectKeys="+issueTypeAttributes.projectKey+"&issuetypeIds="+issueTypeAttributes.issueTypeID+"&expand=projects.issuetypes.fields");
            String basic_auth = new String(Base64.encodeBase64((JIRA_USERNAME+":"+JIRA_PASSWORD).getBytes())); // 
            httpGet.addHeader("Authorization""Basic " + basic_auth);
            CloseableHttpResponse response = new DefaultHttpClient().execute(httpGet);
            String projectResponsJSON = EntityUtils.toString(response.getEntity());
            response.close();
            System.out.println("projectResponse:"+projectResponsJSON);
            
            JSONObject metaData = new JSONObject(projectResponsJSON);
            JSONArray projects = metaData.getJSONArray("projects");
//            holder.errorMessages = holder.errorMessages + projects.toString();
            JSONObject project = projects.getJSONObject(0);
//            holder.errorMessages = holder.errorMessages + project.toString();
            issueTypeAttributes.jiraProjectName = project.getString("name");
            issueTypeAttributes.jiraProjectID = project.getString("id");
            JSONArray issuetypes = project.getJSONArray("issuetypes");
            JSONObject issuetype = issuetypes.getJSONObject(0);
            issueTypeAttributes.issueName = issuetype.getString("name");
            JSONObject fields = issuetype.getJSONObject("fields");
                    
            for(String fieldName: JSONObject.getNames(fields)) {
                JSONObject fieldJSON = fields.getJSONObject(fieldName);
                IssueTypeFieldAttributes field = new IssueTypeFieldAttributes();
                field.fieldName = fieldName;
                field.fieldDisplayName = fieldJSON.getString("name");
                field.isRequired = fieldJSON.getBoolean("required");
                JSONObject schema = fieldJSON.getJSONObject("schema");
                field.type = schema.getString("type");
                try {
                    JSONArray allowedValues = fieldJSON.getJSONArray("allowedValues");
                    for (int i = 0; i < allowedValues.length(); i++) {
                        JSONObject allowedValueJSON = allowedValues.getJSONObject(i);
                        IssueTypeFieldAllowedValue allowedValue = new IssueTypeFieldAllowedValue();
                        allowedValue.valueID = allowedValueJSON.getString("id");
                        allowedValue.valueName = allowedValueJSON.getString("value");
                        field.allowedValues.add(allowedValue);
                    }
                } catch (Exception ex) {}
                
                issueTypeAttributes.fields.add(field);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        
        return issueTypeAttributes;
    }

    public static class IssueTypeAttributes{
        public String projectKey;
        public String issueTypeID;
        public String jiraProjectName;
        public String jiraProjectID;
        public String issueName;
        public List<IssueTypeFieldAttributes> fields = new ArrayList<IssueTypeFieldAttributes>();
        
        public String buildCURLCommand() {
            String curlCommand = "curl -k -H \"Content-Type: application/json\" -D- -X POST --data \'{\"fields\": {";
            curlCommand = curlCommand + "\"project\":{\"key\":\""+projectKey+"\"}, \"issuetype\": {\"id\":\""+issueTypeID+"\"}";
            for(IssueTypeFieldAttributes field: fields) {
                if(field.isRequired && (field.type.equals("string") || field.type.equals("array"))) {
                    String defaultValue = null;
                    try {
                        defaultValue = "{\"id\":\""+field.allowedValues.get(0).valueID+"\"}";
                    } catch (Exception ex) {
                        defaultValue = "\"Test\"";
                    }
                    if(field.type.equals("string")) {
                        curlCommand = curlCommand + ", \""+field.fieldName+"\":"+defaultValue;
                    } else if (field.type.equals("array")) {
                        curlCommand = curlCommand + ", \""+field.fieldName+"\":["+defaultValue+"]";
                    }
                }
            }
            curlCommand = curlCommand + "}}\' https://"+JIRA_HOST+"/rest/api/2/issue -u "+JIRA_USERNAME; 
            return curlCommand;
        }
        
        public String buildJSPALink() {
            String jspaLink = "https://"+JIRA_HOST+"/secure/CreateIssueDetails!init.jspa?";
            jspaLink = jspaLink + "pid="+ jiraProjectID +"&issuetype="+issueTypeID;    
            for(IssueTypeFieldAttributes field: fields) {
                if(field.isRequired && (field.type.equals("string") || field.type.equals("array"))) {
                    String defaultValueID = null;
                    try {
                        defaultValueID = field.allowedValues.get(0).valueID;
                    } catch (Exception ex) {
                        defaultValueID = "Test";
                    }
                    jspaLink = jspaLink + "&"+field.fieldName+"="+defaultValueID;
                }
            }
            return jspaLink;
        }
    }
    public static class IssueTypeFieldAttributes{
        public String fieldName;
        public String fieldDisplayName;
        public Boolean isRequired;
        public String type;
        public List<IssueTypeFieldAllowedValue> allowedValues = new ArrayList<IssueTypeFieldAllowedValue>();
    }
    public static class IssueTypeFieldAllowedValue{
        public String valueID;
        public String valueName;
    }
    
    public static class SSLHandler{

        /**
         * Should be called right before connection
         * 
         * Installs C:\Program Files\Java\jdk1.7.0_51\jre\lib\security\jssecacerts file
         * @param host
         * @throws Exception
         */

        static Set<String> hostsInstalled = new HashSet<String>();
        public static void setupSSLContextByInstallingCertification(String host) {
            if(hostsInstalled.contains(host)) {
                return;
            } else {
                hostsInstalled.add(host);
            }
            System.out.println("Installing SSLContext Certification into Java Home...");
            try {
                int port = 443;
                char[] passphrase = "changeit".toCharArray();
                
                char SEP = File.separatorChar;
                File file = new File("jssecacerts");
                if (file.isFile() == false) {
                    File dir = new File(System.getProperty("java.home") + SEP
                            + "lib" + SEP + "security");
                    file = new File(dir, "jssecacerts");
                    if (file.isFile() == false) {
                        file = new File(dir, "cacerts");
                    }
                }
                
                System.out.println("Loading KeyStore " + file + "...");
                InputStream in = new FileInputStream(file);
                KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
                ks.load(in, passphrase);
                in.close();
         
                TrustManagerFactory tmf =
                        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init(ks);
                final X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
                final List<X509Certificate> chainList = new ArrayList<X509Certificate>();
                
                TrustManager tm = new X509TrustManager() {
                    public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                                    throws CertificateException { }
                    public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                            throws CertificateException {
                            chainList.clear();
                            if(arg0 != null) {
                                for (int i = 0; i < arg0.length; i++) {
                                    chainList.add(arg0[i]);
                                }
                            }
                            defaultTrustManager.checkServerTrusted(arg0, arg1); }
                    public X509Certificate[] getAcceptedIssuers() { return null; }
                };
                
                SSLContext context = SSLContext.getInstance("TLS");
                context.init(nullnew TrustManager[]{tm}, null);
                SSLSocketFactory factory = context.getSocketFactory();
         
                System.out.println("Opening connection to " + host + ":" + port + "...");
                SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
                socket.setSoTimeout(10000);
                try {
                    socket.startHandshake();
                    System.out.println("No errors, certificate is already trusted");
                } catch (SSLException e) { }
                socket.close();
         
                if (chainList.isEmpty()) {
                    System.out.println("Could not obtain server certificate chain");
                    return;
                }
         
                System.out.println("Server sent " + chainList.size() + " certificate(s):");

                MessageDigest sha1 = MessageDigest.getInstance("SHA1");
                MessageDigest md5 = MessageDigest.getInstance("MD5");
                for (int i = 0; i < chainList.size(); i++) {
                    X509Certificate cert = chainList.get(i);
                    System.out.println
                            (" " + (i + 1) + " Subject " + cert.getSubjectDN());
                    System.out.println("   Issuer  " + cert.getIssuerDN());
                    sha1.update(cert.getEncoded());
                    System.out.println("   sha1    " + toHexString(sha1.digest()));
                    md5.update(cert.getEncoded());
                    System.out.println("   md5     " + toHexString(md5.digest()));
                }
                
                int k = 0;
                X509Certificate cert = chainList.get(k);
                String alias = host + "-" + (k + 1);
                ks.setCertificateEntry(alias, cert);
         
                File dir = new File(System.getProperty("java.home") + SEP
                        + "lib" + SEP + "security");
                file = new File(dir, "jssecacerts");
                OutputStream out = new FileOutputStream(file);
                ks.store(out, passphrase);
                out.close();
                
                System.out.println("Installed SSLContext Certification into Java Home: "+file.getAbsolutePath());
            } catch (Exception ex) { }
        }
     
        private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
     
        private static String toHexString(byte[] bytes) {
            StringBuilder sb = new StringBuilder(bytes.length * 3);
            for (int b : bytes) {
                b &= 0xff;
                sb.append(HEXDIGITS[b >> 4]);
                sb.append(HEXDIGITS[b & 15]);
                sb.append(' ');
            }
            return sb.toString();
        }
    }
}

Thursday, November 5, 2015

Calculating Loan Amortization with Monthly Compounding and Quarterly Payments

Say you have a loan for $100,000 and the interest rate is 17.7802%.  Payments are made quarterly in the amount of $10,500.  Here would be your payment schedule.

 
month:0      before interest balance:100000
month:0      after interest balance:101481.68333333333      interest:1481.6833333333332
month:1      before interest balance:101481.68333333333
month:1      after interest balance:102985.32052166945      interest:1503.637188336111
month:2      before interest balance:102985.32052166945
month:2      after interest balance:104511.23685161893      interest:1525.9163299494892
month:2      after payment balance:94011.23685161893      payment:10500
month:3      before interest balance:94011.23685161893
month:3      after interest balance:95404.18567950989      interest:1392.9488278909623
month:4      before interest balance:95404.18567950989
month:4      after interest balance:96817.77359802557      interest:1413.5879185156846
month:5      before interest balance:96817.77359802557
month:5      after interest balance:98252.30641313191      interest:1434.532815106345
month:5      after payment balance:87752.30641313191      payment:10500
month:6      before interest balance:87752.30641313191
month:6      after interest balance:89052.51771187088      interest:1300.2112987389733
month:7      before interest balance:89052.51771187088
month:7      after interest balance:90371.99402472138      interest:1319.4763128505053
month:8      before interest balance:90371.99402472138
month:8      after interest balance:91711.02079818667      interest:1339.0267734652925
month:8      after payment balance:81211.02079818667      payment:10500
month:9      before interest balance:81211.02079818667
month:9      after interest balance:82414.31095818327      interest:1203.2901599965987
month:10      before interest balance:82414.31095818327
month:10      after interest balance:83635.43006793218      interest:1221.1191097489084
month:11      before interest balance:83635.43006793218
month:11      after interest balance:84874.64229601038      interest:1239.2122280782062
month:11      after payment balance:74374.64229601038      payment:10500
month:12      before interest balance:74374.64229601038
month:12      after interest balance:75476.63897513665      interest:1101.9966791262698
month:13      before interest balance:75476.63897513665
month:13      after interest balance:76594.96375539142      interest:1118.3247802547705
month:14      before interest balance:76594.96375539142
month:14      after interest balance:77729.85856752776      interest:1134.8948121363421
month:14      after payment balance:67229.85856752776      payment:10500
month:15      before interest balance:67229.85856752776
month:15      after interest balance:68225.99217694638      interest:996.1336094186308
month:16      before interest balance:68225.99217694638
month:16      after interest balance:69236.8853320335      interest:1010.8931550871183
month:17      before interest balance:69236.8853320335
month:17      after interest balance:70262.75672251736      interest:1025.8713904838517
month:17      after payment balance:59762.756722517355      payment:10500
month:18      before interest balance:59762.756722517355
month:18      after interest balance:60648.25152841544      interest:885.4948058980858
month:19      before interest balance:60648.25152841544
month:19      after interest balance:61546.86656327005      interest:898.6150348546101
month:20      before interest balance:61546.86656327005
month:20      after interest balance:62458.79622732693      interest:911.9296640568783
month:20      after payment balance:51958.79622732693      payment:10500
month:21      before interest balance:51958.79622732693
month:21      after interest balance:52728.661051227864      interest:769.8648239009318
month:22      before interest balance:52728.661051227864
month:22      after interest balance:53509.93283391373      interest:781.271782685868
month:23      before interest balance:53509.93283391373
month:23      after interest balance:54302.78059039169      interest:792.8477564779606
month:23      after payment balance:43802.78059039169      payment:10500
month:24      before interest balance:43802.78059039169
month:24      after interest balance:44451.79908993609      interest:649.0184995444018
month:25      before interest balance:44451.79908993609
month:25      after interest balance:45110.43398841849      interest:658.6348984824014
month:26      before interest balance:45110.43398841849
month:26      after interest balance:45778.82777041922      interest:668.3937820007319
month:26      after payment balance:35278.82777041922      payment:10500
month:27      before interest balance:35278.82777041922
month:27      after interest balance:35801.5482816889      interest:522.7205112696732
month:28      before interest balance:35801.5482816889
month:28      after interest balance:36332.01385565397      interest:530.4655739650708
month:29      before interest balance:36332.01385565397
month:29      after interest balance:36870.33924961755      interest:538.3253939635822
month:29      after payment balance:26370.33924961755      payment:10500
month:30      before interest balance:26370.33924961755
month:30      after interest balance:26761.06417122259      interest:390.72492160504163
month:31      before interest balance:26761.06417122259
month:31      after interest balance:27157.578398870235      interest:396.5142276476433
month:32      before interest balance:27157.578398870235
month:32      after interest balance:27559.96771174323      interest:402.38931287299374
month:32      after payment balance:17059.96771174323      payment:10500
month:33      before interest balance:17059.96771174323
month:33      after interest balance:17312.742410000177      interest:252.77469825694746
month:34      before interest balance:17312.742410000177
month:34      after interest balance:17569.26242883208      interest:256.5200188319043
month:35      before interest balance:17569.26242883208
month:35      after interest balance:17829.58326202968      interest:260.3208331976001
month:35      after payment balance:7329.583262029679      payment:10500

Here is the algorithm used to calculate this:


<html> 
<body> 
<pre> 
<script> 
function log(arg) { 
    document.body.innerHTML = document.body.innerHTML + arg + '\n<br>'

function clear() { 
    document.body.innerHTML = ''


var rate = .177802;
var balance = 100000;
var payment = 10500;

for(var i=0; i<12; i++){
    for(var j=0; j<3; j++) {
        log('month:'+(i*3+j)+'      before interest balance:'+balance);
        var interest = balance*rate/12;
        balance = balance + interest;
        log('month:'+(i*3+j)+'      after interest balance:'+balance+'      interest:' + interest);
    
    if(j == 2) {
        balance = balance - payment;
            log('month:'+(i*3+j)+'      after payment balance:'+balance+'      payment:' + payment);
        }
    }
}

</script> 
</pre> 
</body> 
</html>