Scala: Basic Class Creation

In this tutorial I will show you how to create your first Scala class and then use it. I am just beginning with Scala during the time of this writing. Review the Scala style guide.

So the first thing we want to do is determine what we want to create a class to represent. In this tutorial I am just going to play around and use Person. We will want to create a constructor, getters, setters, toString and then finally a method to combine some properties.

Create your class.

  1. class Person {
  2. }

We could have added variables to the Person declaration. But I thought I’d leave that out for now.

Create our private first and last name.

  1. private var _firstName: String = null

When we set variables as private in the class they are not accessible from outside the class. Notice how the variable starts with “_” this is just one of the Scala naming conventions.

Create our constructor

  1. /**
  2. * @constructor Creates a person with first/last name
  3. * @param firstName the persons first name
  4. * @param lastName the persons last name
  5. */
  6. def this(firstName: String, lastName: String) {
  7. this()
  8. _firstName = firstName
  9. _lastName = lastName
  10. }

This is where we can set the first and last name when we instantiate our object.

Create a getter

  1. def firstName = _firstName

Create a setter

  1. def firstName_=(firstName: String) {
  2. _firstName = firstName
  3. }

Override toString

  1. override def toString = s"firstName = $firstName"

Notice how their is “s” before the string and we have $firstname there. That will reference the variable itself.

Create a Method

  1. def fullName: String = {
  2. return s"$firstName $lastName"
  3. }

This will just give you the full name of the person.

Putting it all together

  1. package models
  2.  
  3. class Person {
  4. private var _firstName: String = null
  5. private var _lastName: String = null
  6. /**
  7. * @constructor Creates a person with first/last name
  8. * @param firstName the persons first name
  9. * @param lastName the persons last name
  10. */
  11. def this(firstName: String, lastName: String) {
  12. this()
  13. _firstName = firstName
  14. _lastName = lastName
  15. }
  16. //Getter
  17. def firstName = _firstName
  18. def lastName = _lastName
  19. //Setter
  20. def firstName_=(firstName: String) {
  21. _firstName = firstName
  22. }
  23. def lastName_=(lastName: String) {
  24. _lastName = lastName
  25. }
  26. def fullName: String = {
  27. return s"$firstName $lastName"
  28. }
  29. override def toString = s"firstName = $firstName, lastName = $lastName"
  30. }

So what I have shown you above will get you started on creating your first class but you could make it alot cleaner with less code. it’s entirely up to you how you want to proceed and what you feel comfortable with.

  1. package models
  2.  
  3. class PersonCondensed {
  4. var firstName:String = null
  5. var lastName:String = null
  6. /**
  7. * @constructor Creates a person with first/last name
  8. * @param firstName the persons first name
  9. * @param lastName the persons last name
  10. */
  11. def this(firstName: String, lastName: String) {
  12. this()
  13. this.firstName = firstName
  14. this.lastName = lastName
  15. }
  16. def fullName: String = {
  17. return s"$firstName $lastName"
  18. }
  19. override def toString = s"firstName = $firstName, lastName = $lastName"
  20. }

Using our class

Here are the three different ways of calling our classes we did above.

  1. import models.Person
  2. import models.PersonCondensed
  3.  
  4. object Test {
  5. def main(args: Array[String]) {
  6. val person = new Person()
  7. person.firstName_=("John")
  8. person.lastName_=("Smith")
  9. person.value=(234)
  10. println(person.fullName)
  11. println(person.toString())
  12. val person2 = new Person("John", "Smith")
  13. println(person2.fullName)
  14. println(person2.toString())
  15. val person3 = new PersonCondensed()
  16. person3.firstName=("John")
  17. person3.lastName=("Smith")
  18. println(person3.firstName)
  19. println(person3.lastName)
  20. println(person3.fullName)
  21. println(person3.toString())
  22. }
  23. }

Eclipse Installation

In this tutorial I will show you how to install Eclipse using Ubuntu 16.04.

Install JDK 8

  1. sudo apt-get install openjdk-8-jdk

Download Oxygen.

  1. tar -xzvf eclipse-inst-linux64.tar.gz
  2. ~/eclipse-installer/eclipse-inst

Install Eclipse

Eclipse Desktop Shortcut

  1. cd ~/Desktop
  2. touch eclipse.desktop
  3. chmod u+x eclipse.desktop
  4. nano eclipse.desktop
  5.  
  6. #Add the below to the file
  7.  
  8. [Desktop Entry]
  9. Type=Application
  10. Name=Eclipse
  11. Icon=~/eclipse/java-oxygen/eclipse/icon.xpm
  12. Exec=~/eclipse/java-oxygen/eclipse/eclipse
  13. Terminal=false
  14. Categories=Development;IDE;Java;
  15. StartupWMClass=Eclipse

Hadoop & Java: Connect to Remote Kerberos HDFS using KeyTab

In this tutorial I will show you how to connect to remote Kerberos HDFS cluster using Java.  If you haven’t install hdfs with kerberos yet follow the tutorial.

Import SSL Cert to Java:

Follow this tutorial to “Installing unlimited strength encryption Java libraries

If on Windows do the following

  1. #Import it
  2. "C:\Program Files\Java\jdk1.8.0_171\bin\keytool" -import -file hadoop.csr -keystore "C:\Program Files\Java\jdk1.8.0_171\jre\lib\security\cacerts" -alias "hadoop"
  3.  
  4. #Check it
  5. "C:\Program Files\Java\jdk1.8.0_171\bin\keytool" -list -v -keystore "C:\Program Files\Java\jdk1.8.0_171\jre\lib\security\cacerts"
  6.  
  7. #If you want to delete it
  8. "C:\Program Files\Java\jdk1.8.0_171\bin\keytool" -delete -alias hadoop -keystore "C:\Program Files\Java\jdk1.8.0_171\jre\lib\security\cacerts"

POM.xml:

  1. <dependency>
  2. <groupId>org.apache.hadoop</groupId>
  3. <artifactId>hadoop-client</artifactId>
  4. <version>2.9.1</version>
  5. </dependency>

Imports:

  1. import org.apache.hadoop.conf.Configuration;
  2. import org.apache.hadoop.fs.FileStatus;
  3. import org.apache.hadoop.fs.FileSystem;
  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.security.UserGroupInformation;

Connect:

  1. // Setup the configuration object.
  2. final Configuration config = new Configuration();
  3.  
  4. config.set("fs.defaultFS", "swebhdfs://hadoop:50470");
  5. config.set("hadoop.security.authentication", "kerberos");
  6. config.set("hadoop.rpc.protection", "integrity");
  7.  
  8. System.setProperty("https.protocols", "TLSv1,TLSv1.1,TLSv1.2");
  9. System.setProperty("java.security.krb5.conf", "C:\\Program Files\\Java\\jdk1.8.0_171\\jre\\lib\\security\\krb5.conf");
  10. System.setProperty("java.security.krb5.realm", "REALM.CA");
  11. System.setProperty("java.security.krb5.kdc", "REALM.CA");
  12. System.setProperty("sun.security.krb5.debug", "true");
  13. System.setProperty("javax.net.debug", "all");
  14. System.setProperty("javax.net.ssl.keyStorePassword","YOURPASSWORD");
  15. System.setProperty("javax.net.ssl.keyStore","C:\\Program Files\\Java\\jdk1.8.0_171\\jre\\lib\\security\\cacerts");
  16. System.setProperty("javax.net.ssl.trustStore", "C:\\Program Files\\Java\\jdk1.8.0_171\\jre\\lib\\security\\cacerts");
  17. System.setProperty("javax.net.ssl.trustStorePassword","YOURPASSWORD");
  18. System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
  19.  
  20. UserGroupInformation.setConfiguration(config);
  21. UserGroupInformation.setLoginUser(UserGroupInformation.loginUserFromKeytabAndReturnUGI("myuser/hadoop@REALM.CA", "c:\\data\\myuser.keytab"));
  22.  
  23. System.out.println(UserGroupInformation.getLoginUser());
  24. System.out.println(UserGroupInformation.getCurrentUser());

