Tuesday 6 November 2018

Angular 4+ : Sudden @types/jasmine error at runtime (npm start)

We've been building our angular application on a day to day basis, as everyone should. :-P Then, suddenly the following error surfaced on our Development Pipeline on Jenkins:

chunk {styles} styles.js, styles.js.map (styles) 201 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 332 kB [initial] [rendered]

ERROR in node_modules/@types/jasmine/index.d.ts(138,47): error TS1005: ';' expected.
node_modules/@types/jasmine/index.d.ts(138,90): error TS1005: '(' expected.
node_modules/@types/jasmine/index.d.ts(138,104): error TS1005: ']' expected.

node_modules/@types/jasmine/index.d.ts(138,112): error TS1005: ',' expected.

We did not change any versions or anything (didn't touch package.json), except for typescript logic as part of development progress.

At the end of the day, this error occurred due to @types/jasmine publishing a new version. ALSO, we had the following configured in our package.json under the "devDependencies" section:


"@types/jasmine": "^2.8.6",
"@types/jasminewd2": "^2.0.3"

Removal of the caret '^' character resolved the issue.

So, in other words, because we had the caret character against the versions of:

  • @types/jasmine
  • @types/jasminewd2
...it made it vulnerable to subsequent publication of versions from @types/jasmine.

Hence, I've noted it here... :-)

-----
PS: For the record, short explanation of menaing of '~' and '^' character in package.json file:

  • '^' - It will update you to the most recent MAJOR version 
  • '~' - It will update you to the most recent MINOR version 
------
Enjoy!


502 Bad Gateway nginx error on Kubernetes docker instance

We have taken a JSON Web Token approach to handle authorization in our Spring Boot application. Everything was working fine up to a point when we started getting 502 Bad Gateway errors for no reason (or, that's what we thought).

We discovered that this happened due to the token size which increased as we progressed with the development of functionality, which in turn resulted in the generation of a larger token based on additional authorization information.

The question still remains, why are we getting a 502 Bad Gateway. The HTTP 502 occurred due to the size of the header and on response to the HTTP request coming in, the kubernetes proxy rejected the request due to its header size.

So, we had to add the following line to the ingress of our application's docker descriptor:

  • ingress.kubernetes.io/proxy-buffer-size: 16k
That solved it. Hope it is of help to someone. :-)

Wednesday 10 October 2018

Oracle stored procedure with complex parameters - Array of structs and blobs

The following sniplet of code really helped me in implementing a procedure call containing an array of structs and array of blobs as part of its parameter signature: (I hope it will help you too)

import java.sql.Array;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import oracle.jdbc.OracleConnection;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.support.AbstractSqlTypeValue;

public class SqlBlobArrayValue extends AbstractSqlTypeValue {

    private List<byte[]> values;

    private String defaultTypeName;

    public SqlBlobArrayValue(List<byte[]> values) {
        this.values = values;
    }

    public SqlBlobArrayValue(List<byte[]> values, String defaultTypeName) {
        this.values = values;
        this.defaultTypeName = defaultTypeName;
    }

    protected Object createTypeValue(Connection conn, int sqlType, String typeName)
            throws SQLException {
        if (typeName == null && defaultTypeName == null) {
            throw new InvalidDataAccessApiUsageException(
                    "The typeName is null in this context. Consider setting the defaultTypeName.");
        }

        Blob[] blobs = new Blob[values.size()];
        for (int i = 0; i < blobs.length; ++i) {
            Blob blob = conn.createBlob();
            blob.setBytes(1, values.get(i));
            blobs[i] = blob;
        }

        Array array = conn.unwrap(OracleConnection.class).createOracleArray(typeName != null ? typeName : defaultTypeName, blobs);
        return array;
    }
}
With recognition to Luke Woodward on Stackoverflow. Thank you Luke!!

Thursday 20 April 2017

Angular JS - Javascript Madness

Those of you who have struggled with order in ansynchronous service calls in Angular JS will understand why I've posted the code below, for reference purposes. 

I just have to record the following as it took quite an effort to make sure two subsequent calls are made based on deferred promises with a final piece of code actually amending the results returned as part of the first promise. Hope you find it useful. 

$scope.validateDEXDeals = function(deals, arrayOfIndexes, dealResult, counter, deferred) {
        // extract the current deal's id into a variable
        var dealId = dealResult.deal.id;
        // extract the index of the current deal from the deal array 
        var index = deals.indexOf(dealResult);
       
        // call the workflow service to retrieve possible completed DEX processes
        WorkflowService.retrieveHistoricProcesses('completed', 'DEX', dealId).$promise.then(function (histResponse) {
// IF there does NOT exist a completed DEX process, splice the deal from the response
if (histResponse.data && histResponse.data.length <= 0) {
// record the index to splice
arrayOfIndexes.push(index);
// increase the counter object's value
counter.value++;
// when all the deals have been touched on, we may resolve the deferred promise.
if (counter.value == deals.length) {
deferred.resolve(arrayOfIndexes);
}

 // ELSE, leave the deal as part of the response
} else {
// increase the counter object's value
counter.value++;
// when all the deals have been touched on, we may resolve the deferred promise.
if (counter.value == deals.length) {
deferred.resolve(arrayOfIndexes);
}
}
});
        }
        
        $scope.doExtendedDocExaminationCheck = function(deals) {
        var arrayOfIndexes = [], deferred = $q.defer();
       
        // IF there are completed deals for the given production reference
if (deals) {
// setup a counter object in order to carry the correct index of the coming FOR loop.
var counter = {}
counter.value = 0;
// for each deal, go and validate whether there are DEX completed processes
for (var i=0; i<deals.length; i++) { 
var dealResult = deals[i];
// if the deal result contains a deal
if (dealResult.deal) {
// Check whether there exist completed DEX processes for the given deal
$scope.validateDEXDeals(deals, arrayOfIndexes, dealResult, counter, deferred);

} else { // otherwise increment the counter and continue with the rest of the deals.
counter.value++;
// If all deals have been visited, resolve the deferred promise
if (counter.value == deals.length) {
deferred.resolve(arrayOfIndexes);
}
}
}

} else {
// resolve the deferred promise, otherwise
deferred.resolve(arrayOfIndexes);
}
// return the deferred promise.
return deferred.promise;
        }
        
        

$scope.suggest = function(val) {
// reset deal search results on entry
$scope.dealResult = {};
// response promise from search on deal by production reference
var response;
// SPECIAL response promise to ensure synchronous execution of code on the payment of an LC
// (all options are anyway included in the special promise)
var responsePromise = $q.defer();

// if searching for a Deal with the intention to make a PAYMENT
if ($scope.case.stepCode === 'PAY') {

var _prodDesc = $rootScope.arrayFilter( $rootScope.allProducts,{"id":$scope.case.productCode},'description');
// check that the product in question is in fact a LC, as payment only applies to LCs

if (_prodDesc.indexOf('LC') >= 0) {
// Check whether there are completed deals with the given production reference (similar to other product searches)
response = DealService.dealByProdRef(val, $scope.case.productCode).$promise;

// On response of the deal search...continue to the following check
response.then(function (deals) {
// Check whether there exist completed DEX processes for the given deal
var indexesToSplicePromise = $scope.doExtendedDocExaminationCheck(deals);
//  On return of the possible indexes promise, remove the deals at the specified indexes.
indexesToSplicePromise.then(function(indexesToSplice) {
angular.forEach(indexesToSplice, function(index) {
// remove the deal at the given index
deals.splice(index, 1);
});
// resolve the SPECIAL promise on the modified deals promise
responsePromise.resolve(deals);
});
});

} else {
// search on Deal with no restrictions for any other product type, than LCs.
response = DealService.dealByProdRef(val, $scope.case.productCode).$promise;
// resolve the SPECIAL promise on the deals promise
response.then(function(data) {
responsePromise.resolve(data);
});
}
} else {
// search on Deal with no restrictions.
response = DealService.dealByProdRef(val, $scope.case.productCode).$promise;
// resolve the SPECIAL promise on the deals promise
response.then(function(data) {
responsePromise.resolve(data);
});
}
// return the SPECIAL response promise of the deal search for the type suggestion.
return responsePromise.promise;
        };