Some of you might be interested in presentation which I made recently for internal training purpose. Topic is "Packer by HashiCorp".
Some of you might know this unofficial Stack Careers Android app which allows you search job in IT sector. There is a link => Stack Careers on Google Play. I have been using it for a while, but some time ago it stopped working. Only what I got was : 'No Results'. So, I downloaded repository and found out that feed API of Stack Careers has been changed. I mean that application got HTTP 301 status which means Moved Permanently and no redirect has been performed using standard HttpConnection component of Android stack. More info about what I did you might find below and under pull request link.
In fact that I have been using you app occasionally, I found someday that it does not work now. I managed to figure out that guys from Stackoverflow changed feed API and moreover you app was not able to follow up redirect (HTTP 301 Moved Permanently).
So, according to this pull request what I did and what I did not :
- feed API has not been changed
- added OkHttp library within required by it another library called Okio
- replaced HttpURLConnection with client from OkHttp
- added required rules for proguard to cover up OkHttp
I also would like to mention that feed API for Stack careers has been changed from
http://careers.stackoverflow.com/jobs/feed => https://stackoverflow.com/jobs/feed
PS. I hope that author of Stack Career will accept my fix for that problem and eventually some day we might be able to download new app from Google Play.
Reference :
[1] Stack Careers - pull request
Some of you might be interested in presentation which I made recently for internal training purpose. Topic is "Consul and Consul Pusher".
Some of you might thinking how to create sequence for table which contains some records. You might always export all records from database, then eventually create sequence and after all import those records once again into database. Nevertheless there is a solution how to create this sequence using PL/SQL.
DECLARE seq_value_holder NUMBER; BEGIN -- create a sequence for YOUR_TABLE SELECT NVL(MAX(id), 0) + 1 INTO seq_value_holder FROM YOUR_TABLE; EXECUTE immediate 'create sequence SEQ_YOUR_TABLE start with ' || seq_value_holder || ' increment by 1'; END;
A few days ago, I got an email with inquiry if I would like to participate in recruitment process to Google. I thought why not. It is always good to gain some experience around that. After a phone interview which was not successful for me, but I am not sad about that fact at all, I thought that I might give you some insight what areas you should refresh or just learn quickly. Of course your questions will be correlated with those areas which you picked up before phone interview, but I assume that some of them might be similar with those which I chose.
- Operating systems - monitors, semaphores, mutexes, linux, unix, processes, inode
- Algorithm Complexity - big O notation for different algorithms. Provide some complexity for sorting algorithms. Pick up those data structures which have following complexity for instance O(n log (n))
- Mathematics - calculate something very quickly in mind for instance 2 to the power of 32
- Trees - big O notation for different operation performed on trees like AVL, Binary trees
- Java - question related to programming language which you chose
Some of you might be interested in presentation which I made recently for internal training purpose. Topic is "Mutation testing with Pitest".
If you are trying to speed up your Android phone, you should consider uninstalling Facebook! You can read more about that phenomenon for instance here : https://www.reddit.com/r/Android/comments/42kyph/uninstalling_facebook_speeds_up_your_android/. To be honest my phone is much faster after removing Facebook.
Have you ever wondered how to map enums from one to another ? Did you use switch statement to make it work ? Now you can use method immutableEnumMap from class Maps which is part of Guava. Below you can find an example.
public class EnumSourceMapper { static ImmutableMap<EnumSource, EnumDestination> mapper; static { mapper = Maps.immutableEnumMap(ImmutableMap.<EnumSource, EnumDestination>builder() .put(EnumSource.SUCCESS, EnumDestination.SUCCESS) .put(EnumSource.INCOMPLETE, EnumDestination.ERROR) .put(EnumSource.FAIL, EnumDestination.ERROR) .build()); } public EnumDestination getEnumDestination(EnumSource enumSource) { return mapper.get(enumSource); } }
Recently I was trying to convert some cash in EUR currency, but I did not have time to watch currency graph all the time. So, I have created small tool which will let me know via email when currency will get more expensive above some concrete level. You can put below script in cron to execute it with some time interval. I used Sparkpost as a email provider.
import urllib2 import json from sparkpost import SparkPost sp = SparkPost('YOUR_API_KEY') def currencyConverter(currency_from,currency_to): yql_base_url = "https://query.yahooapis.com/v1/public/yql" yql_query = 'select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20("'+currency_from+currency_to+'")' yql_query_url = yql_base_url + "?q=" + yql_query + "&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys" try: yql_response = urllib2.urlopen(yql_query_url) try: yql_json = json.loads(yql_response.read()) currency_output = 1 * float(yql_json['query']['results']['rate']['Rate']) return currency_output except (ValueError, KeyError, TypeError): return "JSON format error" except IOError, e: if hasattr(e, 'code'): return e.code elif hasattr(e, 'reason'): return e.reason currency_from = "EUR" # currency codes : http://en.wikipedia.org/wiki/ISO_4217 currency_to = "PLN" direction_rate = 4.44 rate = currencyConverter(currency_from,currency_to) print rate if rate > direction_rate: response = sp.transmissions.send( recipients=['YOUR_EMAIL@gmail.com'], html='Rate of ' + currency_from + currency_to + ' equals ' + str(round(rate, 2)) + '
', from_email='test@sparkpostbox.com', subject='EuroMonitor' ) print(response) else: print "Rate too low"
Reference :
[1] EuroMonitor Source Code
I had a chance to work with Spring Test DBUnit [1] (integration between Spring testing framework and DBUnit) with few tests related with Spring Integration. Most of them use the same common text context which contains embedded database H2. Funny thing was that some tests failed, because of some tables already exist. The issue is that embedded database is not cleared between tests and it is reused within the same context. That's why you should use @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) with @TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class}) like below :
@ContextConfiguration @RunWith(SpringJUnit4ClassRunner.class) @TestExecutionListeners({DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public class YourTest { }
Reference :
[1] Spring Test DBUnit
[2] Spring Framework - DirtiesContext
I would like to announce that new Android app has been released recently times by me. This time application is called PerlJobs. This application helps you as a Perl developer to find new job opportunities across the globe. Job offers are divided into sections : Standard, Mod, Catalyst, Mason, Telecommute and By Country. The main source of all jobs is website : https://jobs.perl.org
Yes! I finally managed to create it. Obviously it is not so pretty as it might be, but.. never mind :) If you would like to create your own Google Play Developer Page where you can add some promotion text and graphics (icon and background), just go to your Developer Console and then click Settings and then Developer Page. If you are looking for let's say 'inspiration', you can have a look on my Developer Page which link you can find below :
This time I would like to share with small snippet of code written in Java and Spring MVC which might allow you to pack and download some files (in this case .csv file) in ZIP archive. So, if you will hit URL http://localhost:8090/yourApp/download/zip, Zip archive will be downloaded with name 'download.zip'.
@ResponseBody @RequestMapping(value = {"/download/zip"}, method = RequestMethod.GET) public void downloadZipArchive(HttpServletResponse response) throws IOException { List<MyClass> list; //should contains some records! if (list != null && !list.isEmpty()) { if (list.size() > 200000) { response.setContentType("application/zip"); response.addHeader("Content-Disposition", "attachment; filename=\"download.zip\""); response.addHeader("Content-Transfer-Encoding", "binary"); OutputStream servletOutputStream = response.getOutputStream(); ZipOutputStream zos = new ZipOutputStream(servletOutputStream); int counter = 0; List<List<MyClass>> dividedlist = Lists.partition(list, 200000); for (List<MyClass> partition : dividedlist) { zos.putNextEntry(new ZipEntry("file_" + counter + ".csv")); CSVWriter writer = new CSVWriter(new OutputStreamWriter(zos)); writer.writeNext(new String[]{"HEADER"}); for (MyClass item : partition) { writer.writeNext(new String[]{item.getText()}); } writer.flush(); zos.closeEntry(); counter++; } zos.close(); response.getOutputStream().flush(); response.getOutputStream().close(); } } }
Guava FluentIterable - Get only first object or null from list
by GarciaPL on Tuesday, 23 February 2016
A few days ago I had issue, that I need to get first object from some list which meet my requirements. Of course I can create some loop, write some if statement. If I will find interesting me object, then I am gonna return it. If I will not find any useful in whole list, then I am will return null.
Above solution is done in quite old-style approach. Now it is time for functional programming! I found very useful a library called Guava and it's utility class called FluentIterable. It supports you to manipulate Iterable instances in a chained fashion. This class has a lot of functionalities, but I would like to focus only on one case - get first interesting object to my pattern or just return null.
MyClass interestingObjectOrNull = FluentIterable.from(myList) .firstMatch(new Predicate<MyClass>() { @Override public boolean apply(MyClass element) { return element.getId == 125L } }) .orNull();
And that's it! Simple, isn't ? All you need to remember to check returned object if it is null or not. Of course you might write as much complex apply pattern as you like.
Reference :
[1] Stackoverflow - Get only element of a collection view with Guava, without exception when there are multiple elements
[2] Pastebin - Source code
GPG error: http://downloads.hipchat.com Public key is not available
by GarciaPL on Saturday, 6 February 2016
Recently I had an issue during installation of HipChat from Atlassian on my Ubuntu. I mean that installation went well, but I had issue with GPG keys which was :
"GPG error: http://downloads.hipchat.com stable InRelease: The following signatures couldn't be verified because the public key is not available"
So, I managed to find that WebUpd8Team provides tool called y-ppa-manager. All you have to do is install y-ppa-manager like below :
sudo add-apt-repository ppa:webupd8team/y-ppa-manager sudo apt-get update sudo apt-get install y-ppa-manager
and then launch this tool. Select "Advanced" and then "Try to import all missing GPG keys". This operation might take a one or two minutes, so be calm and wait for notification. After that you can run sudo apt-get update to refresh repositories.
Reference : [1] Y PPA Manager - WebUpd8Team
In recent times I had issue with web application written in Spring. The problem was that some numbers stored in database as a BigDecimal's and Long's were not being stored/processed properly for different locales. On backend the numbers were processed of course using English locale, but when you have number saved with different locale the calculations might be different.
Saved BigDecimal's and Long's were processed against English locale, but presentation of numbers were based on appropriate locale of present user context.
Parse BigDecimal => 12,333,444
English => 12333444
Indonesian => 12333444
Print BigDecimal => 12345.50
English => 12345.50
Indonesian => 12345,50
Only difference for printed numbers for above locales was how decimal places is presented. For English we use dot. For Indonesian comma is used.
Parse Long => 12,333,444
English => 12333444
Indonesian => 12333444
Print Long => 12333444
English => 12333444
Indonesian => 12333444
For Long's the formatter we are going to just remove grouping commas.
So, below you can find CurrencyLocaleBigDecimalFormatter :
package pl.garciapl.test; import org.springframework.format.Formatter; import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; public class CurrencyLocaleBigDecimalFormatter implements Formatter<BigDecimal> { @Override public BigDecimal parse(String text, Locale locale) throws ParseException { DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ENGLISH); format.applyPattern("#,##0.00"); format.setParseBigDecimal(true); format.setGroupingUsed(true); return (BigDecimal) format.parse(text); } @Override public String print(BigDecimal object, Locale locale) { DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(locale); format.applyPattern("#,##0.00"); format.setParseBigDecimal(true); format.setGroupingUsed(false); return format.format(object); } }
and CurrencyLocaleLongFormatter :
package pl.garciapl.test; import org.springframework.format.Formatter; import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; import java.util.Locale; public class CurrencyLocaleLongFormatter implements Formatter<Long> { @Override public Long parse(String text, Locale locale) throws ParseException { DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ENGLISH); format.applyPattern("#,##0.00"); format.setParseBigDecimal(false); format.setGroupingUsed(true); return (Long) format.parse(text); } @Override public String print(Long object, Locale locale) { DecimalFormat format = (DecimalFormat) NumberFormat.getNumberInstance(locale); format.applyPattern("#,##0.00"); format.setParseBigDecimal(false); format.setGroupingUsed(false); return format.format(object); } }
Also CurrencyLocaleFormatterRegistrar is needed because of Spring framework needs to register formatters in registry to use them.
package pl.garciapl.test; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistrar; import org.springframework.format.FormatterRegistry; import java.util.HashSet; import java.util.Set; public class CurrencyLocaleFormatterRegistrar implements FormatterRegistrar { private Set<Formatter> formatters = new HashSet<>(); public CurrencyLocaleFormatterRegistrar(Set<Formatter> formatters) { this.formatters = formatters; } @Override public void registerFormatters(FormatterRegistry registry) { for (Formatter element : this.formatters) { registry.addFormatter(element); } } }
And finally whole beans configuration for Spring
<bean id="currencyLocaleBigDecimalFormatter" class="ie.garciapl.test.CurrencyLocaleBigDecimalFormatter"/> <bean id="currencyLocaleLongFormatter" class="ie.garciapl.test.CurrencyLocaleLongFormatter"/> <bean id="currencyLocaleRegistrar" class="ie.garciapl.test.CurrencyLocaleFormatterRegistrar"> <constructor-arg> <set> <ref bean="currencyLocaleBigDecimalFormatter"/> <ref bean="currencyLocaleLongFormatter"/> </set> </constructor-arg> </bean>
Do not forget to plug into your conversionCurrencyService as below :
<mvc:annotation-driven conversion-service="conversionCurrencyService"/>
Reference : [1] Spring Docs - Formatters [2] Javabeat.net - Introduction to Spring Converters and Formatters [3] CurrencyLocaleBigDecimalFormatter [4] CurrencyLocaleLongFormatter [5] CurrencyLocaleFormatterRegistrar [6] CurrencyLocaleBigDecimalFormatterTest [7] CurrencyLocaleLongFormatterTest
Below you can find GitHub Gist of User Agents in JSON based on massive list of user agents provided by Chris Pederik [1]. I provided the same list of user agents in more friendly form as a JSON because of this one provided in reference is nested multiple times, what obviously affects the use of content. Moreover I removed duplicates.
Reference : [1] https://gist.github.com/enginnr/ed572cf5c324ad04ff2e
I just would like to show you how setup styles.xml and values-v21/styles.xml to use Material Design with AppCompat. First of all rename styles21.xml as styles.xml and place in your res/values-v21 folder (you may need to create a values-v21 folder if you don't already have one). Below you might found AndroidManifest.xml.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="uk.co.thewirelessguy.myappname" > <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="uk.co.thewirelessguy.myappname.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Then change your build.gradle to provide appropriate compileSdkVersion and buildToolsVersion.
apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion "21.1.1" defaultConfig { applicationId "uk.co.thewirelessguy.myappname" minSdkVersion 9 targetSdkVersion 21 versionCode 1 versionName "1.0" } buildTypes { release { runProguard false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:21.0.0' }
After that you can apply styles.xml
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="AppTheme.Base"/> <style name="AppTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <!-- colorPrimary is used for the default action bar background --> <item name="colorPrimary">@color/colorPrimary</item> <!-- colorPrimaryDark is used for the status bar --> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- colorAccent is used as the default value for colorControlActivated which is used to tint widgets --> <item name="colorAccent">@color/colorAccent</item> <!-- You can also set colorControlNormal, colorControlActivated colorControlHighlight & colorSwitchThumbNormal. --> </style> </resources>
And also style for v21
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="AppTheme" parent="AppTheme.Base"> <!-- Customize your theme using Material Design here. --> </style> </resources>
Reference : [1] https://gist.github.com/thewirelessguy/1875ddb114bda7407402
In this post I would like to give you some introduction how to integrate Bower and Gulp into your Java project. On the beginning I just would like to explain briefly you what Bower and Gulp are.
Bower - package management system for client-side programming on the World Wide Web. It depends on Node.js and npm. It works with git and GitHub repositories. [Wikipedia]
Gulp - fast and intuitive streaming build tool built on Node.js.
First of all we are going to use very useful plugin called frontend-maven-plugin provided under groupId com.github.eirslett [3]. This plugin will allows us to download/install Node and NPM locally for your project, run NPM install, and then any combination of Bower, Grunt, Gulp, Jspm, Karma, or Webpack.
<plugin> <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>0.0.26</version> <executions> <execution> <id>install node and npm</id> <goals> <goal>install-node-and-npm</goal> </goals> <phase>generate-resources</phase> <configuration> <nodeVersion>v0.12.9</nodeVersion> <npmVersion>2.14.14</npmVersion> </configuration> </execution> <execution> <id>npm install</id> <goals> <goal>npm</goal> </goals> <!-- Uses package.json --> <configuration> <arguments>install</arguments> </configuration> </execution> <execution> <id>bower install</id> <goals> <goal>bower</goal> </goals> <!-- Uses bower.json --> <configuration> <arguments>install</arguments> </configuration> </execution> <execution> <id>gulp build</id> <goals> <goal>gulp</goal> </goals> <!-- Uses gulpfile.js --> <configuration> <arguments>default --env ${gulp.task}</arguments> </configuration> </execution> </executions> </plugin>
As you can see, first of all above plugin will install locally node and npm. Then npm will install all packages from package.json file. After that bower will install packages used by frontend which are defined in bower.json. The last step is gulp which performs actions defined in gulpfile.js.
Below you can find package.json file in which I have defined bower, gulp and gulp plugins versions :
{ "name": "simple-web", "repository": "git@bitbucket.org:test/test.git", "version": "1.0.0", "private": true, "description": "Simple Web", "main": "index.js", "author": "GarciaPL", "dependencies": { "bower": "1.7.0", "gulp": "3.9.0", "gulp-concat": "2.6.0", "gulp-uglify": "1.5.1", "gulp-sourcemaps": "1.6.0", "gulp-less": "3.0.5", "gulp-minify-css": "1.2.2", "gulp-environments": "0.1.1" } }
Then let's see what bower.json contains. You can find there defined some plugins from Bower Repository which will be downloaded and installed in bower_components directory :
{ "name": "Simple Web", "version": "1.0.0", "private": true, "ignore": [ "**/.*", "node_modules", "bower_components", "test", "tests" ], "dependencies": { "jquery": "1.11.3", "underscore": "1.8.3", "autoNumeric": "1.9.25" } }
And the last file is gulpfile.js. In this file you can define special actions which are going to be performed during maven build phase of your Java application. In definition of maven plugin which you might found at the beginning of this post, there is a command : <arguments>default --env ${gulp.task}</arguments>. Variable gulp.task means against what environment application should be build. This variable might be defined in root pom.xml in profile section as a property.
So, according to gulpfile.js for development phase, gulp will provide vendor.map for vendor.js - for this development() method is used. On the other side production phase will provide you uglified vendor.js (compressed) and minified CSS based on base.less - for this one production() method is used. Vendor.js will be placed in /src/main/webapp/static/js/vendor directory, but CSS file might be found in /src/main/webapp/static/css directory.
var gulp = require('gulp'); var concat = require('gulp-concat'); var uglify = require('gulp-uglify'); var sourcemaps = require('gulp-sourcemaps'); var less = require('gulp-less'); var minifyCSS = require('gulp-minify-css'); var environments = require('gulp-environments'); var development = environments.development; var production = environments.production; gulp.task('default', function () { console.log('Preparing vendor.js for ' + (production() ? "production" : "development")); gulp.start('vendorJS'); console.log('Preparing less for ' + (production() ? "production" : "development")); gulp.start('less'); }); gulp.task('vendorJS', function () { gulp.src(['bower_components/jquery/dist/jquery.min.js', 'bower_components/underscore/underscore-min.js', 'bower_components/autoNumeric/autoNumeric.js']) .pipe(development(sourcemaps.init())) .pipe(concat('vendor.js')) .pipe(production(uglify())) .pipe(development(sourcemaps.write('./'))) .pipe(gulp.dest('./src/main/webapp/static/js/vendor')); }); gulp.task('less', function () { return gulp.src('src/main/webapp/static/less/base.less') .pipe(less()) .pipe(production(minifyCSS())) .pipe(gulp.dest('./src/main/webapp/static/css')); });
Reference :
[1] Bower.io
[2] Gulpjs.com
[3] Eirslett - frontend-maven-plugin
[4] Npmjs.com
[5] Nodejs.org