VirtualBox

In this post I will just walk through a couple settings that you may need to configure. For these examples I am using Ubuntu 16.04.

Networking

If you want your virtualbox os to have it’s own IP on the network and accessable outside the vm then use “Bridged Adapter”.

  • Select “Enable Network Adapter”
  • Attached to: Bridged Adapter
  • Expand Advanced
  • Promiscuous Mode: Allow All
  • Select Cable Connected
  • Adapter Type: Desktop adapter.

If you want to just forward a port to localhost then use “NAT”.

  • Select “Enable Network Adapter”
  • Attached to: NAT
  • Expand Advanced
  • Adapter Type: Desktop adapter.
  • Click “Port Forwarding”
  • Add new Rule
    • Host IP: 127.0.0.1
    • Host Port: 22
    • Guest IP: Leave empty
    • Guest Port: 22

Shared Folders

If you want to share a folder from Host to Guest.

  • Click Add Share
  • Folder Path: Select folder from Host machine
    • I will us C:\data
  • Folder Name: What the share will be on the Guest
    • data
  • Turn on VM
  • Download https://download.virtualbox.org/virtualbox/5.2.12/VBoxGuestAdditions_5.2.12.iso
  • Mount VBoxGuestAdditions_5.2.12.iso
  • On the Guest Ubuntu server run
    • sudo mount /dev/cdrom /media/cdrom
  • Install build-essential
    • sudo apt-get install build-essential linux-headers-`uname –r`
  • Run VBoxGuestAdditions
    • sudo /media/cdrom/VBoxLinuxAdditions.run
  • sudo mkdir -p /mnt/data
  • sudo reboot
  • Mount Share
    • Ubuntu Server
      • sudo mount –t vboxsf data /mnt/data
    • Ubuntu Desktop
      • sudo mount -t vboxsf -o uid=$UID,gid=$(id -g) data /mnt/data/
  • cd /mnt/data
    • Now we can share files between host and guest.

HDFS/Yarn/MapRed: Kerberize/SSL

In this tutorial I will show you how to use Kerberos/SSL with HDFS/Yarn/MapRed. I will use self signed certs for this example. Before you begin ensure you have installed Kerberos Server and Hadoop.

This assumes your hostname is “hadoop”

Create Kerberos Principals

  1. cd /etc/security/keytabs/
  2.  
  3. sudo kadmin.local
  4.  
  5. #You can list princepals
  6. listprincs
  7.  
  8. #Create the following principals
  9. addprinc -randkey nn/hadoop@REALM.CA
  10. addprinc -randkey jn/hadoop@REALM.CA
  11. addprinc -randkey dn/hadoop@REALM.CA
  12. addprinc -randkey sn/hadoop@REALM.CA
  13. addprinc -randkey nm/hadoop@REALM.CA
  14. addprinc -randkey rm/hadoop@REALM.CA
  15. addprinc -randkey jhs/hadoop@REALM.CA
  16. addprinc -randkey HTTP/hadoop@REALM.CA
  17.  
  18. #We are going to create a user to access with later
  19. addprinc -pw hadoop myuser/hadoop@REALM.CA
  20. xst -k myuser.keytab myuser/hadoop@REALM.CA
  21.  
  22. #Create the keytab files.
  23. #You will need these for Hadoop to be able to login
  24. xst -k nn.service.keytab nn/hadoop@REALM.CA
  25. xst -k jn.service.keytab jn/hadoop@REALM.CA
  26. xst -k dn.service.keytab dn/hadoop@REALM.CA
  27. xst -k sn.service.keytab sn/hadoop@REALM.CA
  28. xst -k nm.service.keytab nm/hadoop@REALM.CA
  29. xst -k rm.service.keytab rm/hadoop@REALM.CA
  30. xst -k jhs.service.keytab jhs/hadoop@REALM.CA
  31. xst -k spnego.service.keytab HTTP/hadoop@REALM.CA

Set Keytab Permissions/Ownership

  1. sudo chown root:hadoopuser /etc/security/keytabs/*
  2. sudo chmod 750 /etc/security/keytabs/*

Stop the Cluster

  1. stop-dfs.sh
  2. stop-yarn.sh
  3. mr-jobhistory-daemon.sh --config $HADOOP_CONF_DIR stop historyserver

Hosts Update

  1. sudo nano /etc/hosts
  2.  
  3. #Remove 127.0.1.1 line
  4.  
  5. #Change 127.0.0.1 to the following
  6. #Notice how realm.ca is there its because we need to tell where that host resides
  7. 127.0.0.1 realm.ca hadoop localhost

hadoop-env.sh

We don’t set the HADOOP_SECURE_DN_USER because we are going to use Kerberos

  1. sudo nano /usr/local/hadoop/etc/hadoop/hadoop-env.sh
  2.  
  3. #Locate "export ${HADOOP_SECURE_DN_USER}=${HADOOP_SECURE_DN_USER}"
  4. #and change to
  5.  
  6. export HADOOP_SECURE_DN_USER=

core-site.xml

  1. nano /usr/local/hadoop/etc/hadoop/core-site.xml
  2.  
  3. <configuration>
  4. <property>
  5. <name>fs.defaultFS</name>
  6. <value>hdfs://NAMENODE:54310</value>
  7. <description>The name of the default file system. A URI whose scheme and authority determine the FileSystem implementation. The uri's scheme determines the config property (fs.SCHEME.impl) naming
  8. the FileSystem implementation class. The uri's authority is used to determine the host, port, etc. for a filesystem.</description>
  9. </property>
  10. <property>
  11. <name>hadoop.tmp.dir</name>
  12. <value>/app/hadoop/tmp</value>
  13. </property>
  14. <property>
  15. <name>hadoop.proxyuser.hadoopuser.hosts</name>
  16. <value>*</value>
  17. </property>
  18. <property>
  19. <name>hadoop.proxyuser.hadoopuser.groups</name>
  20. <value>*</value>
  21. </property>
  22. <property>
  23. <name>hadoop.security.authentication</name>
  24. <value>kerberos</value> <!-- A value of "simple" would disable security. -->
  25. </property>
  26. <property>
  27. <name>hadoop.security.authorization</name>
  28. <value>true</value>
  29. </property>
  30. <property>
  31. <name>hadoop.security.auth_to_local</name>
  32. <value>
  33. RULE:[2:$1@$0](nn/.*@.*REALM.TLD)s/.*/hdfs/
  34. RULE:[2:$1@$0](jn/.*@.*REALM.TLD)s/.*/hdfs/
  35. RULE:[2:$1@$0](dn/.*@.*REALM.TLD)s/.*/hdfs/
  36. RULE:[2:$1@$0](sn/.*@.*REALM.TLD)s/.*/hdfs/
  37. RULE:[2:$1@$0](nm/.*@.*REALM.TLD)s/.*/yarn/
  38. RULE:[2:$1@$0](rm/.*@.*REALM.TLD)s/.*/yarn/
  39. RULE:[2:$1@$0](jhs/.*@.*REALM.TLD)s/.*/mapred/
  40. DEFAULT
  41. </value>
  42. </property>
  43. <property>
  44. <name>hadoop.rpc.protection</name>
  45. <value>integrity</value>
  46. </property>
  47. <property>
  48. <name>hadoop.ssl.require.client.cert</name>
  49. <value>false</value>
  50. </property>
  51. <property>
  52. <name>hadoop.ssl.hostname.verifier</name>
  53. <value>DEFAULT</value>
  54. </property>
  55. <property>
  56. <name>hadoop.ssl.keystores.factory.class</name>
  57. <value>org.apache.hadoop.security.ssl.FileBasedKeyStoresFactory</value>
  58. </property>
  59. <property>
  60. <name>hadoop.ssl.server.conf</name>
  61. <value>ssl-server.xml</value>
  62. </property>
  63. <property>
  64. <name>hadoop.ssl.client.conf</name>
  65. <value>ssl-client.xml</value>
  66. </property>
  67. <property>
  68. <name>hadoop.rpc.protection</name>
  69. <value>integrity</value>
  70. </property>
  71. </configuration>

