diff --git a/JGit/README.md b/JGit/README.md
new file mode 100644
index 0000000000..5c65f1101b
--- /dev/null
+++ b/JGit/README.md
@@ -0,0 +1,3 @@
+## Relevant articles:
+
+- [A Guide to JGit](http://www.baeldung.com/jgit)
diff --git a/algorithms/README.md b/algorithms/README.md
new file mode 100644
index 0000000000..42f696d9be
--- /dev/null
+++ b/algorithms/README.md
@@ -0,0 +1,4 @@
+## Relevant articles:
+
+- [Dijkstra Algorithm in Java](http://www.baeldung.com/java-dijkstra)
+- [Introduction to Cobertura](http://www.baeldung.com/cobertura)
diff --git a/algorithms/pom.xml b/algorithms/pom.xml
index 0c85a19534..f72457650a 100644
--- a/algorithms/pom.xml
+++ b/algorithms/pom.xml
@@ -41,4 +41,23 @@
-
\ No newline at end of file
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ 2.7
+
+
+
+ com/baeldung/algorithms/dijkstra/*
+
+
+ com/baeldung/algorithms/dijkstra/*
+
+
+
+
+
+
+
diff --git a/apache-bval/README.md b/apache-bval/README.md
new file mode 100644
index 0000000000..80ea149993
--- /dev/null
+++ b/apache-bval/README.md
@@ -0,0 +1,2 @@
+### Relevant Articles:
+- [Intro to Apache BVal](http://www.baeldung.com/apache-bval)
diff --git a/apache-bval/pom.xml b/apache-bval/pom.xml
new file mode 100644
index 0000000000..5d556af56f
--- /dev/null
+++ b/apache-bval/pom.xml
@@ -0,0 +1,51 @@
+
+ 4.0.0
+ apache-bval
+ apache-bval
+ 0.0.1-SNAPSHOT
+
+
+
+ org.apache.bval
+ bval-jsr
+ ${bval.version}
+
+
+ javax.validation
+ validation-api
+ 1.1.0.Final
+
+
+ org.apache.bval
+ bval-extras
+ ${bval.version}
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ 1.8
+ 1.8
+
+
+
+
+
+ 3.6.0
+ 4.12
+ 1.1.2
+
+
\ No newline at end of file
diff --git a/apache-bval/src/main/java/com/baeldung/model/User.java b/apache-bval/src/main/java/com/baeldung/model/User.java
new file mode 100644
index 0000000000..477136ddb4
--- /dev/null
+++ b/apache-bval/src/main/java/com/baeldung/model/User.java
@@ -0,0 +1,120 @@
+package com.baeldung.model;
+
+import java.io.File;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import org.apache.bval.constraints.Email;
+import org.apache.bval.constraints.NotEmpty;
+import org.apache.bval.extras.constraints.checkdigit.IBAN;
+import org.apache.bval.extras.constraints.creditcard.Visa;
+import org.apache.bval.extras.constraints.file.Directory;
+import org.apache.bval.extras.constraints.net.InetAddress;
+
+import com.baeldung.validation.Password;
+
+public class User {
+ @NotNull
+ @Email
+ private String email;
+
+ @NotEmpty
+ @Password
+ private String password;
+
+ @Size(min = 1, max = 20)
+ private String name;
+
+ @Min(18)
+ private int age;
+
+ @Visa
+ private String cardNumber = "";
+
+ @IBAN
+ private String iban = "";
+
+ @InetAddress
+ private String website = "";
+
+ @Directory
+ private File mainDirectory=new File(".");
+
+ public User() {
+ }
+
+ public User(String email, String password, String name, int age) {
+ super();
+ this.email = email;
+ this.password = password;
+ this.name = name;
+ this.age = age;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getCardNumber() {
+ return cardNumber;
+ }
+
+ public void setCardNumber(String cardNumber) {
+ this.cardNumber = cardNumber;
+ }
+
+ public String getIban() {
+ return iban;
+ }
+
+ public void setIban(String iban) {
+ this.iban = iban;
+ }
+
+ public String getWebsite() {
+ return website;
+ }
+
+ public void setWebsite(String website) {
+ this.website = website;
+ }
+
+ public File getMainDirectory() {
+ return mainDirectory;
+ }
+
+ public void setMainDirectory(File mainDirectory) {
+ this.mainDirectory = mainDirectory;
+ }
+
+}
diff --git a/apache-bval/src/main/java/com/baeldung/validation/Password.java b/apache-bval/src/main/java/com/baeldung/validation/Password.java
new file mode 100644
index 0000000000..4ae06b2fb0
--- /dev/null
+++ b/apache-bval/src/main/java/com/baeldung/validation/Password.java
@@ -0,0 +1,25 @@
+package com.baeldung.validation;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+import static java.lang.annotation.ElementType.*;
+
+@Constraint(validatedBy = { PasswordValidator.class })
+@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Password {
+ String message() default "Invalid password";
+
+ Class>[] groups() default {};
+
+ Class extends Payload>[] payload() default {};
+
+ int length() default 6;
+
+ int nonAlpha() default 1;
+}
diff --git a/apache-bval/src/main/java/com/baeldung/validation/PasswordValidator.java b/apache-bval/src/main/java/com/baeldung/validation/PasswordValidator.java
new file mode 100644
index 0000000000..19038d04d5
--- /dev/null
+++ b/apache-bval/src/main/java/com/baeldung/validation/PasswordValidator.java
@@ -0,0 +1,35 @@
+package com.baeldung.validation;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+public class PasswordValidator implements ConstraintValidator {
+
+ private int length;
+ private int nonAlpha;
+
+ @Override
+ public void initialize(Password password) {
+ this.length = password.length();
+ this.nonAlpha = password.nonAlpha();
+
+ }
+
+ @Override
+ public boolean isValid(String value, ConstraintValidatorContext context) {
+ if (value.length() < length) {
+ return false;
+ }
+ int nonAlphaNr = 0;
+ for (int i = 0; i < value.length(); i++) {
+ if (!Character.isLetterOrDigit(value.charAt(i))) {
+ nonAlphaNr++;
+ }
+ }
+ if (nonAlphaNr < nonAlpha) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/apache-bval/src/test/java/com/baeldung/validation/ValidationTest.java b/apache-bval/src/test/java/com/baeldung/validation/ValidationTest.java
new file mode 100644
index 0000000000..cd58d4460a
--- /dev/null
+++ b/apache-bval/src/test/java/com/baeldung/validation/ValidationTest.java
@@ -0,0 +1,97 @@
+package com.baeldung.validation;
+
+import java.io.File;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+import org.apache.bval.jsr.ApacheValidationProvider;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+import com.baeldung.model.User;
+
+public class ValidationTest {
+ private static ValidatorFactory validatorFactory;
+ private static Validator validator;
+
+ @BeforeClass
+ public static void setup() {
+ validatorFactory = Validation.byProvider(ApacheValidationProvider.class)
+ .configure()
+ .buildValidatorFactory();
+ validator = validatorFactory.getValidator();
+ }
+
+ @Test
+ public void givenUser_whenValidate_thenValidationViolations() {
+ User user = new User("ana@yahoo.com", "pass", "nameTooLong_______________", 15);
+
+ Set> violations = validator.validate(user);
+ assertTrue("no violations", violations.size() > 0);
+ }
+
+ @Test
+ public void givenInvalidAge_whenValidateProperty_thenConstraintViolation() {
+ User user = new User("ana@yahoo.com", "pass", "Ana", 12);
+
+ Set> propertyViolations = validator.validateProperty(user, "age");
+ assertEquals("size is not 1", 1, propertyViolations.size());
+ }
+
+ @Test
+ public void givenValidAge_whenValidateValue_thenNoConstraintViolation() {
+ User user = new User("ana@yahoo.com", "pass", "Ana", 18);
+
+ Set> valueViolations = validator.validateValue(User.class, "age", 20);
+ assertEquals("size is not 0", 0, valueViolations.size());
+ }
+
+ @Test
+ public void whenValidateNonJSR_thenCorrect() {
+ User user = new User("ana@yahoo.com", "pass", "Ana", 20);
+ user.setCardNumber("1234");
+ user.setIban("1234");
+ user.setWebsite("10.0.2.50");
+ user.setMainDirectory(new File("."));
+
+ Set> violations = validator.validateProperty(user, "iban");
+ assertEquals("size is not 1", 1, violations.size());
+
+ violations = validator.validateProperty(user, "website");
+ assertEquals("size is not 0", 0, violations.size());
+
+ violations = validator.validateProperty(user, "mainDirectory");
+ assertEquals("size is not 0", 0, violations.size());
+ }
+
+ @Test
+ public void givenInvalidPassword_whenValidatePassword_thenConstraintViolation() {
+ User user = new User("ana@yahoo.com", "password", "Ana", 20);
+ Set> violations = validator.validateProperty(user, "password");
+ assertEquals("message incorrect", "Invalid password", violations.iterator()
+ .next()
+ .getMessage());
+ }
+
+ @Test
+ public void givenValidPassword_whenValidatePassword_thenNoConstraintViolation() {
+ User user = new User("ana@yahoo.com", "password#", "Ana", 20);
+
+ Set> violations = validator.validateProperty(user, "password");
+ assertEquals("size is not 0", 0, violations.size());
+ }
+
+ @AfterClass
+ public static void close() {
+ if (validatorFactory != null) {
+ validatorFactory.close();
+ }
+ }
+}
diff --git a/apache-solrj/pom.xml b/apache-solrj/pom.xml
new file mode 100644
index 0000000000..74daeae55c
--- /dev/null
+++ b/apache-solrj/pom.xml
@@ -0,0 +1,50 @@
+
+ 4.0.0
+ com.baeldung
+ apache-solrj
+ 0.0.1-SNAPSHOT
+ jar
+ apache-solrj
+
+
+ 4.12
+ 2.19.1
+
+
+
+
+ org.apache.solr
+ solr-solrj
+ 6.4.0
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+
+
+ maven-compiler-plugin
+ 2.3.2
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+ 1.8
+ 1.8
+
+ **/*IntegrationTest.java
+ **/*LiveTest.java
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apache-solrj/src/main/java/com/baeldung/solrjava/ProductBean.java b/apache-solrj/src/main/java/com/baeldung/solrjava/ProductBean.java
new file mode 100644
index 0000000000..14eea8f2f9
--- /dev/null
+++ b/apache-solrj/src/main/java/com/baeldung/solrjava/ProductBean.java
@@ -0,0 +1,44 @@
+package com.baeldung.solrjava;
+
+import org.apache.solr.client.solrj.beans.Field;
+
+public class ProductBean {
+
+ String id;
+ String name;
+ String price;
+
+ public ProductBean(String id, String name, String price) {
+ super();
+ this.id = id;
+ this.name = name;
+ this.price = price;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ @Field("id")
+ protected void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Field("name")
+ protected void setName(String name) {
+ this.name = name;
+ }
+
+ public String getPrice() {
+ return price;
+ }
+
+ @Field("price")
+ protected void setPrice(String price) {
+ this.price = price;
+ }
+}
diff --git a/apache-solrj/src/main/java/com/baeldung/solrjava/SolrJavaIntegration.java b/apache-solrj/src/main/java/com/baeldung/solrjava/SolrJavaIntegration.java
new file mode 100644
index 0000000000..c55e1c9ada
--- /dev/null
+++ b/apache-solrj/src/main/java/com/baeldung/solrjava/SolrJavaIntegration.java
@@ -0,0 +1,56 @@
+package com.baeldung.solrjava;
+
+import java.io.IOException;
+
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.XMLResponseParser;
+import org.apache.solr.common.SolrInputDocument;
+
+public class SolrJavaIntegration {
+
+ private HttpSolrClient solrClient;
+
+ public SolrJavaIntegration(String clientUrl) {
+
+ solrClient = new HttpSolrClient.Builder(clientUrl).build();
+ solrClient.setParser(new XMLResponseParser());
+ }
+
+ public void addProductBean(ProductBean pBean) throws IOException, SolrServerException {
+
+ solrClient.addBean(pBean);
+ solrClient.commit();
+ }
+
+ public void addSolrDocument(String documentId, String itemName, String itemPrice) throws SolrServerException, IOException {
+
+ SolrInputDocument document = new SolrInputDocument();
+ document.addField("id", documentId);
+ document.addField("name", itemName);
+ document.addField("price", itemPrice);
+ solrClient.add(document);
+ solrClient.commit();
+ }
+
+ public void deleteSolrDocumentById(String documentId) throws SolrServerException, IOException {
+
+ solrClient.deleteById(documentId);
+ solrClient.commit();
+ }
+
+ public void deleteSolrDocumentByQuery(String query) throws SolrServerException, IOException {
+
+ solrClient.deleteByQuery(query);
+ solrClient.commit();
+ }
+
+ protected HttpSolrClient getSolrClient() {
+ return solrClient;
+ }
+
+ protected void setSolrClient(HttpSolrClient solrClient) {
+ this.solrClient = solrClient;
+ }
+
+}
diff --git a/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java b/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java
new file mode 100644
index 0000000000..8b5fe77c6f
--- /dev/null
+++ b/apache-solrj/src/test/java/com/baeldung/solrjava/SolrJavaIntegrationTest.java
@@ -0,0 +1,108 @@
+package com.baeldung.solrjava;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import org.apache.solr.client.solrj.SolrQuery;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrDocumentList;
+import org.junit.Before;
+import org.junit.Test;
+
+public class SolrJavaIntegrationTest {
+
+ private SolrJavaIntegration solrJavaIntegration;
+
+ @Before
+ public void setUp() throws Exception {
+
+ solrJavaIntegration = new SolrJavaIntegration("http://localhost:8983/solr/bigboxstore");
+ solrJavaIntegration.addSolrDocument("123456", "Kenmore Dishwasher", "599.99");
+ }
+
+ @Test
+ public void whenAdd_thenVerifyAddedByQueryOnId() throws SolrServerException, IOException {
+
+ SolrQuery query = new SolrQuery();
+ query.set("q", "id:123456");
+ QueryResponse response = null;
+
+ response = solrJavaIntegration.getSolrClient().query(query);
+
+ SolrDocumentList docList = response.getResults();
+ assertEquals(1, docList.getNumFound());
+
+ for (SolrDocument doc : docList) {
+ assertEquals("Kenmore Dishwasher", (String) doc.getFieldValue("name"));
+ assertEquals((Double) 599.99, (Double) doc.getFieldValue("price"));
+ }
+ }
+
+ @Test
+ public void whenAdd_thenVerifyAddedByQueryOnPrice() throws SolrServerException, IOException {
+
+ SolrQuery query = new SolrQuery();
+ query.set("q", "price:599.99");
+ QueryResponse response = null;
+
+ response = solrJavaIntegration.getSolrClient().query(query);
+
+ SolrDocumentList docList = response.getResults();
+ assertEquals(1, docList.getNumFound());
+
+ for (SolrDocument doc : docList) {
+ assertEquals("123456", (String) doc.getFieldValue("id"));
+ assertEquals((Double) 599.99, (Double) doc.getFieldValue("price"));
+ }
+ }
+
+ @Test
+ public void whenAdd_thenVerifyAddedByQuery() throws SolrServerException, IOException {
+
+ SolrDocument doc = solrJavaIntegration.getSolrClient().getById("123456");
+ assertEquals("Kenmore Dishwasher", (String) doc.getFieldValue("name"));
+ assertEquals((Double) 599.99, (Double) doc.getFieldValue("price"));
+ }
+
+ @Test
+ public void whenAddBean_thenVerifyAddedByQuery() throws SolrServerException, IOException {
+
+ ProductBean pBean = new ProductBean("888", "Apple iPhone 6s", "299.99");
+ solrJavaIntegration.addProductBean(pBean);
+
+ SolrDocument doc = solrJavaIntegration.getSolrClient().getById("888");
+ assertEquals("Apple iPhone 6s", (String) doc.getFieldValue("name"));
+ assertEquals((Double) 299.99, (Double) doc.getFieldValue("price"));
+ }
+
+ @Test
+ public void whenDeleteById_thenVerifyDeleted() throws SolrServerException, IOException {
+
+ solrJavaIntegration.deleteSolrDocumentById("123456");
+
+ SolrQuery query = new SolrQuery();
+ query.set("q", "id:123456");
+ QueryResponse response = solrJavaIntegration.getSolrClient().query(query);
+
+ SolrDocumentList docList = response.getResults();
+ assertEquals(0, docList.getNumFound());
+ }
+
+ @Test
+ public void whenDeleteByQuery_thenVerifyDeleted() throws SolrServerException, IOException {
+
+ solrJavaIntegration.deleteSolrDocumentByQuery("name:Kenmore Dishwasher");
+
+ SolrQuery query = new SolrQuery();
+ query.set("q", "id:123456");
+ QueryResponse response = null;
+
+ response = solrJavaIntegration.getSolrClient().query(query);
+
+ SolrDocumentList docList = response.getResults();
+ assertEquals(0, docList.getNumFound());
+ }
+}
diff --git a/apache-thrift/README.md b/apache-thrift/README.md
new file mode 100644
index 0000000000..d8b9195dcc
--- /dev/null
+++ b/apache-thrift/README.md
@@ -0,0 +1,3 @@
+## Relevant articles:
+
+- [Working with Apache Thrift](http://www.baeldung.com/apache-thrift)
diff --git a/apache-velocity/README.md b/apache-velocity/README.md
new file mode 100644
index 0000000000..53c67f847e
--- /dev/null
+++ b/apache-velocity/README.md
@@ -0,0 +1,3 @@
+## Relevant articles:
+
+- [Introduction to Apache Velocity](http://www.baeldung.com/apache-velocity)
diff --git a/aws/pom.xml b/aws/pom.xml
index f3ae672a2f..681b76cfd4 100644
--- a/aws/pom.xml
+++ b/aws/pom.xml
@@ -7,17 +7,36 @@
jar
aws
+
+ 2.5
+ 1.3.0
+ 1.1.0
+ 2.8.0
+
+
com.amazonaws
aws-lambda-java-core
- 1.1.0
+ ${aws-lambda-java-core.version}
+
+
+
+ com.amazonaws
+ aws-lambda-java-events
+ ${aws-lambda-java-events.version}
commons-io
commons-io
- 2.5
+ ${commons-io.version}
+
+
+
+ com.google.code.gson
+ gson
+ ${gson.version}
@@ -26,7 +45,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 2.3
+ 3.0.0
false
diff --git a/aws/src/main/java/com/baeldung/lambda/dynamodb/SavePersonHandler.java b/aws/src/main/java/com/baeldung/lambda/dynamodb/SavePersonHandler.java
new file mode 100644
index 0000000000..625da62efd
--- /dev/null
+++ b/aws/src/main/java/com/baeldung/lambda/dynamodb/SavePersonHandler.java
@@ -0,0 +1,49 @@
+package com.baeldung.lambda.dynamodb;
+
+import com.amazonaws.regions.Region;
+import com.amazonaws.regions.Regions;
+import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
+import com.amazonaws.services.dynamodbv2.document.DynamoDB;
+import com.amazonaws.services.dynamodbv2.document.Item;
+import com.amazonaws.services.dynamodbv2.document.PutItemOutcome;
+import com.amazonaws.services.dynamodbv2.document.spec.PutItemSpec;
+import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException;
+import com.amazonaws.services.lambda.runtime.Context;
+import com.amazonaws.services.lambda.runtime.RequestHandler;
+import com.baeldung.lambda.dynamodb.bean.PersonRequest;
+import com.baeldung.lambda.dynamodb.bean.PersonResponse;
+
+public class SavePersonHandler implements RequestHandler {
+
+ private DynamoDB dynamoDb;
+
+ private String DYNAMODB_TABLE_NAME = "Person";
+ private Regions REGION = Regions.US_WEST_2;
+
+ public PersonResponse handleRequest(PersonRequest personRequest, Context context) {
+ this.initDynamoDbClient();
+
+ persistData(personRequest);
+
+ PersonResponse personResponse = new PersonResponse();
+ personResponse.setMessage("Saved Successfully!!!");
+ return personResponse;
+ }
+
+ private PutItemOutcome persistData(PersonRequest personRequest) throws ConditionalCheckFailedException {
+ return this.dynamoDb.getTable(DYNAMODB_TABLE_NAME)
+ .putItem(
+ new PutItemSpec().withItem(new Item()
+ .withNumber("id", personRequest.getId())
+ .withString("firstName", personRequest.getFirstName())
+ .withString("lastName", personRequest.getLastName())
+ .withNumber("age", personRequest.getAge())
+ .withString("address", personRequest.getAddress())));
+ }
+
+ private void initDynamoDbClient() {
+ AmazonDynamoDBClient client = new AmazonDynamoDBClient();
+ client.setRegion(Region.getRegion(REGION));
+ this.dynamoDb = new DynamoDB(client);
+ }
+}
diff --git a/aws/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonRequest.java b/aws/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonRequest.java
new file mode 100644
index 0000000000..0c0706e676
--- /dev/null
+++ b/aws/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonRequest.java
@@ -0,0 +1,67 @@
+package com.baeldung.lambda.dynamodb.bean;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+public class PersonRequest {
+ private int id;
+ private String firstName;
+ private String lastName;
+ private int age;
+ private String address;
+
+ public static void main(String[] args) {
+ PersonRequest personRequest = new PersonRequest();
+ personRequest.setId(1);
+ personRequest.setFirstName("John");
+ personRequest.setLastName("Doe");
+ personRequest.setAge(30);
+ personRequest.setAddress("United States");
+ System.out.println(personRequest);
+ }
+
+ public String toString() {
+ final Gson gson = new GsonBuilder().setPrettyPrinting().create();
+ return gson.toJson(this);
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+}
diff --git a/aws/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonResponse.java b/aws/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonResponse.java
new file mode 100644
index 0000000000..a61294ddea
--- /dev/null
+++ b/aws/src/main/java/com/baeldung/lambda/dynamodb/bean/PersonResponse.java
@@ -0,0 +1,20 @@
+package com.baeldung.lambda.dynamodb.bean;
+
+import com.google.gson.Gson;
+
+public class PersonResponse {
+ private String message;
+
+ public String toString() {
+ final Gson gson = new Gson();
+ return gson.toJson(this);
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/core-java-9/README.md b/core-java-9/README.md
index 1b44239e40..53ad79e59c 100644
--- a/core-java-9/README.md
+++ b/core-java-9/README.md
@@ -6,3 +6,5 @@
### Relevant Articles:
- [Java 9 Stream API Improvements](http://www.baeldung.com/java-9-stream-api)
+- [Java 9 Convenience Factory Methods for Collections](http://www.baeldung.com/java-9-collections-factory-methods)
+- [New Stream Collectors in Java 9](http://www.baeldung.com/java9-stream-collectors)
diff --git a/core-java-9/pom.xml b/core-java-9/pom.xml
index 9d1ff29ef7..23473ff161 100644
--- a/core-java-9/pom.xml
+++ b/core-java-9/pom.xml
@@ -21,6 +21,11 @@
slf4j-api
${org.slf4j.version}
+
+ ch.qos.logback
+ logback-classic
+ ${ch.qos.logback.version}
+
org.hamcrest
@@ -76,9 +81,9 @@
1.7.21
-
+ 1.2.1
- 3.6-jigsaw-SNAPSHOT
+ 3.6.0
2.19.1
diff --git a/core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsTest.java b/core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsTest.java
new file mode 100644
index 0000000000..1129a10d17
--- /dev/null
+++ b/core-java-9/src/test/java/com/baeldung/java9/process/ProcessAPIEnhancementsTest.java
@@ -0,0 +1,133 @@
+package com.baeldung.java9.process;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Stream;
+
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Created by sanaulla on 2/23/2017.
+ */
+
+public class ProcessAPIEnhancementsTest {
+
+ Logger log = LoggerFactory.getLogger(ProcessAPIEnhancementsTest.class);
+
+ @Test
+ public void givenCurrentProcess_whenInvokeGetInfo_thenSuccess() throws IOException {
+ ProcessHandle processHandle = ProcessHandle.current();
+ ProcessHandle.Info processInfo = processHandle.info();
+ assertNotNull(processHandle.getPid());
+ assertEquals(false, processInfo.arguments()
+ .isPresent());
+ assertEquals(true, processInfo.command()
+ .isPresent());
+ assertTrue(processInfo.command()
+ .get()
+ .contains("java"));
+
+ assertEquals(true, processInfo.startInstant()
+ .isPresent());
+ assertEquals(true, processInfo.totalCpuDuration()
+ .isPresent());
+ assertEquals(true, processInfo.user()
+ .isPresent());
+ }
+
+ @Test
+ public void givenSpawnProcess_whenInvokeGetInfo_thenSuccess() throws IOException {
+
+ String javaCmd = ProcessUtils.getJavaCmd()
+ .getAbsolutePath();
+ ProcessBuilder processBuilder = new ProcessBuilder(javaCmd, "-version");
+ Process process = processBuilder.inheritIO()
+ .start();
+ ProcessHandle processHandle = process.toHandle();
+ ProcessHandle.Info processInfo = processHandle.info();
+ assertNotNull(processHandle.getPid());
+ assertEquals(false, processInfo.arguments()
+ .isPresent());
+ assertEquals(true, processInfo.command()
+ .isPresent());
+ assertTrue(processInfo.command()
+ .get()
+ .contains("java"));
+ assertEquals(true, processInfo.startInstant()
+ .isPresent());
+ assertEquals(true, processInfo.totalCpuDuration()
+ .isPresent());
+ assertEquals(true, processInfo.user()
+ .isPresent());
+ }
+
+ @Test
+ public void givenLiveProcesses_whenInvokeGetInfo_thenSuccess() {
+ Stream liveProcesses = ProcessHandle.allProcesses();
+ liveProcesses.filter(ProcessHandle::isAlive)
+ .forEach(ph -> {
+ assertNotNull(ph.getPid());
+ assertEquals(true, ph.info()
+ .command()
+ .isPresent());
+ assertEquals(true, ph.info()
+ .startInstant()
+ .isPresent());
+ assertEquals(true, ph.info()
+ .totalCpuDuration()
+ .isPresent());
+ assertEquals(true, ph.info()
+ .user()
+ .isPresent());
+ });
+ }
+
+ @Test
+ public void givenProcess_whenGetChildProcess_thenSuccess() throws IOException {
+ int childProcessCount = 5;
+ for (int i = 0; i < childProcessCount; i++) {
+ String javaCmd = ProcessUtils.getJavaCmd()
+ .getAbsolutePath();
+ ProcessBuilder processBuilder
+ = new ProcessBuilder(javaCmd, "-version");
+ processBuilder.inheritIO().start();
+ }
+
+ Stream children = ProcessHandle.current()
+ .children();
+ children.filter(ProcessHandle::isAlive)
+ .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.getPid(), ph.info()
+ .command()));
+ Stream descendants = ProcessHandle.current()
+ .descendants();
+ descendants.filter(ProcessHandle::isAlive)
+ .forEach(ph -> log.info("PID: {}, Cmd: {}", ph.getPid(), ph.info()
+ .command()));
+ }
+
+ @Test
+ public void givenProcess_whenAddExitCallback_thenSuccess() throws Exception {
+ String javaCmd = ProcessUtils.getJavaCmd()
+ .getAbsolutePath();
+ ProcessBuilder processBuilder
+ = new ProcessBuilder(javaCmd, "-version");
+ Process process = processBuilder.inheritIO()
+ .start();
+ ProcessHandle processHandle = process.toHandle();
+
+ log.info("PID: {} has started", processHandle.getPid());
+ CompletableFuture onProcessExit = processHandle.onExit();
+ onProcessExit.get();
+ assertEquals(false, processHandle.isAlive());
+ onProcessExit.thenAccept(ph -> {
+ log.info("PID: {} has stopped", ph.getPid());
+ });
+ }
+
+}
diff --git a/core-java/0.004102810554955205 b/core-java/0.004102810554955205
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/core-java/0.04832801936270381 b/core-java/0.04832801936270381
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/core-java/0.5633433244738808 b/core-java/0.5633433244738808
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/core-java/0.6256429734439612 b/core-java/0.6256429734439612
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/core-java/0.9799201796740292 b/core-java/0.9799201796740292
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/core-java/README.md b/core-java/README.md
index 341dbdf910..a34908d8ae 100644
--- a/core-java/README.md
+++ b/core-java/README.md
@@ -58,3 +58,24 @@
- [Guide to java.util.concurrent.BlockingQueue](http://www.baeldung.com/java-blocking-queue)
- [Guide to CountDownLatch in Java](http://www.baeldung.com/java-countdown-latch)
- [How to Design a Genetic Algorithm in Java](http://www.baeldung.com/java-genetic-algorithm)
+- [A Guide to ConcurrentMap](http://www.baeldung.com/java-concurrent-map)
+- [Guide to PriorityBlockingQueue in Java](http://www.baeldung.com/java-priority-blocking-queue)
+- [Guide to Java 8 groupingBy Collector](http://www.baeldung.com/java-groupingby-collector)
+- [Avoiding the ConcurrentModificationException in Java](http://www.baeldung.com/java-concurrentmodificationexception)
+- [Guide to WeakHashMap in Java](http://www.baeldung.com/java-weakhashmap)
+- [Strategy Design Pattern in Java 8](http://www.baeldung.com/java-strategy-pattern)
+- [Java 8 and Infinite Streams](http://www.baeldung.com/java-inifinite-streams)
+- [Custom Thread Pools In Java 8 Parallel Streams](http://www.baeldung.com/java-8-parallel-streams-custom-threadpool)
+- [String Operations with Java Streams](http://www.baeldung.com/java-stream-operations-on-strings)
+- [Spring Security – Cache Control Headers](http://www.baeldung.com/spring-security-cache-control-headers)
+- [Basic Introduction to JMX](http://www.baeldung.com/java-management-extensions)
+- [AWS Lambda With Java](http://www.baeldung.com/java-aws-lambda)
+- [Introduction to Nashorn](http://www.baeldung.com/java-nashorn)
+- [Exceptions in Java 8 Lambda Expressions](http://www.baeldung.com/java-lambda-exceptions)
+- [Guide to the Guava BiMap](http://www.baeldung.com/guava-bimap)
+- [Iterable to Stream in Java](http://www.baeldung.com/java-iterable-to-stream)
+- [Java 8 Stream findFirst() vs. findAny()](http://www.baeldung.com/java-stream-findfirst-vs-findany)
+- [Chained Exceptions in Java](http://www.baeldung.com/java-chained-exceptions)
+- [The Java HashMap Under the Hood](http://www.baeldung.com/java-hashmap)
+- [A Guide to LinkedHashMap in Java](http://www.baeldung.com/java-linked-hashmap)
+- [A Guide to TreeMap in Java](http://www.baeldung.com/java-treemap)
diff --git a/core-java/src/main/java/com/baeldung/algorithms/RunAlgorithm.java b/core-java/src/main/java/com/baeldung/algorithms/RunAlgorithm.java
index 3f7c8bf4b3..22c5776293 100644
--- a/core-java/src/main/java/com/baeldung/algorithms/RunAlgorithm.java
+++ b/core-java/src/main/java/com/baeldung/algorithms/RunAlgorithm.java
@@ -2,7 +2,8 @@ package com.baeldung.algorithms;
import java.util.Scanner;
-import com.baeldung.algorithms.annealing.SimulatedAnnealing;
+import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
+import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
import com.baeldung.algorithms.ga.binary.SimpleGeneticAlgorithm;
import com.baeldung.algorithms.slope_one.SlopeOne;
@@ -14,6 +15,7 @@ public class RunAlgorithm {
System.out.println("1 - Simulated Annealing");
System.out.println("2 - Slope One");
System.out.println("3 - Simple Genetic Algorithm");
+ System.out.println("4 - Ant Colony");
int decision = in.nextInt();
switch (decision) {
case 1:
@@ -27,6 +29,10 @@ public class RunAlgorithm {
SimpleGeneticAlgorithm ga = new SimpleGeneticAlgorithm();
ga.runAlgorithm(50, "1011000100000100010000100000100111001000000100000100000000001111");
break;
+ case 4:
+ AntColonyOptimization antColony = new AntColonyOptimization(21);
+ antColony.startAntOptimization();
+ break;
default:
System.out.println("Unknown option");
break;
diff --git a/core-java/src/main/java/com/baeldung/algorithms/annealing/City.java b/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/City.java
similarity index 90%
rename from core-java/src/main/java/com/baeldung/algorithms/annealing/City.java
rename to core-java/src/main/java/com/baeldung/algorithms/ga/annealing/City.java
index 77e8652df0..cb5647f4d2 100644
--- a/core-java/src/main/java/com/baeldung/algorithms/annealing/City.java
+++ b/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/City.java
@@ -1,4 +1,4 @@
-package com.baeldung.algorithms.annealing;
+package com.baeldung.algorithms.ga.annealing;
import lombok.Data;
diff --git a/core-java/src/main/java/com/baeldung/algorithms/annealing/SimulatedAnnealing.java b/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java
similarity index 96%
rename from core-java/src/main/java/com/baeldung/algorithms/annealing/SimulatedAnnealing.java
rename to core-java/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java
index a7dc974e97..bff64fc239 100644
--- a/core-java/src/main/java/com/baeldung/algorithms/annealing/SimulatedAnnealing.java
+++ b/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/SimulatedAnnealing.java
@@ -1,4 +1,4 @@
-package com.baeldung.algorithms.annealing;
+package com.baeldung.algorithms.ga.annealing;
public class SimulatedAnnealing {
diff --git a/core-java/src/main/java/com/baeldung/algorithms/annealing/Travel.java b/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java
similarity index 97%
rename from core-java/src/main/java/com/baeldung/algorithms/annealing/Travel.java
rename to core-java/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java
index 9bf341fbbe..3139b49586 100644
--- a/core-java/src/main/java/com/baeldung/algorithms/annealing/Travel.java
+++ b/core-java/src/main/java/com/baeldung/algorithms/ga/annealing/Travel.java
@@ -1,4 +1,4 @@
-package com.baeldung.algorithms.annealing;
+package com.baeldung.algorithms.ga.annealing;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java
new file mode 100644
index 0000000000..4ea23b799f
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/Ant.java
@@ -0,0 +1,37 @@
+package com.baeldung.algorithms.ga.ant_colony;
+
+public class Ant {
+
+ protected int trailSize;
+ protected int trail[];
+ protected boolean visited[];
+
+ public Ant(int tourSize) {
+ this.trailSize = tourSize;
+ this.trail = new int[tourSize];
+ this.visited = new boolean[tourSize];
+ }
+
+ protected void visitCity(int currentIndex, int city) {
+ trail[currentIndex + 1] = city;
+ visited[city] = true;
+ }
+
+ protected boolean visited(int i) {
+ return visited[i];
+ }
+
+ protected double trailLength(double graph[][]) {
+ double length = graph[trail[trailSize - 1]][trail[0]];
+ for (int i = 0; i < trailSize - 1; i++) {
+ length += graph[trail[i]][trail[i + 1]];
+ }
+ return length;
+ }
+
+ protected void clear() {
+ for (int i = 0; i < trailSize; i++)
+ visited[i] = false;
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java
new file mode 100644
index 0000000000..e46ac77e84
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/algorithms/ga/ant_colony/AntColonyOptimization.java
@@ -0,0 +1,212 @@
+package com.baeldung.algorithms.ga.ant_colony;
+
+import java.util.Arrays;
+import java.util.Random;
+
+public class AntColonyOptimization {
+
+ private double c = 1.0;
+ private double alpha = 1;
+ private double beta = 5;
+ private double evaporation = 0.5;
+ private double Q = 500;
+ private double antFactor = 0.8;
+ private double randomFactor = 0.01;
+
+ private int maxIterations = 1000;
+
+ public int numberOfCities;
+ public int numberOfAnts;
+ private double graph[][];
+ private double trails[][];
+ private Ant ants[];
+ private Random random = new Random();
+ private double probabilities[];
+
+ private int currentIndex;
+
+ public int[] bestTourOrder;
+ public double bestTourLength;
+
+ public AntColonyOptimization(int noOfCities) {
+ graph = generateRandomMatrix(noOfCities);
+ numberOfCities = graph.length;
+ numberOfAnts = (int) (numberOfCities * antFactor);
+
+ trails = new double[numberOfCities][numberOfCities];
+ probabilities = new double[numberOfCities];
+ ants = new Ant[numberOfAnts];
+ for (int j = 0; j < numberOfAnts; j++) {
+ ants[j] = new Ant(numberOfCities);
+ }
+ }
+
+ /**
+ * Generate initial solution
+ * @param n
+ * @return
+ */
+ public double[][] generateRandomMatrix(int n) {
+ double[][] randomMatrix = new double[n][n];
+ random.setSeed(System.currentTimeMillis());
+ for (int i = 0; i < n; i++) {
+ for (int j = 0; j < n; j++) {
+ Integer r = random.nextInt(100) + 1;
+ randomMatrix[i][j] = Math.abs(r);
+ }
+ }
+ return randomMatrix;
+ }
+
+ /**
+ * Perform ant optimization
+ * @return
+ */
+ public int[] startAntOptimization() {
+ int[] finalResult = null;
+ for (int i = 1; i <= 3; i++) {
+ System.out.println("Attempt #" + i);
+ finalResult = solve();
+ }
+ return finalResult;
+ }
+
+ /**
+ * Use this method to run the main logic
+ * @return
+ */
+ private int[] solve() {
+ setupAnts();
+ clearTrails();
+ int iteration = 0;
+ while (iteration < maxIterations) {
+ moveAnts();
+ updateTrails();
+ updateBest();
+ iteration++;
+ }
+ System.out.println("Best tour length: " + (bestTourLength - numberOfCities));
+ System.out.println("Best tour order: " + Arrays.toString(bestTourOrder));
+ return bestTourOrder.clone();
+ }
+
+ /**
+ * Prepare ants for the simulation
+ */
+ private void setupAnts() {
+ currentIndex = -1;
+ for (int i = 0; i < numberOfAnts; i++) {
+ ants[i].clear();
+ ants[i].visitCity(currentIndex, random.nextInt(numberOfCities));
+ }
+ currentIndex++;
+ }
+
+ /**
+ * At each iteration, move ants
+ */
+ private void moveAnts() {
+ while (currentIndex < numberOfCities - 1) {
+ for (Ant a : ants)
+ a.visitCity(currentIndex, selectNextCity(a));
+ currentIndex++;
+ }
+ }
+
+ /**
+ * Select next city for each ant
+ * @param ant
+ * @return
+ */
+ private int selectNextCity(Ant ant) {
+ if (random.nextDouble() < randomFactor) {
+ int t = random.nextInt(numberOfCities - currentIndex);
+ int j = -1;
+ for (int i = 0; i < numberOfCities; i++) {
+ if (!ant.visited(i)) {
+ j++;
+ }
+ if (j == t) {
+ return i;
+ }
+ }
+ }
+ calculateProbabilities(ant);
+ double r = random.nextDouble();
+ double total = 0;
+ for (int i = 0; i < numberOfCities; i++) {
+ total += probabilities[i];
+ if (total >= r) {
+ return i;
+ }
+ }
+
+ throw new RuntimeException("There are no other cities");
+ }
+
+ /**
+ * Calculate the next city picks probabilites
+ * @param ant
+ */
+ private void calculateProbabilities(Ant ant) {
+ int i = ant.trail[currentIndex];
+ double pheromone = 0.0;
+ for (int l = 0; l < numberOfCities; l++) {
+ if (!ant.visited(l)) {
+ pheromone += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta);
+ }
+ }
+ for (int j = 0; j < numberOfCities; j++) {
+ if (ant.visited(j)) {
+ probabilities[j] = 0.0;
+ } else {
+ double numerator = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta);
+ probabilities[j] = numerator / pheromone;
+ }
+ }
+ }
+
+ /**
+ * Update trails that ants used
+ */
+ private void updateTrails() {
+ for (int i = 0; i < numberOfCities; i++) {
+ for (int j = 0; j < numberOfCities; j++) {
+ trails[i][j] *= evaporation;
+ }
+ }
+ for (Ant a : ants) {
+ double contribution = Q / a.trailLength(graph);
+ for (int i = 0; i < numberOfCities - 1; i++) {
+ trails[a.trail[i]][a.trail[i + 1]] += contribution;
+ }
+ trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution;
+ }
+ }
+
+ /**
+ * Update the best solution
+ */
+ private void updateBest() {
+ if (bestTourOrder == null) {
+ bestTourOrder = ants[0].trail;
+ bestTourLength = ants[0].trailLength(graph);
+ }
+ for (Ant a : ants) {
+ if (a.trailLength(graph) < bestTourLength) {
+ bestTourLength = a.trailLength(graph);
+ bestTourOrder = a.trail.clone();
+ }
+ }
+ }
+
+ /**
+ * Clear trails after simulation
+ */
+ private void clearTrails() {
+ for (int i = 0; i < numberOfCities; i++)
+ for (int j = 0; j < numberOfCities; j++)
+ trails[i][j] = c;
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/concurrent/locks/ReentrantLockWithCondition.java b/core-java/src/main/java/com/baeldung/concurrent/locks/ReentrantLockWithCondition.java
new file mode 100644
index 0000000000..4f061d2efd
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/concurrent/locks/ReentrantLockWithCondition.java
@@ -0,0 +1,83 @@
+package com.baeldung.concurrent.locks;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Stack;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static java.lang.Thread.sleep;
+
+public class ReentrantLockWithCondition {
+
+ static Logger logger = LoggerFactory.getLogger(ReentrantLockWithCondition.class);
+
+ Stack stack = new Stack<>();
+ int CAPACITY = 5;
+
+ ReentrantLock lock = new ReentrantLock();
+ Condition stackEmptyCondition = lock.newCondition();
+ Condition stackFullCondition = lock.newCondition();
+
+ public void pushToStack(String item) throws InterruptedException {
+ try {
+ lock.lock();
+ if (stack.size() == CAPACITY) {
+ logger.info(Thread.currentThread().getName() + " wait on stack full");
+ stackFullCondition.await();
+ }
+ logger.info("Pushing the item " + item);
+ stack.push(item);
+ stackEmptyCondition.signalAll();
+ } finally {
+ lock.unlock();
+ }
+
+ }
+
+ public String popFromStack() throws InterruptedException {
+ try {
+ lock.lock();
+ if (stack.size() == 0) {
+ logger.info(Thread.currentThread().getName() + " wait on stack empty");
+ stackEmptyCondition.await();
+ }
+ return stack.pop();
+ } finally {
+ stackFullCondition.signalAll();
+ lock.unlock();
+ }
+ }
+
+ public static void main(String[] args) {
+ final int threadCount = 2;
+ ReentrantLockWithCondition object = new ReentrantLockWithCondition();
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+ service.execute(() -> {
+ for (int i = 0; i < 10; i++) {
+ try {
+ object.pushToStack("Item " + i);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ });
+
+ service.execute(() -> {
+ for (int i = 0; i < 10; i++) {
+ try {
+ logger.info("Item popped " + object.popFromStack());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ });
+
+ service.shutdown();
+ }
+}
diff --git a/core-java/src/main/java/com/baeldung/concurrent/locks/SharedObjectWithLock.java b/core-java/src/main/java/com/baeldung/concurrent/locks/SharedObjectWithLock.java
new file mode 100644
index 0000000000..b6a4615638
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/concurrent/locks/SharedObjectWithLock.java
@@ -0,0 +1,92 @@
+package com.baeldung.concurrent.locks;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+import static java.lang.Thread.sleep;
+
+public class SharedObjectWithLock {
+
+ Logger logger = LoggerFactory.getLogger(SharedObjectWithLock.class);
+
+ ReentrantLock lock = new ReentrantLock(true);
+
+ int counter = 0;
+
+ public void perform() {
+
+ lock.lock();
+ logger.info("Thread - " + Thread.currentThread().getName() + " acquired the lock");
+ try {
+ logger.info("Thread - " + Thread.currentThread().getName() + " processing");
+ counter++;
+ } catch (Exception exception) {
+ logger.error(" Interrupted Exception ", exception);
+ } finally {
+ lock.unlock();
+ logger.info("Thread - " + Thread.currentThread().getName() + " released the lock");
+ }
+ }
+
+ public void performTryLock() {
+
+ logger.info("Thread - " + Thread.currentThread().getName() + " attempting to acquire the lock");
+ try {
+ boolean isLockAcquired = lock.tryLock(2, TimeUnit.SECONDS);
+ if (isLockAcquired) {
+ try {
+ logger.info("Thread - " + Thread.currentThread().getName() + " acquired the lock");
+
+ logger.info("Thread - " + Thread.currentThread().getName() + " processing");
+ sleep(1000);
+ } finally {
+ lock.unlock();
+ logger.info("Thread - " + Thread.currentThread().getName() + " released the lock");
+
+ }
+ }
+ } catch (InterruptedException exception) {
+ logger.error(" Interrupted Exception ", exception);
+ }
+ logger.info("Thread - " + Thread.currentThread().getName() + " could not acquire the lock");
+ }
+
+ public ReentrantLock getLock() {
+ return lock;
+ }
+
+ boolean isLocked() {
+ return lock.isLocked();
+ }
+
+ boolean hasQueuedThreads() {
+ return lock.hasQueuedThreads();
+ }
+
+ int getCounter() {
+ return counter;
+ }
+
+ public static void main(String[] args) {
+
+ final int threadCount = 2;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+ final SharedObjectWithLock object = new SharedObjectWithLock();
+
+ service.execute(() -> {
+ object.perform();
+ });
+ service.execute(() -> {
+ object.performTryLock();
+ });
+
+ service.shutdown();
+
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/concurrent/locks/StampedLockDemo.java b/core-java/src/main/java/com/baeldung/concurrent/locks/StampedLockDemo.java
new file mode 100644
index 0000000000..0b0dbc72cb
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/concurrent/locks/StampedLockDemo.java
@@ -0,0 +1,104 @@
+package com.baeldung.concurrent.locks;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.locks.StampedLock;
+
+import static java.lang.Thread.sleep;
+
+public class StampedLockDemo {
+ Map map = new HashMap<>();
+ Logger logger = LoggerFactory.getLogger(StampedLockDemo.class);
+
+ private final StampedLock lock = new StampedLock();
+
+ public void put(String key, String value) throws InterruptedException {
+ long stamp = lock.writeLock();
+
+ try {
+ logger.info(Thread.currentThread().getName() + " acquired the write lock with stamp " + stamp);
+ map.put(key, value);
+ } finally {
+ lock.unlockWrite(stamp);
+ logger.info(Thread.currentThread().getName() + " unlocked the write lock with stamp " + stamp);
+ }
+ }
+
+ public String get(String key) throws InterruptedException {
+ long stamp = lock.readLock();
+ logger.info(Thread.currentThread().getName() + " acquired the read lock with stamp " + stamp);
+ try {
+ sleep(5000);
+ return map.get(key);
+
+ } finally {
+ lock.unlockRead(stamp);
+ logger.info(Thread.currentThread().getName() + " unlocked the read lock with stamp " + stamp);
+
+ }
+
+ }
+
+ public String readWithOptimisticLock(String key) throws InterruptedException {
+ long stamp = lock.tryOptimisticRead();
+ String value = map.get(key);
+
+ if (!lock.validate(stamp)) {
+ stamp = lock.readLock();
+ try {
+ sleep(5000);
+ return map.get(key);
+
+ } finally {
+ lock.unlock(stamp);
+ logger.info(Thread.currentThread().getName() + " unlocked the read lock with stamp " + stamp);
+
+ }
+ }
+ return value;
+ }
+
+ public static void main(String[] args) {
+ final int threadCount = 4;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+ StampedLockDemo object = new StampedLockDemo();
+
+ Runnable writeTask = () -> {
+
+ try {
+ object.put("key1", "value1");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ };
+ Runnable readTask = () -> {
+
+ try {
+ object.get("key1");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ };
+ Runnable readOptimisticTask = () -> {
+
+ try {
+ object.readWithOptimisticLock("key1");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ };
+ service.submit(writeTask);
+ service.submit(writeTask);
+ service.submit(readTask);
+ service.submit(readOptimisticTask);
+
+ service.shutdown();
+
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/concurrent/locks/SynchronizedHashMapWithRWLock.java b/core-java/src/main/java/com/baeldung/concurrent/locks/SynchronizedHashMapWithRWLock.java
new file mode 100644
index 0000000000..83b8b34fe9
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/concurrent/locks/SynchronizedHashMapWithRWLock.java
@@ -0,0 +1,120 @@
+package com.baeldung.concurrent.locks;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import static java.lang.Thread.sleep;
+
+public class SynchronizedHashMapWithRWLock {
+
+ static Map syncHashMap = new HashMap<>();
+ Logger logger = LoggerFactory.getLogger(SynchronizedHashMapWithRWLock.class);
+
+ private final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Lock readLock = lock.readLock();
+ private final Lock writeLock = lock.writeLock();
+
+ public void put(String key, String value) throws InterruptedException {
+
+ try {
+ writeLock.lock();
+ logger.info(Thread.currentThread().getName() + " writing");
+ syncHashMap.put(key, value);
+ sleep(1000);
+ } finally {
+ writeLock.unlock();
+ }
+
+ }
+
+ public String get(String key) {
+ try {
+ readLock.lock();
+ logger.info(Thread.currentThread().getName() + " reading");
+ return syncHashMap.get(key);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ public String remove(String key) {
+ try {
+ writeLock.lock();
+ return syncHashMap.remove(key);
+ } finally {
+ writeLock.unlock();
+ }
+ }
+
+ public boolean containsKey(String key) {
+ try {
+ readLock.lock();
+ return syncHashMap.containsKey(key);
+ } finally {
+ readLock.unlock();
+ }
+ }
+
+ boolean isReadLockAvailable() {
+ return readLock.tryLock();
+ }
+
+ public static void main(String[] args) throws InterruptedException {
+
+ final int threadCount = 3;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+ SynchronizedHashMapWithRWLock object = new SynchronizedHashMapWithRWLock();
+
+ service.execute(new Thread(new Writer(object), "Writer"));
+ service.execute(new Thread(new Reader(object), "Reader1"));
+ service.execute(new Thread(new Reader(object), "Reader2"));
+
+ service.shutdown();
+ }
+
+ private static class Reader implements Runnable {
+
+ SynchronizedHashMapWithRWLock object;
+
+ public Reader(SynchronizedHashMapWithRWLock object) {
+ this.object = object;
+ }
+
+ @Override
+ public void run() {
+ for (int i = 0; i < 10; i++) {
+ object.get("key" + i);
+ }
+ }
+ }
+
+ private static class Writer implements Runnable {
+
+ SynchronizedHashMapWithRWLock object;
+
+ public Writer(SynchronizedHashMapWithRWLock object) {
+ this.object = object;
+ }
+
+ @Override
+ public void run() {
+ for (int i = 0; i < 10; i++) {
+ try {
+ object.put("key" + i, "value" + i);
+ sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+}
diff --git a/core-java/src/main/java/com/baeldung/list/listoflist/Pen.java b/core-java/src/main/java/com/baeldung/list/listoflist/Pen.java
new file mode 100644
index 0000000000..efbd88d0b1
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/list/listoflist/Pen.java
@@ -0,0 +1,18 @@
+package com.baeldung.list.listoflist;
+
+public class Pen implements Stationery {
+
+ public String name;
+
+ public Pen(String name) {
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
\ No newline at end of file
diff --git a/core-java/src/main/java/com/baeldung/list/listoflist/Pencil.java b/core-java/src/main/java/com/baeldung/list/listoflist/Pencil.java
new file mode 100644
index 0000000000..7dfa119703
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/list/listoflist/Pencil.java
@@ -0,0 +1,18 @@
+package com.baeldung.list.listoflist;
+
+public class Pencil implements Stationery{
+
+ public String name;
+
+ public Pencil(String name) {
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
\ No newline at end of file
diff --git a/core-java/src/main/java/com/baeldung/list/listoflist/Rubber.java b/core-java/src/main/java/com/baeldung/list/listoflist/Rubber.java
new file mode 100644
index 0000000000..7511139e14
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/list/listoflist/Rubber.java
@@ -0,0 +1,18 @@
+package com.baeldung.list.listoflist;
+
+public class Rubber implements Stationery {
+
+ public String name;
+
+ public Rubber(String name) {
+ this.name = name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+}
\ No newline at end of file
diff --git a/core-java/src/main/java/com/baeldung/list/listoflist/Stationery.java b/core-java/src/main/java/com/baeldung/list/listoflist/Stationery.java
new file mode 100644
index 0000000000..d914397cb8
--- /dev/null
+++ b/core-java/src/main/java/com/baeldung/list/listoflist/Stationery.java
@@ -0,0 +1,5 @@
+package com.baeldung.list.listoflist;
+
+public interface Stationery {
+
+}
diff --git a/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java b/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java
new file mode 100644
index 0000000000..cd8efaa106
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/algorithms/AntColonyOptimizationTest.java
@@ -0,0 +1,22 @@
+package com.baeldung.algorithms;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.baeldung.algorithms.ga.ant_colony.AntColonyOptimization;
+
+public class AntColonyOptimizationTest {
+
+ @Test
+ public void testGenerateRandomMatrix() {
+ AntColonyOptimization antTSP = new AntColonyOptimization(5);
+ Assert.assertNotNull(antTSP.generateRandomMatrix(5));
+ }
+
+ @Test
+ public void testStartAntOptimization() {
+ AntColonyOptimization antTSP = new AntColonyOptimization(5);
+ Assert.assertNotNull(antTSP.startAntOptimization());
+ }
+
+}
diff --git a/core-java/src/test/java/com/baeldung/algorithms/SimulatedAnnealingTest.java b/core-java/src/test/java/com/baeldung/algorithms/SimulatedAnnealingTest.java
index 2fc7ea9b92..6822bae990 100644
--- a/core-java/src/test/java/com/baeldung/algorithms/SimulatedAnnealingTest.java
+++ b/core-java/src/test/java/com/baeldung/algorithms/SimulatedAnnealingTest.java
@@ -3,7 +3,7 @@ package com.baeldung.algorithms;
import org.junit.Assert;
import org.junit.Test;
-import com.baeldung.algorithms.annealing.SimulatedAnnealing;
+import com.baeldung.algorithms.ga.annealing.SimulatedAnnealing;
public class SimulatedAnnealingTest {
diff --git a/core-java/src/test/java/com/baeldung/concurrent/locks/SharedObjectWithLockManualTest.java b/core-java/src/test/java/com/baeldung/concurrent/locks/SharedObjectWithLockManualTest.java
new file mode 100644
index 0000000000..9b82ced642
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/concurrent/locks/SharedObjectWithLockManualTest.java
@@ -0,0 +1,75 @@
+package com.baeldung.concurrent.locks;
+
+import org.junit.Test;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class SharedObjectWithLockManualTest {
+
+ @Test
+ public void whenLockAcquired_ThenLockedIsTrue() {
+ final SharedObjectWithLock object = new SharedObjectWithLock();
+
+ final int threadCount = 2;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+
+ executeThreads(object, threadCount, service);
+
+ assertEquals(true, object.isLocked());
+
+ service.shutdown();
+ }
+
+ @Test
+ public void whenLocked_ThenQueuedThread() {
+ final int threadCount = 4;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+ final SharedObjectWithLock object = new SharedObjectWithLock();
+
+ executeThreads(object, threadCount, service);
+
+ assertEquals(object.hasQueuedThreads(), true);
+
+ service.shutdown();
+
+ }
+
+ public void whenTryLock_ThenQueuedThread() {
+ final SharedObjectWithLock object = new SharedObjectWithLock();
+
+ final int threadCount = 2;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+
+ executeThreads(object, threadCount, service);
+
+ assertEquals(true, object.isLocked());
+
+ service.shutdown();
+ }
+
+ @Test
+ public void whenGetCount_ThenCorrectCount() throws InterruptedException {
+ final int threadCount = 4;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+ final SharedObjectWithLock object = new SharedObjectWithLock();
+
+ executeThreads(object, threadCount, service);
+ Thread.sleep(1000);
+ assertEquals(object.getCounter(), 4);
+
+ service.shutdown();
+
+ }
+
+ private void executeThreads(SharedObjectWithLock object, int threadCount, ExecutorService service) {
+ for (int i = 0; i < threadCount; i++) {
+ service.execute(() -> {
+ object.perform();
+ });
+ }
+ }
+
+}
diff --git a/core-java/src/test/java/com/baeldung/concurrent/locks/SynchronizedHashMapWithRWLockManualTest.java b/core-java/src/test/java/com/baeldung/concurrent/locks/SynchronizedHashMapWithRWLockManualTest.java
new file mode 100644
index 0000000000..fd6cf08442
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/concurrent/locks/SynchronizedHashMapWithRWLockManualTest.java
@@ -0,0 +1,58 @@
+package com.baeldung.concurrent.locks;
+
+import jdk.nashorn.internal.ir.annotations.Ignore;
+import org.junit.Test;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static junit.framework.TestCase.assertEquals;
+
+public class SynchronizedHashMapWithRWLockManualTest {
+
+ @Test
+ public void whenWriting_ThenNoReading() {
+ SynchronizedHashMapWithRWLock object = new SynchronizedHashMapWithRWLock();
+ final int threadCount = 3;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+
+ executeWriterThreads(object, threadCount, service);
+
+ assertEquals(object.isReadLockAvailable(), false);
+
+ service.shutdown();
+ }
+
+ @Test
+ public void whenReading_ThenMultipleReadingAllowed() {
+ SynchronizedHashMapWithRWLock object = new SynchronizedHashMapWithRWLock();
+ final int threadCount = 5;
+ final ExecutorService service = Executors.newFixedThreadPool(threadCount);
+
+ executeReaderThreads(object, threadCount, service);
+
+ assertEquals(object.isReadLockAvailable(), true);
+
+ service.shutdown();
+ }
+
+ private void executeWriterThreads(SynchronizedHashMapWithRWLock object, int threadCount, ExecutorService service) {
+ for (int i = 0; i < threadCount; i++) {
+ service.execute(() -> {
+ try {
+ object.put("key" + threadCount, "value" + threadCount);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+ }
+
+ private void executeReaderThreads(SynchronizedHashMapWithRWLock object, int threadCount, ExecutorService service) {
+ for (int i = 0; i < threadCount; i++)
+ service.execute(() -> {
+ object.get("key" + threadCount);
+ });
+ }
+
+}
diff --git a/core-java/src/test/java/com/baeldung/java/map/README.md b/core-java/src/test/java/com/baeldung/java/map/README.md
deleted file mode 100644
index 0bba153763..0000000000
--- a/core-java/src/test/java/com/baeldung/java/map/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-### Relevant Articles:
-- [The Java HashMap Under the Hood](http://www.baeldung.com/java-hashmap)
diff --git a/core-java/src/test/java/com/baeldung/test/comparison/DivisibilityTest.java b/core-java/src/test/java/com/baeldung/junit4vstestng/DivisibilityTest.java
similarity index 74%
rename from core-java/src/test/java/com/baeldung/test/comparison/DivisibilityTest.java
rename to core-java/src/test/java/com/baeldung/junit4vstestng/DivisibilityTest.java
index 9ae13f5934..dec7dbe6aa 100644
--- a/core-java/src/test/java/com/baeldung/test/comparison/DivisibilityTest.java
+++ b/core-java/src/test/java/com/baeldung/junit4vstestng/DivisibilityTest.java
@@ -1,4 +1,4 @@
-package com.baeldung.test.comparison;
+package com.baeldung.junit4vstestng;
import static org.junit.Assert.assertEquals;
@@ -15,7 +15,7 @@ public class DivisibilityTest {
}
@Test
- public void givenNumber_whenDivisiblebyTwo_thenCorrect() {
+ public void givenNumber_whenDivisibleByTwo_thenCorrect() {
assertEquals(number % 2, 0);
}
}
diff --git a/core-java/src/test/java/com/baeldung/junit4vstestng/ParametrizedTests.java b/core-java/src/test/java/com/baeldung/junit4vstestng/ParametrizedTests.java
new file mode 100644
index 0000000000..e9a9c6a07a
--- /dev/null
+++ b/core-java/src/test/java/com/baeldung/junit4vstestng/ParametrizedTests.java
@@ -0,0 +1,34 @@
+package com.baeldung.junit4vstestng;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(value = Parameterized.class)
+public class ParametrizedTests {
+
+ private int value;
+ private boolean isEven;
+
+ public ParametrizedTests(int value, boolean isEven) {
+ this.value = value;
+ this.isEven = isEven;
+ }
+
+ @Parameters
+ public static Collection