ssl-server.xml

Change ssl-server.xml.example to ssl-server.xml

  1. cp /usr/local/hadoop/etc/hadoop/ssl-server.xml.example /usr/local/hadoop/etc/hadoop/ssl-server.xml
  2.  
  3. nano /usr/local/hadoop/etc/hadoop/ssl-server.xml

Update properties

  1. <configuration>
  2. <property>
  3. <name>ssl.server.truststore.location</name>
  4. <value>/etc/security/serverKeys/truststore.jks</value>
  5. <description>Truststore to be used by NN and DN. Must be specified.</description>
  6. </property>
  7. <property>
  8. <name>ssl.server.truststore.password</name>
  9. <value>PASSWORD</value>
  10. <description>Optional. Default value is "".</description>
  11. </property>
  12. <property>
  13. <name>ssl.server.truststore.type</name>
  14. <value>jks</value>
  15. <description>Optional. The keystore file format, default value is "jks".</description>
  16. </property>
  17. <property>
  18. <name>ssl.server.truststore.reload.interval</name>
  19. <value>10000</value>
  20. <description>Truststore reload check interval, in milliseconds. Default value is 10000 (10 seconds).</description>
  21. </property>
  22. <property>
  23. <name>ssl.server.keystore.location</name>
  24. <value>/etc/security/serverKeys/keystore.jks</value>
  25. <description>Keystore to be used by NN and DN. Must be specified.</description>
  26. </property>
  27. <property>
  28. <name>ssl.server.keystore.password</name>
  29. <value>PASSWORD</value>
  30. <description>Must be specified.</description>
  31. </property>
  32. <property>
  33. <name>ssl.server.keystore.keypassword</name>
  34. <value>PASSWORD</value>
  35. <description>Must be specified.</description>
  36. </property>
  37. <property>
  38. <name>ssl.server.keystore.type</name>
  39. <value>jks</value>
  40. <description>Optional. The keystore file format, default value is "jks".</description>
  41. </property>
  42. <property>
  43. <name>ssl.server.exclude.cipher.list</name>
  44. <value>TLS_ECDHE_RSA_WITH_RC4_128_SHA,SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA,
  45. SSL_RSA_WITH_DES_CBC_SHA,SSL_DHE_RSA_WITH_DES_CBC_SHA,
  46. SSL_RSA_EXPORT_WITH_RC4_40_MD5,SSL_RSA_EXPORT_WITH_DES40_CBC_SHA,
  47. SSL_RSA_WITH_RC4_128_MD5</value>
  48. <description>Optional. The weak security cipher suites that you want excluded from SSL communication.</description>
  49. </property>
  50. </configuration>

ssl-client.xml

Change ssl-client.xml.example to ssl-client.xml

  1. cp /usr/local/hadoop/etc/hadoop/ssl-client.xml.example /usr/local/hadoop/etc/hadoop/ssl-client.xml
  2.  
  3. nano /usr/local/hadoop/etc/hadoop/ssl-client.xml

Update properties

  1. <configuration>
  2. <property>
  3. <name>ssl.client.truststore.location</name>
  4. <value>/etc/security/serverKeys/truststore.jks</value>
  5. <description>Truststore to be used by clients like distcp. Must be specified.</description>
  6. </property>
  7. <property>
  8. <name>ssl.client.truststore.password</name>
  9. <value>PASSWORD</value>
  10. <description>Optional. Default value is "".</description>
  11. </property>
  12. <property>
  13. <name>ssl.client.truststore.type</name>
  14. <value>jks</value>
  15. <description>Optional. The keystore file format, default value is "jks".</description>
  16. </property>
  17. <property>
  18. <name>ssl.client.truststore.reload.interval</name>
  19. <value>10000</value>
  20. <description>Truststore reload check interval, in milliseconds. Default value is 10000 (10 seconds).</description>
  21. </property>
  22. <property>
  23. <name>ssl.client.keystore.location</name>
  24. <value></value>
  25. <description>Keystore to be used by clients like distcp. Must be specified.</description>
  26. </property>
  27. <property>
  28. <name>ssl.client.keystore.password</name>
  29. <value></value>
  30. <description>Optional. Default value is "".</description>
  31. </property>
  32. <property>
  33. <name>ssl.client.keystore.keypassword</name>
  34. <value></value>
  35. <description>Optional. Default value is "".</description>
  36. </property>
  37. <property>
  38. <name>ssl.client.keystore.type</name>
  39. <value>jks</value>
  40. <description>Optional. The keystore file format, default value is "jks".</description>
  41. </property>
  42. </configuration>

mapred-site.xml

Just add the following to the config to let it know the Kerberos keytabs to use.

  1. nano /usr/local/hadoop/etc/hadoop/mapred-site.xml
  2.  
  3. <property>
  4. <name>mapreduce.jobhistory.keytab</name>
  5. <value>/etc/security/keytabs/jhs.service.keytab</value>
  6. </property>
  7. <property>
  8. <name>mapreduce.jobhistory.principal</name>
  9. <value>jhs/_HOST@REALM.CA</value>
  10. </property>
  11. <property>
  12. <name>mapreduce.jobhistory.http.policy</name>
  13. <value>HTTPS_ONLY</value>
  14. </property>

hdfs-site.xml

Add the following properties

  1. nano /usr/local/hadoop/etc/hadoop/hdfs-site.xml
  2.  
  3. <property>
  4. <name>dfs.http.policy</name>
  5. <value>HTTPS_ONLY</value>
  6. </property>
  7. <property>
  8. <name>hadoop.ssl.enabled</name>
  9. <value>true</value>
  10. </property>
  11. <property>
  12. <name>dfs.datanode.https.address</name>
  13. <value>NAMENODE:50475</value>
  14. </property>
  15. <property>
  16. <name>dfs.namenode.https-address</name>
  17. <value>NAMENODE:50470</value>
  18. <description>Your NameNode hostname for http access.</description>
  19. </property>
  20. <property>
  21. <name>dfs.namenode.secondary.https-address</name>
  22. <value>NAMENODE:50091</value>
  23. <description>Your Secondary NameNode hostname for http access.</description>
  24. </property>
  25. <property>
  26. <name>dfs.namenode.https-bind-host</name>
  27. <value>0.0.0.0</value>
  28. </property>
  29. <property>
  30. <name>dfs.block.access.token.enable</name>
  31. <value>true</value>
  32. <description> If "true", access tokens are used as capabilities for accessing datanodes. If "false", no access tokens are checked on accessing datanod</description>
  33. </property>
  34. <property>
  35. <name>dfs.namenode.kerberos.principal</name>
  36. <value>nn/_HOST@REALM.CA</value>
  37. <description> Kerberos principal name for the NameNode</description>
  38. </property>
  39. <property>
  40. <name>dfs.secondary.namenode.kerberos.principal</name>
  41. <value>sn/_HOST@REALM.CA</value>
  42. <description>Kerberos principal name for the secondary NameNode.</description>
  43. </property>
  44. <property>
  45. <name>dfs.web.authentication.kerberos.keytab</name>
  46. <value>/etc/security/keytabs/spnego.service.keytab</value>
  47. <description>The Kerberos keytab file with the credentials for the HTTP Kerberos principal used by Hadoop-Auth in the HTTP endpoint.</description>
  48. </property>
  49. <property>
  50. <name>dfs.namenode.keytab.file</name>
  51. <value>/etc/security/keytabs/nn.service.keytab</value>
  52. <description>Combined keytab file containing the namenode service and host principals.</description>
  53. </property>
  54. <property>
  55. <name>dfs.datanode.keytab.file</name>
  56. <value>/etc/security/keytabs/dn.service.keytab</value>
  57. <description>The filename of the keytab file for the DataNode.</description>
  58. </property>
  59. <property>
  60. <name>dfs.datanode.kerberos.principal</name>
  61. <value>dn/_HOST@REALM.CA</value>
  62. <description>The Kerberos principal that the DataNode runs as. "_HOST" is replaced by the real host name.</description>
  63. </property>
  64. <property>
  65. <name>dfs.namenode.kerberos.internal.spnego.principal</name>
  66. <value>${dfs.web.authentication.kerberos.principal}</value>
  67. </property>
  68. <property>
  69. <name>dfs.secondary.namenode.kerberos.internal.spnego.principal</name>
  70. <value>>${dfs.web.authentication.kerberos.principal}</value>
  71. </property>
  72. <property>
  73. <name>dfs.web.authentication.kerberos.principal</name>
  74. <value>HTTP/_HOST@REALM.CA</value>
  75. <description>The HTTP Kerberos principal used by Hadoop-Auth in the HTTP endpoint.</description>
  76. </property>
  77. <property>
  78. <name>dfs.data.transfer.protection</name>
  79. <value>integrity</value>
  80. </property>
  81. <property>
  82. <name>dfs.datanode.address</name>
  83. <value>NAMENODE:50010</value>
  84. </property>
  85. <property>
  86. <name>dfs.secondary.namenode.keytab.file</name>
  87. <value>/etc/security/keytabs/sn.service.keytab</value>
  88. </property>
  89. <property>
  90. <name>dfs.secondary.namenode.kerberos.internal.spnego.principal</name>
  91. <value>HTTP/_HOST@REALM.CA</value>
  92. </property>
  93. <property>
  94. <name>dfs.webhdfs.enabled</name>
  95. <value>true</value>
  96. </property>

Remove the following properties

  1. dfs.namenode.http-address
  2. dfs.namenode.secondary.http-address
  3. dfs.namenode.http-bind-host

yarn-site.xml

Add the following properties

  1. nano /usr/local/hadoop/etc/hadoop/yarn-site.xml
  2.  
  3. <property>
  4. <name>yarn.http.policy</name>
  5. <value>HTTPS_ONLY</value>
  6. </property>
  7. <property>
  8. <name>yarn.resourcemanager.webapp.https.address</name>
  9. <value>${yarn.resourcemanager.hostname}:8090</value>
  10. </property>
  11. <property>
  12. <name>yarn.resourcemanager.hostname</name>
  13. <value>NAMENODE</value>
  14. </property>
  15. <property>
  16. <name>yarn.nodemanager.bind-host</name>
  17. <value>0.0.0.0</value>
  18. </property>
  19. <property>
  20. <name>yarn.nodemanager.webapp.address</name>
  21. <value>${yarn.nodemanager.hostname}:8042</value>
  22. </property>
  23. <property>
  24. <name>yarn.resourcemanager.principal</name>
  25. <value>rm/_HOST@REALM.CA</value>
  26. </property>
  27. <property>
  28. <name>yarn.resourcemanager.keytab</name>
  29. <value>/etc/security/keytabs/rm.service.keytab</value>
  30. </property>
  31. <property>
  32. <name>yarn.nodemanager.principal</name>
  33. <value>nm/_HOST@REALM.CA</value>
  34. </property>
  35. <property>
  36. <name>yarn.nodemanager.keytab</name>
  37. <value>/etc/security/keytabs/nm.service.keytab</value>
  38. </property>
  39. <property>
  40. <name>yarn.nodemanager.hostname</name>
  41. <value>NAMENODE</value>
  42. </property>
  43. <property>
  44. <name>yarn.resourcemanager.bind-host</name>
  45. <value>0.0.0.0</value>
  46. </property>
  47. <property>
  48. <name>yarn.timeline-service.bind-host</name>
  49. <value>0.0.0.0</value>
  50. </property>

Remove the following properties

  1. yarn.resourcemanager.webapp.address

SSL

Setup SSL Directories

  1. sudo mkdir -p /etc/security/serverKeys
  2. sudo chown -R root:hadoopuser /etc/security/serverKeys/
  3. sudo chmod 755 /etc/security/serverKeys/
  4.  
  5. cd /etc/security/serverKeys

Setup Keystore

  1. sudo keytool -genkey -alias NAMENODE -keyalg RSA -keysize 1024 -dname "CN=NAMENODE,OU=ORGANIZATION_UNIT,C=canada" -keypass PASSWORD -keystore /etc/security/serverKeys/keystore.jks -storepass PASSWORD
  2. sudo keytool -export -alias NAMENODE -keystore /etc/security/serverKeys/keystore.jks -rfc -file /etc/security/serverKeys/NAMENODE.csr -storepass PASSWORD

Setup Truststore

  1. sudo keytool -import -noprompt -alias NAMENODE -file /etc/security/serverKeys/NAMENODE.csr -keystore /etc/security/serverKeys/truststore.jks -storepass PASSWORD

Generate Self Signed Certifcate

  1. sudo openssl genrsa -out /etc/security/serverKeys/NAMENODE.key 2048
  2.  
  3. sudo openssl req -x509 -new -key /etc/security/serverKeys/NAMENODE.key -days 300 -out /etc/security/serverKeys/NAMENODE.pem
  4.  
  5. sudo keytool -keystore /etc/security/serverKeys/keystore.jks -alias NAMENODE -certreq -file /etc/security/serverKeys/NAMENODE.cert -storepass PASSWORD -keypass PASSWORD
  6.  
  7. sudo openssl x509 -req -CA /etc/security/serverKeys/NAMENODE.pem -CAkey /etc/security/serverKeys/NAMENODE.key -in /etc/security/serverKeys/NAMENODE.cert -out /etc/security/serverKeys/NAMENODE.signed -days 300 -CAcreateserial

Setup File Permissions

  1. sudo chmod 440 /etc/security/serverKeys/*
  2. sudo chown root:hadoopuser /etc/security/serverKeys/*

Start the Cluster

  1. start-dfs.sh
  2. start-yarn.sh
  3. mr-jobhistory-daemon.sh --config $HADOOP_CONF_DIR start historyserver

Create User Directory

  1. kinit -kt /etc/security/keytabs/myuser.keytab myuser/hadoop@REALM.CA
  2. #ensure the login worked
  3. klist
  4.  
  5. #Create hdfs directory now
  6. hdfs dfs -mkdir /user
  7. hdfs dfs -mkdir /user/myuser
  8.  
  9. #remove kerberos ticket
  10. kdestroy

URL

https://NAMENODE:50470
https://NAMENODE:50475
https://NAMENODE:8090

References

https://www.ibm.com/support/knowledgecenter/en/SSPT3X_4.2.0/com.ibm.swg.im.infosphere.biginsights.admin.doc/doc/admin_ssl_hbase_mr_yarn_hdfs_web.html

Kerberos Server Installation

In this tutorial I will show you how to install Kerberos server on Ubuntu 16.04.

  1. sudo apt install krb5-kdc krb5-admin-server krb5-config -y

Enter your realm. I will use REALM.CA

Enter your servers. I will use localhost

Enter your administrative server. I will use localhost

Now you can click Ok and installation will continue.

Next we can create our new realm

  1. sudo krb5_newrealm

Enter your password then confirm it.

Now we can edit our kadm5.acl to have admin. Uncomment “*/admin *”

  1. sudo nano /etc/krb5kdc/kadm5.acl

Now we make our keytabs directory and grant the necessary permissions.

  1. sudo mkdir -p /etc/security/keytabs/
  2. sudo chown root:hduser /etc/security/keytabs
  3. sudo chmod 750 /etc/security/keytabs

Now we edit our krb5.conf file

  1. sudo nano /etc/krb5.conf

Ensure it looks like the below

  1. [libdefaults]
  2. default_realm = REALM.CA
  3.  
  4.  
  5. [realms]
  6. REALM.CA = {
  7. kdc = localhost
  8. admin_server = localhost
  9. }
  10.  
  11.  
  12. [domain_realm]
  13. .realm.ca = REALM.CA
  14. realm.ca = REALM.CA

Now we can restart the kerberos services

  1. sudo service krb5-kdc restart; service krb5-admin-server restart

Once you create a principal if when you attempt to use kadmin you get the error “GSS-API (or Kerberos) error while initializing kadmin interface”. Then do the following.

  1. sudo RUNLEVEL=1 apt-get install rng-tools
  2. cat /dev/random | rngtest -c 1000
  3. sudo apt-get install haveged
  4. cat /proc/sys/kernel/random/entropy_avail
  5. cat /dev/random | rngtest -c 1000
  6. haveged -n 2g -f - | dd of=/dev/null

Uninstallation

  1. sudo apt remove --purge krb5-kdc krb5-admin-server krb5-config -y
  2. sudo rm -rf /var/lib/krb5kdc

References
I used the following references as a guide.

http://blog.ruanbekker.com/blog/2017/10/18/setup-kerberos-server-and-client-on-ubuntu/ 
http://csetutorials.com/setup-kerberos-ubuntu.html  

Dropwizard: Swagger Integration

This entry is part 5 of 5 in the series Dropwizard

In this tutorial I will show you how to use Swagger in your Maven application. I will also show you how to configure it with Swagger UI so when you start your application you can see the Swagger UI from your generated JSON.

POM.xml

Dependencies

  1. <dependency>
  2. <groupId>io.dropwizard</groupId>
  3. <artifactId>dropwizard-assets</artifactId>
  4. <version>1.3.2</version>
  5. </dependency>
  6.  
  7. <dependency>
  8. <groupId>io.swagger</groupId>
  9. <artifactId>swagger-jaxrs</artifactId>
  10. <version>1.5.19</version>
  11. </dependency>

Plugins

maven-jar-plugin

If you followed creating a basic Dropwizard app then you should have this already installed. If so then just add the following two configs under “manifest” section.

  1. <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
  2. <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
maven-clean-plugin

Because we are pulling the latest Swagger-UI code on each build we must clean the old build.

  1. <plugin>
  2. <artifactId>maven-clean-plugin</artifactId>
  3. <version>3.1.0</version>
  4. <configuration>
  5. <filesets>
  6. <fileset>
  7. <directory>${basedir}/src/main/resources/swagger-ui</directory>
  8. <followSymlinks>false</followSymlinks>
  9. </fileset>
  10. </filesets>
  11. </configuration>
  12. </plugin>
download-maven-plugin

We are downloading the latest Swagger-UI code from github. Notice how lifecycle phase “generate-resources” is used. This is important due to build getting the proper code before beginning build.

  1. <plugin>
  2. <groupId>com.googlecode.maven-download-plugin</groupId>
  3. <artifactId>download-maven-plugin</artifactId>
  4. <version>1.4.0</version>
  5. <executions>
  6. <execution>
  7. <id>swagger-ui</id>
  8. <phase>generate-resources</phase>
  9. <goals>
  10. <goal>wget</goal>
  11. </goals>
  12. <configuration>
  13. <url>
  14. https://github.com/swagger-api/swagger-ui/archive/master.tar.gz
  15. </url>
  16. <unpack>true</unpack>
  17. <outputDirectory>
  18. ${project.build.directory}
  19. </outputDirectory>
  20. </configuration>
  21. </execution>
  22. </executions>
  23. </plugin>
replacer

This updates the code downloaded from github to have your swagger.json content instead of the petstore swagger content. Notice how lifecycle phase “generate-resources” is used. This is important due to build getting the proper code before beginning build.

  1. <plugin>
  2. <groupId>com.google.code.maven-replacer-plugin</groupId>
  3. <artifactId>replacer</artifactId>
  4. <version>1.5.3</version>
  5. <executions>
  6. <execution>
  7. <phase>generate-resources</phase>
  8. <goals>
  9. <goal>replace</goal>
  10. </goals>
  11. </execution>
  12. </executions>
  13. <configuration>
  14. <includes>
  15. <include>${project.build.directory}/swagger-ui-master/dist/index.html</include>
  16. <include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-bundle.js</include>
  17. <include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-bundle.js.map</include>
  18. <include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-standalone-preset.js</include>
  19. <include>${project.build.directory}/swagger-ui-master/dist/swagger-ui-standalone-preset.js.map</include>
  20. <include>${project.build.directory}/swagger-ui-master/dist/swagger-ui.js</include>
  21. <include>${project.build.directory}/swagger-ui-master/dist/swagger-ui.js.map</include>
  22. </includes>
  23. <replacements>
  24. <replacement>
  25. <token>http://petstore.swagger.io/v2/swagger.json</token>
  26. <value>/swagger.json</value>
  27. </replacement>
  28. </replacements>
  29. </configuration>
  30. </plugin>
maven-resources-plugin

This will copy the content that you just downloaded and modified into your resources folder. Notice how lifecycle phase “generate-resources” is used. This is important due to build getting the proper code before beginning build.

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-resources-plugin</artifactId>
  4. <version>3.1.0</version>
  5. <executions>
  6. <execution>
  7. <id>copy-resources</id>
  8. <phase>generate-resources</phase>
  9. <goals>
  10. <goal>copy-resources</goal>
  11. </goals>
  12. <configuration>
  13. <outputDirectory>
  14. ${basedir}/src/main/resources/swagger-ui
  15. </outputDirectory>
  16. <resources>
  17. <resource>
  18. <directory>
  19. ${project.build.directory}/swagger-ui-master/dist
  20. </directory>
  21. </resource>
  22. </resources>
  23. </configuration>
  24. </execution>
  25. </executions>
  26. </plugin>

Now if you run the following command you will see that the swagger-ui copied to your resources folder.

  1. mvn clean install

MyDropwizardAppApplication

initialize

Now we need to configure our Dropwizard app to host the swagger-ui that we recently downloaded and modified. In our “MyDropwizardAppApplication” class that we created in the initial Dropwizard tutorial we must add the AssetsBundle for our swagger-ui.

  1. @Override
  2. public void initialize(final Bootstrap bootstrap) {
  3. bootstrap.addBundle(GuiceBundle.builder().enableAutoConfig(this.getClass().getPackage().getName())
  4. .modules(new ServerModule()).build());
  5.  
  6. // This allows you to host swagger ui on this dropwizard app's host
  7. final AssetsBundle assetsBundle = new AssetsBundle("/swagger-ui", "/swagger-ui", "index.html");
  8. bootstrap.addBundle(assetsBundle);
  9. bootstrap.addCommand(new MyCommand());
  10. }
run

Now we need to setup our Swagger scanners for our api and our models.

  1. @Override
  2. public void run(final MyDropwizardAppConfiguration configuration, final Environment environment) {
  3. this.initSwagger(configuration, environment);
  4. }
  5.  
  6. private void initSwagger(MyDropwizardAppConfiguration configuration, Environment environment) {
  7. // Swagger Resource
  8. // The ApiListingResource creates the swagger.json file at localhost:8080/swagger.json
  9. environment.jersey().register(new ApiListingResource());
  10. environment.jersey().register(SwaggerSerializers.class);
  11.  
  12. Package objPackage = this.getClass().getPackage();
  13. String version = objPackage.getImplementationVersion();
  14.  
  15. // Swagger Scanner, which finds all the resources for @Api Annotations
  16. ScannerFactory.setScanner(new DefaultJaxrsScanner());
  17.  
  18. //This is what is shown when you do "http://localhost:8080/swagger-ui/"
  19. BeanConfig beanConfig = new BeanConfig();
  20. beanConfig.setVersion(version);
  21. beanConfig.setSchemes(new String[] { "http" });
  22. beanConfig.setHost("localhost:8080");
  23. beanConfig.setPrettyPrint(true);
  24. beanConfig.setDescription("The drpowizard apis");
  25. beanConfig.setResourcePackage("ca.gaudreault.mydropwizardapp");
  26. beanConfig.setScan(true);
  27. }

Now if we were to run our app we would be able to go to http://localhost:8080/swagger-ui/ and we would see our content but since we didn’t update any model or api then we wouldn’t see much of anything. So remember the previous tutorials on Dropwizard Guice and Dropwizard Resource. We will update those now.

Model

If you compare this to the one we did in the guice tutorial there are only a few differences. Notice we import the swagger annotations. We then add “ApiModel” annotation to the class and “ApiModelProperty” to the variable “value” and set it to be “NotNull”.

  1. package ca.gaudreault.mydropwizardapp.models;
  2.  
  3. import java.io.Serializable;
  4.  
  5. import javax.validation.constraints.NotNull;
  6.  
  7. import io.swagger.annotations.ApiModel;
  8. import io.swagger.annotations.ApiModelProperty;
  9.  
  10. @ApiModel(description = "My Example Model.")
  11. public class MyModel implements Serializable {
  12. private static final long serialVersionUID = 1L;
  13. @NotNull
  14. @ApiModelProperty(required = true, notes = "My value")
  15. private Integer value;
  16. public Integer getValue() {
  17. return value;
  18. }
  19. public void setValue(Integer value) {
  20. this.value = value;
  21. }
  22. }

Resource

If you compare this to the one we did in the guice tutorial there are only a few differences. Notice our class has “@SwaggerDefinition” and “@API” defined. This will help the Swagger-UI  group your end points together using the tags. Also notice how our “runTest” end point has “@Path”, “@ApiResponses” and “@ApiOperation” now.

  1. package ca.gaudreault.mydropwizardapp.resources;
  2.  
  3. import javax.ws.rs.GET;
  4. import javax.ws.rs.Path;
  5. import javax.ws.rs.Produces;
  6. import javax.ws.rs.core.MediaType;
  7.  
  8. import org.eclipse.jetty.http.HttpStatus;
  9.  
  10. import com.codahale.metrics.annotation.Timed;
  11. import com.google.inject.Inject;
  12.  
  13. import ca.gaudreault.mydropwizardapp.models.MyModel;
  14. import ca.gaudreault.mydropwizardapp.services.MyService;
  15. import io.swagger.annotations.Api;
  16. import io.swagger.annotations.ApiOperation;
  17. import io.swagger.annotations.ApiResponses;
  18. import io.swagger.annotations.ApiResponse;
  19. import io.swagger.annotations.SwaggerDefinition;
  20. import io.swagger.annotations.Tag;
  21.  
  22. @SwaggerDefinition(tags = { @Tag(name = "MyResource", description = "My Example Resource") })
  23. @Api(value = "MyResource")
  24. @Timed
  25. @Path("/my-resource")
  26. public class MyResource {
  27. private MyService myService;
  28.  
  29. @Inject
  30. public MyResource(final MyService myService) {
  31. this.myService = myService;
  32. }
  33.  
  34. @GET
  35. @Path("/runTest")
  36. @ApiOperation(value = "Run test and returns myModel", notes = "Run test and returns myModel", response = MyModel.class, tags = {
  37. "MyResource" })
  38. @ApiResponses(value = {
  39. @ApiResponse(code = HttpStatus.OK_200, message = "Successfully Tested", response = MyModel.class) })
  40. @Timed
  41. @Produces(MediaType.APPLICATION_JSON)
  42. public MyModel runTest() {
  43. return this.myService.runTest();
  44. }
  45. }

Run our Project

If we run our project and we hit the following rest end point http://localhost:8080/my-resource/runTest we will get back the below. This shows us our rest end point is working as expected still.

  1. {"value":123123}

Checking Swagger-UI

Now that we have started our project we can now check to see what was generated. Go to Swagger-UI. You will see the below. You are now well on your way in using Swagger.

Model Expanded

Resource Expanded

 

 

 

 

References

The following helped me build this tutorial.

  • https://robferguson.org/blog/2016/12/11/resteasy-embedded-jetty-fat-jars-swagger-and-swagger-ui/
  • https://itazuramono.com/2015/12/07/automatic-swagger-documentation-for-dropwizard-using-maven/
  • http://mikelynchgames.com/software-development/adding-swagger-to-your-dropwizard-application/

Java: JUnit 4 /w PowerMock

In this tutorial I will show you how to use JUnit 4 with PowerMock for mocking Static classes into your application. If you have not already done so follow JUnit 4 tutorial.

POM.xml

  1. <dependency>
  2. <groupId>org.mockito</groupId>
  3. <artifactId>mockito-core</artifactId>
  4. <version>2.18.3</version>
  5. <scope>test</scope>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.assertj</groupId>
  9. <artifactId>assertj-core</artifactId>
  10. <version>3.10.0</version>
  11. <scope>test</scope>
  12. </dependency>

Static Class

We will create this class to use for our static testing.

  1. public final class MyStaticTest {
  2. public static String getString() {
  3. return "test";
  4. }
  5. }

Imports

  1. import static org.assertj.core.api.Assertions.assertThat;
  2. import static org.mockito.Mockito.when;
  3.  
  4. import org.junit.Before;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.mockito.MockitoAnnotations;
  8. import org.powermock.api.mockito.PowerMockito;
  9. import org.powermock.core.classloader.annotations.PrepareForTest;
  10. import org.powermock.modules.junit4.PowerMockRunner;

Test Class

Now we can run our test with PowerMock and mock our static classes methods as you can see from the below.

  1. @RunWith(PowerMockRunner.class)
  2. @PrepareForTest({ MyStaticTest.class })
  3. public class AppTestStatic {
  4. @Before
  5. public void setup() {
  6. MockitoAnnotations.initMocks(this);
  7. PowerMockito.mockStatic(MyStaticTest.class);
  8. }
  9.  
  10. @Test
  11. public void myTest() {
  12. when(MyStaticTest.getString()).thenReturn("myTest");
  13.  
  14. final String returnString = MyStaticTest.getString();
  15.  
  16. assertThat(returnString).isEqualTo("myTest");
  17. }
  18. }

 

Java: JUnit 4 Example

In this tutorial I will show you how to use JUnit 4 into your application. The next tutorial I will use this class with PowerMock.

Build Path

Ensure you have added JUnit 4 to your build path and that you are using Java 8.

Imports

  1. import org.junit.Before;
  2. import org.junit.Test;

Test Class

  1. package ca.gaudreault.mytestapp;
  2.  
  3. import org.junit.Before;
  4. import org.junit.Test;
  5.  
  6. public class AppTest {
  7. @Before
  8. public void setup() {
  9. }
  10.  
  11. @Test
  12. public void myTest() {
  13. }
  14. }

This was a very basic example of writing a unit test with JUnit 4. In future example I will build on this with PowerMock.

Dropwizard: Resource

This entry is part 4 of 5 in the series Dropwizard

In this tutorial I will give a basic example of a resource endpoint. If you haven’t configured Guice yet please do so before continuing.

So basically now that you have Guice configured and working you can now create an api endpoint. For this we will just use a GET but you can also do POST, PUT, DELETE.

  1. package ca.gaudreault.mydropwizardapp.resources;
  2.  
  3. import javax.ws.rs.GET;
  4. import javax.ws.rs.Path;
  5. import javax.ws.rs.Produces;
  6. import javax.ws.rs.core.MediaType;
  7.  
  8. import com.codahale.metrics.annotation.Timed;
  9. import com.google.inject.Inject;
  10.  
  11. import ca.gaudraeult.mydropwizardapp.services.MyService;
  12. import ca.gaudreault.mydropwizardapp.models.MyModel;
  13.  
  14. @Timed
  15. @Path("/my-resource")
  16. public class MyResource {
  17. MyService myService;
  18.  
  19. @Inject
  20. public MyResource(final MyService myService) {
  21. this.myService = myService;
  22. }
  23.  
  24. @GET
  25. @Timed
  26. @Produces(MediaType.APPLICATION_JSON)
  27. public MyModel runTest() {
  28. return this.myService.runTest();
  29. }
  30. }

Once you run your application you can view the endpoint by going to http://localhost:8080/my-resource.

The output will be as follows.

  1. {"value":123123}

If you noticed we added the “@Timed” annotation. You can now go to http://localhost:8081/metrics?pretty=true to view the metrics on our “runTest” method. The output will look like the below.

  1. {
  2. "ca.gaudreault.mydropwizardapp.resources.MyResource.runTest": {
  3. "count": 0,
  4. "max": 0.0,
  5. "mean": 0.0,
  6. "min": 0.0,
  7. "p50": 0.0,
  8. "p75": 0.0,
  9. "p95": 0.0,
  10. "p98": 0.0,
  11. "p99": 0.0,
  12. "p999": 0.0,
  13. "stddev": 0.0,
  14. "m15_rate": 0.0,
  15. "m1_rate": 0.0,
  16. "m5_rate": 0.0,
  17. "mean_rate": 0.0,
  18. "duration_units": "seconds",
  19. "rate_units": "calls/second"
  20. }

Dropwizard: Command

This entry is part 3 of 5 in the series Dropwizard

In this tutorial I will give a brief demonstration on how to write a custom dropwizard command.

MyCommand

So below you will see the command class and how we are creating and registering a command line param called “test” which is a Boolean.

  1. package ca.gaudreault.mydropwizardapp;
  2.  
  3. import io.dropwizard.cli.Command;
  4. import io.dropwizard.setup.Bootstrap;
  5. import net.sourceforge.argparse4j.inf.Namespace;
  6. import net.sourceforge.argparse4j.inf.Subparser;
  7.  
  8. public class MyCommand extends Command {
  9.  
  10. protected MyCommand() {
  11. super("myCommand", "This is a sample command");
  12. }
  13.  
  14. @Override
  15. public void configure(Subparser subparser) {
  16. subparser.addArgument("-test").required(true).type(Boolean.class).dest("test").help("Does something really awesome");
  17. }
  18.  
  19. @Override
  20. public void run(Bootstrap<?> bootstrap, Namespace namespace) throws Exception {
  21. System.out.println("MyCommand " + namespace.getBoolean("test"));
  22. }
  23. }

MyDropwizardAppApplication

If you remember from part 1 of this series you created the based Dropwizard app. So you should have a class called “MyDropwizardAppApplication”. Open that now and modify the “initialize” like the below. Note that we are only adding the “addCommand”.

  1. @Override
  2. public void initialize(final Bootstrap bootstrap) {
  3. bootstrap.addCommand(new MyCommand());
  4. }

Executing Command

Basically now we can just call our JAR file and pass the following arguments to it.

  1. myCommand -test false

You will see once it runs that following

  1. MyCommand false

Dropwizard: Guice Bundle

This entry is part 2 of 5 in the series Dropwizard

In this tutorial I will show you how to add Guice to your Dropwizard app. This will be a very basic implementation. Some things you should note is that I didn’t put in any docstrings. You should always do that!

Now there are a few Dropwizard Guice integrations available but the most active is the one I will show you today called “dropwizard-guicey“.

POM.xml

  1. <dependency>
  2. <groupId>ru.vyarus</groupId>
  3. <artifactId>dropwizard-guicey</artifactId>
  4. <version>4.1.0</version>
  5. </dependency>

Model

Now we create a model to use with our service

  1. package ca.gaudreault.mydropwizardapp.models;
  2.  
  3. import java.io.Serializable;
  4.  
  5. import javax.validation.constraints.NotNull;
  6.  
  7. public class MyModel implements Serializable {
  8. private static final long serialVersionUID = 1L;
  9. private Integer value;
  10. public Integer getValue() {
  11. return value;
  12. }
  13. public void setValue(Integer value) {
  14. this.value = value;
  15. }
  16. }

Service

Here you will create your service interface and class so that you can bind it in the guice module.

Interface

  1. package ca.gaudraeult.mydropwizardapp.services;
  2.  
  3. import ca.gaudreault.mydropwizardapp.models.MyModel;
  4.  
  5. public interface MyService {
  6. MyModel runTest();
  7. }

Implementation

  1. package ca.gaudraeult.mydropwizardapp.services;
  2.  
  3. import ca.gaudreault.mydropwizardapp.models.MyModel;
  4.  
  5. public class MyServiceImpl implements MyService {
  6. public MyServiceImpl() { }
  7.  
  8. @Override
  9. public MyModel runTest() {
  10. final MyModel myModel = new MyModel();
  11. myModel.setValue(123123);
  12. return myModel;
  13. }
  14. }

ServerModule

Now when we create our module class you can bind the interface to the implementation. Note that if your implementation does not implement the interface this will not work.

  1. package ca.gaudreault.mydropwizardapp;
  2.  
  3. import com.google.inject.AbstractModule;
  4.  
  5. import ca.gaudraeult.mydropwizardapp.services.MyService;
  6. import ca.gaudraeult.mydropwizardapp.services.MyServiceImpl;
  7.  
  8. public class ServerModule extends AbstractModule {
  9.  
  10. @Override
  11. protected void configure() {
  12. bind(MyService.class).to(MyServiceImpl.class);
  13. }
  14. }

Dropwizard Application

If you remember from part 1 of this series you created the based Dropwizard app. So you should have a class called “MyDropwizardAppApplication”. Open that now and modify the “initialize” like the below. Baseically here we are registering our ServerModule class to Dropwizard.

  1. @Override
  2. public void initialize(final Bootstrap bootstrap) {
  3. bootstrap.addBundle(GuiceBundle.builder()
  4. .enableAutoConfig(this.getClass().getPackage().getName())
  5. .modules(new ServerModule())
  6. .build());
  7. }

And that is it you have configured a very basic Dropwizard Guice configuration.

ElasticSearch: High Level Client Search Scrolling

This entry is part 4 of 4 in the series ElasticSearch High Level Rest Client

In this tutorial I will show you how to perform a search scroll using the high level client. If you have not already done so please follow the search tutorial.

The reason you following the search tutorial first is that sets up the search. So you just have to do a few more steps.

Imports:

  1. import org.elasticsearch.action.search.SearchScrollRequest;
  2. import org.elasticsearch.common.unit.TimeValue;

Modify the “SearchRequest”. A recommended timeout is 60000 or 1m.

  1. request.scroll(new TimeValue(60000));

Once you perform the initial search now you will get a “scrollId”. Use that to generate your new “SearchScrollRequest” using that scrollId. One thing to note is the “scrollRequest” timeout value. Set this or it may not work.

  1. final SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
  2. searchScrollRequest.scroll(new TimeValue(60000));

Now the searchResponse that we used initially we can repurpose to continue scrolling the results.

  1. searchResponse = client.searchScroll(searchScrollRequest);

We know that their are no more results when the scrollId is null or when getHits length is 0.

  1. searchResponse.getHits().getHits().length > 0

ElasticSearch: High Level Client Search

This entry is part 3 of 4 in the series ElasticSearch High Level Rest Client

In this tutorial I will show you how to perform a search using the high level client. If you have not already done so please connect to ElasticSearch.

Imports

  1. import org.elasticsearch.action.search.SearchRequest;
  2. import org.elasticsearch.search.builder.SearchSourceBuilder;
  3. import org.elasticsearch.action.search.SearchResponse;
  4. import org.elasticsearch.search.SearchHits;
  5. import org.elasticsearch.search.SearchHit;
  6. import org.elasticsearch.action.search.SearchType;

Now we can perform the search.

  1. final SearchRequest request = new SearchRequest();
  2. request.searchType(SearchType.QUERY_THEN_FETCH);
  3.  
  4. final String[] types = { "doc" };
  5. final String[] indexes = { "index" };
  6.  
  7. //Specify the types that your search applies to.
  8. //Note that this is not needed. If ommitted it will search all.
  9. request.types(types);
  10.  
  11. //Specify the indexes that your search applies to.
  12. //Note that this is not needed. If ommitted it will search all.
  13. request.indices(indexes);
  14.  
  15. final SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
  16. //You can add any type of query into this query. Adjust to what you need.
  17. searchSourceBuilder.query(MyQuery);
  18. request.source(searchSourceBuilder);
  19.  
  20. final SearchResponse searchResponse = client.search(request);
  21.  
  22. //This will let us know if the search was terminated early.
  23. final Boolean terminatedEarly = searchResponse.isTerminatedEarly();
  24. //This will let us know if it timed out.
  25. final boolean timedOut = searchResponse.isTimedOut();
  26.  
  27. //Now to loop through our hits to do what we need to
  28. final SearchHits searchHits = searchResponse.getHits();
  29. for (final SearchHit hit : searchHits) {
  30. //Do work
  31. }

 

 

 

ElasticSearch: High Level Client Post

This entry is part 2 of 4 in the series ElasticSearch High Level Rest Client

In this tutorial I will show you how to perform a POST request. If you have not connected first please do so before continuing.

Imports

  1. import org.apache.http.HttpEntity;
  2. import org.apache.http.nio.entity.NStringEntity;
  3. import org.apache.http.entity.ContentType;
  4. import org.apache.http.util.EntityUtils;
  5. import org.elasticsearch.client.Response;

Now we can perform the POST to ElasticSearch.

  1. final Integer id = 1;
  2. final String document = "{\"key\": 1 }";
  3. final HttpEntity httpEntity = new NStringEntity(document, ContentType.APPLICATION_JSON);
  4.  
  5. final Response response = restHighLevelClient.getLowLevelClient().performRequest("POST", "/indexName/indexType/" + id, Collections.<String, String>emptyMap(), httpEntity);
  6.  
  7. //Now you can print the response
  8. System.out.println(EntityUtils.toString(response.getEntity()));

ElasticSearch: Low Level Client Get

This entry is part 3 of 3 in the series ElasticSearch Low Level Rest Client

In this tutorial I will show you how to put a json document into ElasticSearch. If you have not first connected to ElasticSearch please do so before continuing.

POM.xml

  1. <dependency>
  2. <groupId>com.fasterxml.jackson.core</groupId>
  3. <artifactId>jackson-databind</artifactId>
  4. <version>2.9.5</version>
  5. </dependency>

Imports

  1. import org.apache.http.HttpEntity;
  2. import org.apache.http.nio.entity.NStringEntity;
  3. import org.apache.http.entity.ContentType;
  4. import org.elasticsearch.client.Response;
  5. import org.apache.http.util.EntityUtils;

Now perform the GET request using the low level client.

  1. ObjectMapper objectMapper = new ObjectMapper();
  2. final String document = "{\"key\": 1 }";
  3. final JsonNode document = objectMapper.readTree("{" +
  4. " \"query\": {" +
  5. " \"match\" : {" +
  6. " \"key\" : 1 }}}");
  7. final HttpEntity httpEntity = new NStringEntity(document.toString(), ContentType.APPLICATION_JSON);
  8. final Response response = restClient.performRequest("GET", "/indexName/indexType/_search", Collections.<String, String>emptyMap(), httpEntity);
  9. //Now you can print the response
  10. System.out.println(EntityUtils.toString(response.getEntity()));
  11.  
  12. //OR get the content
  13. final JsonNode content = objectMapper.readTree(response.getEntity().getContent());
  14. System.out.println(content);

ElasticSearch: Low Level Client Put

This entry is part 2 of 3 in the series ElasticSearch Low Level Rest Client

In this tutorial I will show you how to put a json document into ElasticSearch. If you have not first connected to ElasticSearch please do so before continuing.

Imports

  1. import org.apache.http.HttpEntity;
  2. import org.apache.http.nio.entity.NStringEntity;
  3. import org.elasticsearch.client.Response;
  4. import org.apache.http.entity.ContentType;
  5. import org.apache.http.util.EntityUtils;

Now perform the PUT request using the low level client.

  1. final String document = "{\"key\": 1 }";
  2. final HttpEntity httpEntity = new NStringEntity(document, ContentType.APPLICATION_JSON);
  3. final Integer id = 1;
  4. final Response response = restClient.performRequest("PUT", "/indexName/indexType/" + id, Collections.<String, String>emptyMap(), httpEntity);
  5.  
  6. //Now you can print the response
  7. System.out.println(EntityUtils.toString(response.getEntity()));

ElasticSearch: High Level Rest Client Connection

This entry is part 1 of 4 in the series ElasticSearch High Level Rest Client

In this tutorial I will show you how to use the ElasticSearch high level rest client.

First you will need to add the low level rest to the pom.

  1. <properties>
  2. <elasticSearch.version>6.2.4</elasticSearch.version>
  3. </properties>
  4.  
  5. <dependency>
  6. <groupId>org.elasticsearch.client</groupId>
  7. <artifactId>elasticsearch-rest-high-level-client</artifactId>
  8. <version>${elasticSearch.version}</version>
  9. </dependency>

Next you will need to specify the imports.

  1. import java.util.List;
  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import org.apache.http.HttpHost;
  5. import org.elasticsearch.client.RestClient;
  6. import org.elasticsearch.client.RestClientBuilder;
  7. import org.elasticsearch.client.RestHighLevelClient;

Now you can connect to ElasticSearch.

  1. final List hosts = new ArrayList<>(Arrays.asList("localhost"));
  2. final Integer port = 9200;
  3. final String scheme = "http";
  4. final HttpHost[] httpHosts = hosts.stream().map(host -> new HttpHost(host, port, scheme)).toArray(HttpHost[]::new);
  5.  
  6. final RestClientBuilder restClientBuilder = RestClient.builder(httpHosts);
  7. final RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClientBuilder);

Now you can do whatever you need to!

ElasticSearch: Low Level Rest Client Connection

This entry is part 1 of 3 in the series ElasticSearch Low Level Rest Client

In this tutorial I will show you how to use the ElasticSearch low level rest client.

First you will need to add the low level rest to the pom.

  1. <properties>
  2. <elasticSearch.version>6.2.4</elasticSearch.version>
  3. </properties>
  4.  
  5. <dependency>
  6. <groupId>org.elasticsearch.client</groupId>
  7. <artifactId>elasticsearch-rest-client</artifactId>
  8. <version>${elasticSearch.version}</version>
  9. </dependency>

Next you will need to specify the imports.

  1. import org.apache.http.HttpHost;
  2. import org.elasticsearch.client.Response;
  3. import org.elasticsearch.client.RestClient;
  4. import org.elasticsearch.client.RestClientBuilder;

Now you can connect to ElasticSearch.

  1. final RestClientBuilder restClientBuilder = RestClient.builder(new HttpHost("localhost", 9200, "http"));
  2. final RestClient restClient = builder.build();

Now you can do whatever you need to!