improving aws lb

Project: http://git-wip-us.apache.org/repos/asf/stratos/repo
Commit: http://git-wip-us.apache.org/repos/asf/stratos/commit/d68a6d50
Tree: http://git-wip-us.apache.org/repos/asf/stratos/tree/d68a6d50
Diff: http://git-wip-us.apache.org/repos/asf/stratos/diff/d68a6d50

Branch: refs/heads/stratos-4.1.x
Commit: d68a6d5033587b25ec37031a1b7884fc002a3e6a
Parents: 912c923
Author: Isuru Haththotuwa <[email protected]>
Authored: Wed Nov 4 19:10:08 2015 +0530
Committer: Isuru Haththotuwa <[email protected]>
Committed: Tue Nov 10 13:32:43 2015 +0530

----------------------------------------------------------------------
 .../modules/aws-extension/INSTALL.md            |  10 +-
 .../aws-extension/src/main/assembly/bin.xml     |   5 +
 .../aws-extension/src/main/bin/aws-extension.sh |   7 +-
 .../aws-extension/src/main/conf/aws.properties  |   2 +
 .../aws/extension/AWSExtensionContext.java      |  28 +++
 .../apache/stratos/aws/extension/AWSHelper.java | 224 +++++++++++++++---
 .../stratos/aws/extension/AWSLoadBalancer.java  | 227 +++++++++++++++----
 .../apache/stratos/aws/extension/Constants.java |   7 +
 .../exception/PersistenceException.java         |  39 ++++
 .../FileBasedPersistenceManager.java            | 161 +++++++++++++
 .../persistence/PersistenceManager.java         |  36 +++
 .../extension/persistence/dao/LBInfoDAO.java    |  52 +++++
 .../extension/persistence/dto/LBInfoDTO.java    |  69 ++++++
 .../src/main/security/client-truststore.jks     | Bin 35240 -> 36562 bytes
 14 files changed, 794 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/INSTALL.md
----------------------------------------------------------------------
diff --git a/extensions/load-balancer/modules/aws-extension/INSTALL.md 
b/extensions/load-balancer/modules/aws-extension/INSTALL.md
index 4f8a090..aec4cfe 100644
--- a/extensions/load-balancer/modules/aws-extension/INSTALL.md
+++ b/extensions/load-balancer/modules/aws-extension/INSTALL.md
@@ -24,9 +24,11 @@ below steps to proceed with the installation:
 
 1. Extract org.apache.stratos.aws.extension-<version>.zip to a desired 
location: <aws-extension-home>.
 
-2. Open <aws-extension-home>/conf/aws-credentials.conf file in text editor and 
update AWS access key and secret key information. 
+2. Open <aws-extension-home>/conf/aws.properties file in text editor and 
update AWS access key and secret key information.
    If you are using HTTPS as the FE protocol for the AWS LBs, upload a 
certificate [1] for the LBs and update 
    load-balancer-ssl-certificate-id with the ARN [2].
+   To enable application level sticky sessions, update 
app-sticky-session-cookie-name with the relevant cookie name. By default
+   its using JSESSIONID.
 
 3. Open <aws-extension-home>/bin/aws-extension.sh file in a text editor and 
update following system properties:
    ```
@@ -37,6 +39,12 @@ below steps to proceed with the installation:
    -Dthrift.receiver.ip=127.0.0.1
    -Dthrift.receiver.port=7615
    -Dnetwork.partition.id=network-partition-1
+
+   # if running in a VPC, set:
+   -Doperating.in.vpc=true
+
+   # if cross-zone loadbalancing is required, set:
+   -Denable.cross.zone.load.balancing=true
    ```
 
 4. Open <aws-extension-home>/conf/jndi.properties file in a text editor and 
update message broker information:

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/assembly/bin.xml
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/assembly/bin.xml 
b/extensions/load-balancer/modules/aws-extension/src/main/assembly/bin.xml
index ba0ad12..31cf4ad 100644
--- a/extensions/load-balancer/modules/aws-extension/src/main/assembly/bin.xml
+++ b/extensions/load-balancer/modules/aws-extension/src/main/assembly/bin.xml
@@ -52,6 +52,11 @@
                 <include>client-truststore.jks</include>
             </includes>
         </fileSet>
+       <fileSet>
+            <directory>${project.basedir}/src/main/resources</directory>
+            <outputDirectory>/resources</outputDirectory>
+            <fileMode>0600</fileMode>
+        </fileSet>
         <fileSet>
             <directory>${project.basedir}</directory>
             <outputDirectory>/</outputDirectory>

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/bin/aws-extension.sh
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/bin/aws-extension.sh 
b/extensions/load-balancer/modules/aws-extension/src/main/bin/aws-extension.sh
index 19936ae..fd4102b 100755
--- 
a/extensions/load-balancer/modules/aws-extension/src/main/bin/aws-extension.sh
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/bin/aws-extension.sh
@@ -27,6 +27,7 @@ class_path=`echo ${lib_path}/*.jar | tr ' ' ':'`
 properties="-Djndi.properties.dir=${script_path}/../conf
             
-Dlog4j.properties.file.path=${script_path}/../conf/log4j.properties
             -Daws.properties.file=${script_path}/../conf/aws.properties
+            -Dlb.info.file=${script_path}/../resources/lbinformation.ser
             
-Djavax.net.ssl.trustStore=${script_path}/../security/client-truststore.jks
             -Djavax.net.ssl.trustStorePassword=wso2carbon
             
-Dthrift.client.config.file.path=${script_path}/../conf/thrift-client-config.xml
@@ -35,7 +36,11 @@ properties="-Djndi.properties.dir=${script_path}/../conf
             -Dthrift.receiver.port=7615
             -Dnetwork.partition.id=network-partition-1
             -Dcluster.id=cluster-1
-            -Dservice.name=service-1"
+            -Dservice.name=service-1
+            -Dterminate.lbs.on.extension.stop=false
+            -Dterminate.lb.on.cluster.removal=true
+            -Doperating.in.vpc=true
+            -Denable.cross.zone.load.balancing=true"
 
 
 # Uncomment below line to enable remote debugging

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/conf/aws.properties
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/conf/aws.properties 
b/extensions/load-balancer/modules/aws-extension/src/main/conf/aws.properties
index ebdf614..39a5d84 100644
--- 
a/extensions/load-balancer/modules/aws-extension/src/main/conf/aws.properties
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/conf/aws.properties
@@ -38,3 +38,5 @@ statistics-interval=60
 # You can request these details for a specific certificate object by 
referencing the name of the certificate object:
 # aws iam get-server-certificate --server-certificate-name 
your-certificate-name
 load-balancer-ssl-certificate-id=
+# Enable Application generated cookie stickiness by specifying the Cookie name 
uses
+app-sticky-session-cookie-name=JSESSIONID

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java
index d3da969..9b2ef4a 100644
--- 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSExtensionContext.java
@@ -36,6 +36,10 @@ public class AWSExtensionContext {
     private String networkPartitionId;
     private String clusterId;
     private String serviceName;
+    private boolean terminateLBsOnExtensionStop;
+    private boolean terminateLBOnClusterRemoval;
+    private boolean operatingInVPC;
+    private boolean enableCrossZoneLoadBalancing;
 
     private AWSExtensionContext() {
         this.cepStatsPublisherEnabled = 
Boolean.getBoolean(Constants.CEP_STATS_PUBLISHER_ENABLED);
@@ -44,6 +48,10 @@ public class AWSExtensionContext {
         this.networkPartitionId = 
System.getProperty(Constants.NETWORK_PARTITION_ID);
         this.clusterId = System.getProperty(Constants.CLUSTER_ID);
         this.serviceName = System.getProperty(Constants.SERVICE_NAME);
+        this.terminateLBsOnExtensionStop = 
Boolean.getBoolean(Constants.TERMINATE_LBS_ON_EXTENSION_STOP);
+        this.terminateLBOnClusterRemoval = 
Boolean.getBoolean(Constants.TERMINATE_LB_ON_CLUSTER_REMOVAL);
+        this.operatingInVPC = Boolean.getBoolean(Constants.OPERATIMG_IN_VPC);
+        this.enableCrossZoneLoadBalancing = 
Boolean.getBoolean(Constants.ENABLE_CROSS_ZONE_LOADBALANCING);
 
         if (log.isDebugEnabled()) {
             log.debug(Constants.CEP_STATS_PUBLISHER_ENABLED + " = " + 
cepStatsPublisherEnabled);
@@ -51,6 +59,10 @@ public class AWSExtensionContext {
             log.debug(Constants.THRIFT_RECEIVER_PORT + " = " + 
thriftReceiverPort);
             log.debug(Constants.NETWORK_PARTITION_ID + " = " + 
networkPartitionId);
             log.debug(Constants.CLUSTER_ID + " = " + clusterId);
+            log.debug(Constants.TERMINATE_LBS_ON_EXTENSION_STOP + "=" + 
terminateLBsOnExtensionStop);
+            log.debug(Constants.TERMINATE_LB_ON_CLUSTER_REMOVAL + "=" + 
terminateLBOnClusterRemoval);
+            log.debug(Constants.OPERATIMG_IN_VPC + "=" + operatingInVPC);
+            log.debug(Constants.ENABLE_CROSS_ZONE_LOADBALANCING + "=" +  
enableCrossZoneLoadBalancing);
         }
     }
 
@@ -98,4 +110,20 @@ public class AWSExtensionContext {
     public String getServiceName() {
         return serviceName;
     }
+
+    public boolean terminateLBsOnExtensionStop() {
+        return terminateLBsOnExtensionStop;
+    }
+
+    public boolean terminateLBOnClusterRemoval() {
+        return terminateLBOnClusterRemoval;
+    }
+
+    public boolean isOperatingInVPC() {
+        return operatingInVPC;
+    }
+
+    public boolean isCrossZoneLoadBalancingEnabled () {
+        return enableCrossZoneLoadBalancing;
+    }
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java
index 4bdd3e5..c9500f7 100644
--- 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSHelper.java
@@ -22,16 +22,13 @@ package org.apache.stratos.aws.extension;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import com.amazonaws.AmazonServiceException;
+import com.amazonaws.services.ec2.model.*;
+import com.amazonaws.services.elasticloadbalancing.model.Instance;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.stratos.load.balancer.common.domain.*;
@@ -48,13 +45,6 @@ import com.amazonaws.services.cloudwatch.model.Dimension;
 import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsRequest;
 import com.amazonaws.services.cloudwatch.model.GetMetricStatisticsResult;
 import com.amazonaws.services.ec2.AmazonEC2Client;
-import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
-import com.amazonaws.services.ec2.model.CreateSecurityGroupRequest;
-import com.amazonaws.services.ec2.model.CreateSecurityGroupResult;
-import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest;
-import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult;
-import com.amazonaws.services.ec2.model.IpPermission;
-import com.amazonaws.services.ec2.model.SecurityGroup;
 import 
com.amazonaws.services.elasticloadbalancing.AmazonElasticLoadBalancingClient;
 import com.amazonaws.services.elasticloadbalancing.model.*;
 
@@ -67,6 +57,7 @@ public class AWSHelper {
        private String allowedCidrIpForLBSecurityGroup;
        private int statisticsInterval;
        private String sslCertificateId;
+       private String appStickySessionCookie;
 
        private AtomicInteger lbSequence;
 
@@ -130,7 +121,10 @@ public class AWSHelper {
                        // Read the SSL certificate Id. This is mandatory if 
only we are using HTTPS as the front end protocol.
                        // 
http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/using-elb-listenerconfig-quickref.html
                        this.sslCertificateId = properties
-                                       
.getProperty(Constants.LOAD_BALANCER_SSL_CERTIFICATE_ID);
+                                       
.getProperty(Constants.LOAD_BALANCER_SSL_CERTIFICATE_ID).trim();
+
+                       // Cookie name for application level stickiness
+                       this.appStickySessionCookie = 
properties.getProperty(Constants.APP_STICKY_SESSION_COOKIE_NAME).trim();
 
                        this.allowedCidrIpForLBSecurityGroup = properties
                                        
.getProperty(Constants.ALLOWED_CIDR_IP_KEY);
@@ -233,7 +227,7 @@ public class AWSHelper {
         * @throws LoadBalancerExtensionException
         */
        public String createLoadBalancer(String name, List<Listener> listeners,
-                       String region) throws LoadBalancerExtensionException {
+                       String region, String availabilityZone, boolean inVPC) 
throws LoadBalancerExtensionException {
 
                log.info("Creating load balancer " + name);
 
@@ -242,18 +236,23 @@ public class AWSHelper {
 
                createLoadBalancerRequest.setListeners(listeners);
 
+               // don't need this now since we are anyway updating zone 
according to the member
+//             Set<String> availabilityZones = new HashSet<String>();
+//             availabilityZones.add(getAvailabilityZoneFromRegion(region));
+//
+//             
createLoadBalancerRequest.setAvailabilityZones(availabilityZones);
                Set<String> availabilityZones = new HashSet<String>();
-               availabilityZones.add(getAvailabilityZoneFromRegion(region));
-
+               availabilityZones.add(availabilityZone);
                
createLoadBalancerRequest.setAvailabilityZones(availabilityZones);
 
                try {
-                       String securityGroupId = 
getSecurityGroupIdForRegion(region);
+                       if (inVPC) {
+                               String securityGroupId = 
getSecurityGroupIdForRegion(region);
+                               List<String> securityGroups = new 
ArrayList<String>();
+                               securityGroups.add(securityGroupId);
 
-                       List<String> securityGroups = new ArrayList<String>();
-                       securityGroups.add(securityGroupId);
-
-                       
createLoadBalancerRequest.setSecurityGroups(securityGroups);
+                               
createLoadBalancerRequest.setSecurityGroups(securityGroups);
+                       }
 
                        elbClient.setEndpoint(String.format(
                                        Constants.ELB_ENDPOINT_URL_FORMAT, 
region));
@@ -264,8 +263,9 @@ public class AWSHelper {
                        return clbResult.getDNSName();
 
                } catch (AmazonClientException e) {
-                       throw new LoadBalancerExtensionException(
-                                       "Could not create load balancer " + 
name, e);
+                       String errorMsg = "Could not create load balancer " + 
name;
+                       log.error(errorMsg, e);
+                       throw new LoadBalancerExtensionException(errorMsg, e);
                }
        }
 
@@ -378,7 +378,7 @@ public class AWSHelper {
         *            of the load balancer
         * @return description of the load balancer
         */
-       private LoadBalancerDescription getLoadBalancerDescription(
+       public LoadBalancerDescription getLoadBalancerDescription(
                        String loadBalancerName, String region) {
 
                List<String> loadBalancers = new ArrayList<String>();
@@ -430,8 +430,9 @@ public class AWSHelper {
                } catch (AmazonClientException e) {
                        log.error("Could not find instances attached  load 
balancer "
                                        + loadBalancerName, e);
-                       return null;
                }
+
+               return null;
        }
 
        /**
@@ -886,11 +887,12 @@ public class AWSHelper {
         * @return name of the load balancer
         * @throws LoadBalancerExtensionException
         */
-       public String generateLoadBalancerName()
+       public String generateLoadBalancerName(String serviceName)
                        throws LoadBalancerExtensionException {
                String name = null;
 
-               name = lbPrefix + getNextLBSequence();
+               //name = lbPrefix + getNextLBSequence();
+               name = lbPrefix + serviceName;
 
                if (name.length() > Constants.LOAD_BALANCER_NAME_MAX_LENGTH)
                        throw new LoadBalancerExtensionException(
@@ -942,7 +944,171 @@ public class AWSHelper {
                        return null;
        }
 
+       public CreateAppCookieStickinessPolicyResult 
createStickySessionPolicy(String lbName, String cookieName, String policyName, 
String region) {
+
+               
elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region));
+
+               CreateAppCookieStickinessPolicyRequest stickinessPolicyReq = 
new CreateAppCookieStickinessPolicyRequest().
+                               
withLoadBalancerName(lbName).withCookieName(cookieName).withPolicyName(policyName);
+
+               CreateAppCookieStickinessPolicyResult stickinessPolicyResult = 
null;
+               try {
+                       stickinessPolicyResult = 
elbClient.createAppCookieStickinessPolicy(stickinessPolicyReq);
+
+               } catch (AmazonServiceException e) {
+                       log.error(e.getMessage(), e);
+
+               } catch (AmazonClientException e) {
+                       log.error(e.getMessage(), e);
+               }
+
+               if (stickinessPolicyResult == null) {
+                       log.error("Error in creating Application Stickiness 
policy for for cookie name: " + cookieName + ", policy: " + policyName);
+               } else {
+                       log.info("Enabled Application stickiness using: " + 
cookieName + ", policy: " + policyName + " for LB " + lbName);
+               }
+
+               return stickinessPolicyResult;
+       }
+
+       public void applyPolicyToLBListenerPorts(Collection<Port> ports, String 
loadBalancerName, String policyName, String region) {
+
+               for (Port port : ports) {
+                       if ("HTTP".equalsIgnoreCase(port.getProtocol()) || 
"HTTPS".equalsIgnoreCase(port.getProtocol())) {
+                               applyPolicyToListener(loadBalancerName, 
port.getProxy(), policyName, region);
+                               // hack to stop too many calls to AWS API :(
+                               try {
+                                       Thread.sleep(2000);
+                               } catch (InterruptedException e) {}
+                       }
+               }
+       }
+
+       private void applyPolicyToListener (String loadBalancerName, int 
listenerPort, String policyName, String region) {
+
+               SetLoadBalancerPoliciesOfListenerRequest 
loadBalancerPoliciesOfListenerReq =  new 
SetLoadBalancerPoliciesOfListenerRequest().
+                               
withLoadBalancerName(loadBalancerName).withLoadBalancerPort(listenerPort).withPolicyNames(policyName);
+
+               
elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region));
+
+               SetLoadBalancerPoliciesOfListenerResult 
setLBPoliciesOfListenerRes = null;
+               try {
+                       setLBPoliciesOfListenerRes =  
elbClient.setLoadBalancerPoliciesOfListener(loadBalancerPoliciesOfListenerReq);
+
+               } catch (AmazonServiceException e) {
+                       log.error(e.getMessage(), e);
+
+               } catch (AmazonClientException e) {
+                       log.error(e.getMessage(), e);
+               }
+
+               if (setLBPoliciesOfListenerRes == null) {
+                       log.error("Unable to apply policy " + policyName + " 
for Listener port: " + listenerPort + " for LB: " + loadBalancerName);
+               } else {
+                       log.info("Successfully applied policy " + policyName + 
" for Listener port: " + listenerPort + " for LB: " + loadBalancerName);
+               }
+       }
+
+       public List<String> getAvailabilityZonesFromRegion (final String 
region) {
+
+               DescribeAvailabilityZonesRequest availabilityZonesReq = new 
DescribeAvailabilityZonesRequest();
+               List<Filter> availabilityZoneFilters = new ArrayList<Filter>();
+               availabilityZoneFilters.add(new Filter("region-name", new 
ArrayList<String>() {{
+                       add(region);
+               }}));
+               availabilityZoneFilters.add(new Filter("state", new 
ArrayList<String>() {{
+                       add("available");
+               }}));
+
+               
ec2Client.setEndpoint(String.format(Constants.EC2_ENDPOINT_URL_FORMAT, region));
+               DescribeAvailabilityZonesResult availabilityZonesRes = null;
+
+               try {
+                       availabilityZonesRes = 
ec2Client.describeAvailabilityZones(availabilityZonesReq);
+
+               } catch (AmazonServiceException e) {
+                       log.error(e.getMessage(), e);
+
+               } catch (AmazonClientException e) {
+                       log.error(e.getMessage(), e);
+               }
+
+               List<String> availabilityZones = null;
+
+               if (availabilityZonesRes != null) {
+                       availabilityZones = new ArrayList<>();
+                       for (AvailabilityZone zone : 
availabilityZonesRes.getAvailabilityZones()) {
+                               availabilityZones.add(zone.getZoneName());
+                       }
+               } else {
+                       log.error("Unable to retrieve the active availability 
zones for region " + region);
+               }
+
+               return availabilityZones;
+       }
+
+       public void addAvailabilityZonesForLoadBalancer (String 
loadBalancerName, List<String> availabilityZones, String region) {
+
+               EnableAvailabilityZonesForLoadBalancerRequest 
enableAvailabilityZonesReq = new EnableAvailabilityZonesForLoadBalancerRequest()
+                               
.withLoadBalancerName(loadBalancerName).withAvailabilityZones(availabilityZones);
+
+               
elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region));
+
+               EnableAvailabilityZonesForLoadBalancerResult 
enableAvailabilityZonesRes = null;
+
+               try {
+                       enableAvailabilityZonesRes = 
elbClient.enableAvailabilityZonesForLoadBalancer(enableAvailabilityZonesReq);
+
+               } catch (AmazonServiceException e) {
+                       log.error(e.getMessage(), e);
+
+               } catch (AmazonClientException e) {
+                       log.error(e.getMessage(), e);
+               }
+
+               if (enableAvailabilityZonesRes != null) {
+                       log.info("Availability zones successfully added to LB " 
+ loadBalancerName + ". Updated zone list: ");
+                       for (String zone : 
enableAvailabilityZonesRes.getAvailabilityZones()) {
+                               log.info(zone);
+                       }
+               } else {
+                       log.error("Updating availability zones failed for LB " 
+ loadBalancerName);
+               }
+       }
+
+       public void modifyLBAttributes (String loadBalancerName, String region, 
boolean enableCrossZoneLbing, boolean enableConnDraining) {
+
+               if (!enableCrossZoneLbing && !enableConnDraining) {
+                       log.info("No attributes specified to modify in the LB " 
+ loadBalancerName);
+                       return;
+               }
+
+               ModifyLoadBalancerAttributesRequest modifyLBAttributesReq = new 
ModifyLoadBalancerAttributesRequest().withLoadBalancerName(loadBalancerName);
+               LoadBalancerAttributes modifiedLbAttributes = new 
LoadBalancerAttributes();
+               if (enableCrossZoneLbing) {
+                       modifiedLbAttributes.setCrossZoneLoadBalancing(new 
CrossZoneLoadBalancing().withEnabled(true));
+               }
+               if (enableConnDraining) {
+                       modifiedLbAttributes.setConnectionDraining(new 
ConnectionDraining().withEnabled(true));
+               }
+
+               
modifyLBAttributesReq.setLoadBalancerAttributes(modifiedLbAttributes);
+
+               
elbClient.setEndpoint(String.format(Constants.ELB_ENDPOINT_URL_FORMAT, region));
+
+               ModifyLoadBalancerAttributesResult modifyLBAttributesRes = 
elbClient.modifyLoadBalancerAttributes(modifyLBAttributesReq);
+               if (modifyLBAttributesRes != null) {
+                       log.info("Successfully enabled cross zone load 
balancing and connection draining for " + loadBalancerName);
+               } else {
+                       log.error("Failed to enable cross zone load balancing 
and connection draining for " + loadBalancerName);
+               }
+       }
+
        public String getSslCertificateId() {
                return sslCertificateId;
        }
+
+       public String getAppStickySessionCookie() {
+               return appStickySessionCookie;
+       }
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java
index c3a63ee..8389ec0 100644
--- 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/AWSLoadBalancer.java
@@ -19,10 +19,16 @@
 
 package org.apache.stratos.aws.extension;
 
+import 
com.amazonaws.services.elasticloadbalancing.model.CreateAppCookieStickinessPolicyResult;
 import com.amazonaws.services.elasticloadbalancing.model.Instance;
 import com.amazonaws.services.elasticloadbalancing.model.Listener;
+import 
com.amazonaws.services.elasticloadbalancing.model.LoadBalancerDescription;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.aws.extension.exception.PersistenceException;
+import 
org.apache.stratos.aws.extension.persistence.FileBasedPersistenceManager;
+import org.apache.stratos.aws.extension.persistence.PersistenceManager;
+import org.apache.stratos.aws.extension.persistence.dto.LBInfoDTO;
 import org.apache.stratos.load.balancer.common.domain.Cluster;
 import org.apache.stratos.load.balancer.common.domain.Member;
 import org.apache.stratos.load.balancer.common.domain.Service;
@@ -30,10 +36,7 @@ import 
org.apache.stratos.load.balancer.common.domain.Topology;
 import org.apache.stratos.load.balancer.extension.api.LoadBalancer;
 import 
org.apache.stratos.load.balancer.extension.api.exception.LoadBalancerExtensionException;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 public class AWSLoadBalancer implements LoadBalancer {
@@ -47,8 +50,13 @@ public class AWSLoadBalancer implements LoadBalancer {
        // Object used to invoke methods related to AWS API
        private AWSHelper awsHelper;
 
+       // PersistenceManager: used to persist LB Information by tuples of <lb 
name, cluster id, region>
+       PersistenceManager persistenceManager;
+
        public AWSLoadBalancer() throws LoadBalancerExtensionException {
                awsHelper = new AWSHelper();
+               persistenceManager = new FileBasedPersistenceManager();
+               initialize();
        }
 
        /*
@@ -100,6 +108,7 @@ public class AWSLoadBalancer implements LoadBalancer {
                                                
activeClusters.add(cluster.getClusterId());
 
                                                List<Instance> 
instancesToAddToLoadBalancer = new ArrayList<Instance>();
+                                               List<String> availabilityZones 
= new ArrayList<String>();
 
                                                for (Member member : 
clusterMembers) {
                                                        // if instance id of 
member is not in
@@ -113,6 +122,7 @@ public class AWSLoadBalancer implements LoadBalancer {
                                                                        || 
!attachedInstances.contains(instance)) {
                                                                
instancesToAddToLoadBalancer.add(instance);
 
+
                                                                if 
(log.isDebugEnabled()) {
                                                                        
log.debug("Instance "
                                                                                
        + awsHelper
@@ -122,13 +132,25 @@ public class AWSLoadBalancer implements LoadBalancer {
                                                                                
        + loadBalancerName);
                                                                }
 
+                                                               // LB Common 
Member has a property 'EC2_AVAILABILITY_ZONE' points to the ec2 availability 
zone
+                                                               // for this 
member. Use the property value to update the LB about the relevant zone
+                                                               String 
availabilityZone = getEC2AvaialbilityZoneOfMember(member);
+                                                               if 
(availabilityZone != null) {
+                                                                       
availabilityZones.add(availabilityZone);
+                                                               }
                                                        }
                                                }
 
-                                               if 
(instancesToAddToLoadBalancer.size() > 0)
+                                               if 
(instancesToAddToLoadBalancer.size() > 0) {
                                                        
awsHelper.registerInstancesToLoadBalancer(
                                                                        
loadBalancerName,
                                                                        
instancesToAddToLoadBalancer, region);
+                                               }
+
+                                               // update LB with the zones
+                                               if 
(!availabilityZones.isEmpty()) {
+                                                       
awsHelper.addAvailabilityZonesForLoadBalancer(loadBalancerName, 
availabilityZones, region);
+                                               }
                                        }
 
                                } else {
@@ -136,26 +158,38 @@ public class AWSLoadBalancer implements LoadBalancer {
                                        Collection<Member> clusterMembers = 
cluster.getMembers();
 
                                        if (clusterMembers.size() > 0) {
+                                               Member aMember = 
clusterMembers.iterator().next();
+
                                                // a unique load balancer name 
with user-defined
                                                // prefix and a sequence number.
                                                String loadBalancerName = 
awsHelper
-                                                               
.generateLoadBalancerName();
+                                                               
.generateLoadBalancerName(cluster.getServiceName());
 
-                                               String region = 
awsHelper.getAWSRegion(clusterMembers
-                                                               
.iterator().next().getInstanceId());
+                                               String region = 
awsHelper.getAWSRegion(aMember.getInstanceId());
 
                                                // list of AWS listeners 
obtained using port
                                                // mappings of one of the 
members of the cluster.
                                                List<Listener> 
listenersForThisCluster = awsHelper
-                                                               
.getRequiredListeners(clusterMembers.iterator()
-                                                                               
.next());
+                                                               
.getRequiredListeners(aMember);
+
+                                               // Get the zone from the first 
member and use in LB creation. Zone will be updated for each member below
+                                               String initialAvailabilityZone 
= getEC2AvaialbilityZoneOfMember(aMember);
+                                               if (initialAvailabilityZone == 
null) {
+                                                       // could not get the 
availability zone from the Member property 'EC2_AVAILABILITY_ZONE'
+                                                       // use the default 
(<region>a)
+                                                       initialAvailabilityZone 
= awsHelper.getAvailabilityZoneFromRegion(region);
+                                               }
 
-                                               // DNS name of load balancer 
which was created.
+                                               // Returns DNS name of load 
balancer which was created.
                                                // This is used in the domain 
mapping of this
                                                // cluster.
                                                String loadBalancerDNSName = 
awsHelper
                                                                
.createLoadBalancer(loadBalancerName,
-                                                                               
listenersForThisCluster, region);
+                                                                               
listenersForThisCluster, region, initialAvailabilityZone, 
AWSExtensionContext.getInstance().isOperatingInVPC());
+
+                                               // enable connection draining 
(default) and cross zone load balancing (if specified in aws-extension.sh)
+                                               
awsHelper.modifyLBAttributes(loadBalancerName, region, 
AWSExtensionContext.getInstance().isCrossZoneLoadBalancingEnabled(),
+                                                               true);
 
                                                // Add the inbound rule the 
security group of the load
                                                // balancer
@@ -183,6 +217,7 @@ public class AWSLoadBalancer implements LoadBalancer {
 
                                                // Register instances in the 
cluster to load balancer
                                                List<Instance> instances = new 
ArrayList<Instance>();
+                                               List<String> availabilityZones 
= new ArrayList<String>();
 
                                                for (Member member : 
clusterMembers) {
                                                        String instanceId = 
member.getInstanceId();
@@ -200,11 +235,43 @@ public class AWSLoadBalancer implements LoadBalancer {
                                                                        
.getAWSInstanceName(instanceId));
 
                                                        instances.add(instance);
+                                                       // LB Common Member has 
a property 'EC2_AVAILABILITY_ZONE' which points to the ec2 availability
+                                                       // zone for this 
member. Use the property value to update the LB about the relevant zone
+                                                       String availabilityZone 
= getEC2AvaialbilityZoneOfMember(member);
+                                                       if (availabilityZone != 
null) {
+                                                               
availabilityZones.add(availabilityZone);
+                                                       }
                                                }
 
                                                
awsHelper.registerInstancesToLoadBalancer(
                                                                
loadBalancerName, instances, region);
 
+                                               // update LB with the zones
+                                               if 
(!availabilityZones.isEmpty()) {
+                                                       
awsHelper.addAvailabilityZonesForLoadBalancer(loadBalancerName, 
availabilityZones, region);
+                                               }
+
+                                               // add stickiness policy
+                                               if 
(awsHelper.getAppStickySessionCookie() != null && 
!awsHelper.getAppStickySessionCookie().isEmpty()) {
+                                                       
CreateAppCookieStickinessPolicyResult result = 
awsHelper.createStickySessionPolicy(loadBalancerName, 
awsHelper.getAppStickySessionCookie(),
+                                                                       
Constants.STICKINESS_POLICY, region);
+
+                                                       if (result != null) {
+                                                               // Take a 
single port mapping from a member, and apply the policy for
+                                                               // the LB 
Listener port (Proxy port of the port mapping)
+                                                               
awsHelper.applyPolicyToLBListenerPorts(aMember.getPorts(), loadBalancerName, 
Constants.STICKINESS_POLICY, region);
+                                                       }
+                                               }
+
+                                               // persist LB info
+                                               try {
+                                                       
persistenceManager.persist(new LBInfoDTO(loadBalancerName, 
cluster.getClusterId(), region));
+
+                                               } catch (PersistenceException 
e) {
+                                                       log.error("Unable to 
persist LB Information for " + loadBalancerName + ", cluster id " +
+                                                               
cluster.getClusterId());
+                                               }
+
                                                LoadBalancerInfo 
loadBalancerInfo = new LoadBalancerInfo(
                                                                
loadBalancerName, region);
 
@@ -212,39 +279,49 @@ public class AWSLoadBalancer implements LoadBalancer {
                                                                
loadBalancerInfo);
                                                
activeClusters.add(cluster.getClusterId());
                                        }
-                               }
-
-                               // sleep to stop AWS Rate Exceeding: Caused by: 
com.amazonaws.AmazonServiceException: Rate exceeded
-                               // (Service: AmazonElasticLoadBalancing; Status 
Code: 400; Error Code: Throttling; Request ID: xxx-xxx)
-                               try {
-                                       Thread.sleep(3000);
-                               } catch (InterruptedException ignored) {}
 
+                                       pause(3000);
+                               }
                        }
                }
 
-               // Find out clusters which were present earlier but are not now.
-               List<String> clustersToRemoveFromMap = new ArrayList<String>();
+               // if 'terminate.lb.on.cluster.removal' = true in 
aws-extension.sh
+               if 
(AWSExtensionContext.getInstance().terminateLBOnClusterRemoval()) {
 
-               for (String clusterId : clusterIdToLoadBalancerMap.keySet()) {
-                       if (!activeClusters.contains(clusterId)) {
-                               clustersToRemoveFromMap.add(clusterId);
+                       // Find out clusters which were present earlier but are 
not now.
+                       List<String> clustersToRemoveFromMap = new 
ArrayList<String>();
+                       // TODO: improve using an iterator and removing the 
unwanted cluster id in this loop
+                       for (String clusterId : 
clusterIdToLoadBalancerMap.keySet()) {
+                               if (!activeClusters.contains(clusterId)) {
+                                       clustersToRemoveFromMap.add(clusterId);
 
-                               if (log.isDebugEnabled()) {
-                                       log.debug("Load balancer for cluster " 
+ clusterId
-                                                       + " needs to be 
removed.");
-                               }
+                                       if (log.isDebugEnabled()) {
+                                               log.debug("Load balancer for 
cluster " + clusterId
+                                                               + " needs to be 
removed.");
+                                       }
 
+                               }
                        }
-               }
 
-               // Delete load balancers associated with these clusters.
-               for (String clusterId : clustersToRemoveFromMap) {
-                       // Remove load balancer for this cluster.
-                       awsHelper.deleteLoadBalancer(
-                                       
clusterIdToLoadBalancerMap.get(clusterId).getName(),
-                                       
clusterIdToLoadBalancerMap.get(clusterId).getRegion());
-                       clusterIdToLoadBalancerMap.remove(clusterId);
+
+                       // Delete load balancers associated with these clusters.
+                       for (String clusterId : clustersToRemoveFromMap) {
+                               // Remove load balancer for this cluster.
+                               final String loadBalancerName = 
clusterIdToLoadBalancerMap.get(clusterId).getName();
+                               final String region = 
clusterIdToLoadBalancerMap.get(clusterId).getRegion();
+                               awsHelper.deleteLoadBalancer(
+                                               loadBalancerName,
+                                               region);
+                               //remove and persist
+                               try {
+                                       persistenceManager.remove(new 
LBInfoDTO(loadBalancerName, clusterId, region));
+
+                               } catch (PersistenceException e) {
+                                       log.error("Unable to persist LB 
Information for " + loadBalancerName + ", cluster id " +
+                                                       clusterId);
+                               }
+                               clusterIdToLoadBalancerMap.remove(clusterId);
+                       }
                }
 
                activeClusters.clear();
@@ -252,6 +329,14 @@ public class AWSLoadBalancer implements LoadBalancer {
                return true;
        }
 
+       private String getEC2AvaialbilityZoneOfMember(Member member) {
+               if (member.getProperties() != null) {
+            return 
member.getProperties().getProperty(Constants.EC2_AVAILABILITY_ZONE_PROPERTY);
+        }
+
+               return null;
+       }
+
        /*
         * start method is called after extension if configured first time. Does
         * nothing but logs the message.
@@ -261,6 +346,41 @@ public class AWSLoadBalancer implements LoadBalancer {
                log.info("AWS load balancer extension started.");
        }
 
+       private void initialize() {
+               // load persisted LB information
+               Set<LBInfoDTO> lbInfo = null;
+               try {
+                       lbInfo = persistenceManager.retrieve();
+
+               } catch (PersistenceException e) {
+                       log.error("Unable to retrieve persisted LB 
Information", e);
+               }
+
+               if (lbInfo != null) {
+                       for (LBInfoDTO lbInfoDTO : lbInfo) {
+                               LoadBalancerDescription lbDesc = 
awsHelper.getLoadBalancerDescription(lbInfoDTO.getName(),
+                                               lbInfoDTO.getRegion());
+                               if (lbDesc != null) {
+                                       
clusterIdToLoadBalancerMap.put(lbInfoDTO.getClusterId(), new 
LoadBalancerInfo(lbInfoDTO.getName(),
+                                                       lbInfoDTO.getRegion()));
+                               } else {
+                                       // make debug
+                                       if (log.isInfoEnabled()) {
+                                               log.info("Unable to locate LB " 
+ lbInfoDTO.getName());
+                                       }
+                                       // remove the persisted entry
+                                       try {
+                                               persistenceManager.remove(new 
LBInfoDTO(lbInfoDTO.getName(), lbInfoDTO.getClusterId(), 
lbInfoDTO.getRegion()));
+
+                                       } catch (PersistenceException e) {
+                                               log.error("Unable to remove 
persisted LB Information", e);
+                                       }
+                               }
+
+                       }
+               }
+       }
+
        /*
         * reload method is called every time after extension if configured. 
Does
         * nothing but logs the message.
@@ -274,15 +394,38 @@ public class AWSLoadBalancer implements LoadBalancer {
         * stop method deletes load balancers for all clusters in the topology.
         */
        public void stop() throws LoadBalancerExtensionException {
-               // Remove all load balancers
-               for (LoadBalancerInfo loadBalancerInfo : 
clusterIdToLoadBalancerMap
-                               .values()) {
-                       // Remove load balancer
-                       awsHelper.deleteLoadBalancer(loadBalancerInfo.getName(),
-                                       loadBalancerInfo.getRegion());
+               // Remove all load balancers if 
'terminate.lbs.on.extension.stop' = true in aws-extension.sh
+               if 
(AWSExtensionContext.getInstance().terminateLBsOnExtensionStop()) {
+                       for (Map.Entry<String, LoadBalancerInfo> lbInfoEntry : 
clusterIdToLoadBalancerMap
+                                       .entrySet()) {
+                               // Remove load balancer
+                               
awsHelper.deleteLoadBalancer(lbInfoEntry.getValue().getName(),
+                                               
lbInfoEntry.getValue().getRegion());
+
+                               // remove the persisted entry
+                               try {
+                                       persistenceManager.remove(new 
LBInfoDTO(lbInfoEntry.getValue().getName(), lbInfoEntry.getKey(),
+                                                       
lbInfoEntry.getValue().getRegion()));
+
+                               } catch (PersistenceException e) {
+                                       log.error("Unable to remove persisted 
LB Information", e);
+                               }
+                       }
+               } else {
+                       if (log.isInfoEnabled()) {
+                               log.info("Not terminating LBs since 
terminate.lbs.on.extension.stop=false");
+                       }
                }
        }
 
+       private static void pause (long duration) {
+               // sleep to stop AWS Rate Exceeding: Caused by: 
com.amazonaws.AmazonServiceException: Rate exceeded
+               // (Service: AmazonElasticLoadBalancing; Status Code: 400; 
Error Code: Throttling; Request ID: xxx-xxx)
+               try {
+                       Thread.sleep(duration);
+               } catch (InterruptedException ignored) {}
+       }
+
        public static ConcurrentHashMap<String, LoadBalancerInfo> 
getClusterIdToLoadBalancerMap() {
                return clusterIdToLoadBalancerMap;
        }

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java
index 626f1ce..dbcfb9a 100644
--- 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/Constants.java
@@ -54,4 +54,11 @@ public class Constants {
        public static final String STATISTICS_INTERVAL = "statistics-interval";
        public static final int STATISTICS_INTERVAL_MULTIPLE_OF = 60;
        public static final String LOAD_BALANCER_SSL_CERTIFICATE_ID = 
"load-balancer-ssl-certificate-id";
+       public static final String APP_STICKY_SESSION_COOKIE_NAME = 
"app-sticky-session-cookie-name";
+       public static final String TERMINATE_LBS_ON_EXTENSION_STOP = 
"terminate.lbs.on.extension.stop";
+       public static final String TERMINATE_LB_ON_CLUSTER_REMOVAL = 
"terminate.lb.on.cluster.removal";
+       public static final String STICKINESS_POLICY = "stickiness-policy";
+       public static final String OPERATIMG_IN_VPC = "operating.in.vpc";
+       public static final String ENABLE_CROSS_ZONE_LOADBALANCING = 
"enable.cross.zone.load.balancing";
+       public static final String EC2_AVAILABILITY_ZONE_PROPERTY = 
"EC2_AVAILABILITY_ZONE";
 }

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/exception/PersistenceException.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/exception/PersistenceException.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/exception/PersistenceException.java
new file mode 100644
index 0000000..eb3fa52
--- /dev/null
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/exception/PersistenceException.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.stratos.aws.extension.exception;
+
+public class PersistenceException extends Exception {
+
+    private final String message;
+
+    public PersistenceException (String message, Throwable cause) {
+        super(message, cause);
+        this.message = message;
+    }
+
+    public PersistenceException (String message) {
+        super(message);
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/FileBasedPersistenceManager.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/FileBasedPersistenceManager.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/FileBasedPersistenceManager.java
new file mode 100644
index 0000000..57b5427
--- /dev/null
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/FileBasedPersistenceManager.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.stratos.aws.extension.persistence;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.stratos.aws.extension.exception.PersistenceException;
+import org.apache.stratos.aws.extension.persistence.dao.LBInfoDAO;
+import org.apache.stratos.aws.extension.persistence.dto.LBInfoDTO;
+
+import java.io.*;
+import java.util.Set;
+
+public class FileBasedPersistenceManager implements PersistenceManager {
+
+    private static final Log log = 
LogFactory.getLog(FileBasedPersistenceManager.class);
+    private String lbInfoFilePath = null;
+
+    public FileBasedPersistenceManager () {
+        lbInfoFilePath = System.getProperty("lb.info.file");
+        if (lbInfoFilePath == null || lbInfoFilePath.isEmpty()) {
+            throw new RuntimeException("required system property lb.info.file 
not found");
+        }
+    }
+
+    @Override
+    public synchronized void persist (LBInfoDTO lbInfoDTO) throws 
PersistenceException {
+
+        LBInfoDAO retrievedLbInfoDAO = retrieveLBInfo();
+        if (retrievedLbInfoDAO == null) {
+            retrievedLbInfoDAO = new LBInfoDAO();
+        }
+
+        retrievedLbInfoDAO.add(lbInfoDTO);
+        persistLBInfo(retrievedLbInfoDAO);
+    }
+
+    @Override
+    public synchronized Set<LBInfoDTO> retrieve () throws PersistenceException 
{
+        return retrieveLBInfo() != null && retrieveLBInfo().get() != null ? 
retrieveLBInfo().get() : null;
+    }
+
+    @Override
+    public synchronized void remove(LBInfoDTO lbInfoDTO) throws 
PersistenceException {
+
+        LBInfoDAO retrievedLbInfoDAO = retrieveLBInfo();
+        if (retrievedLbInfoDAO != null) {
+            retrievedLbInfoDAO.remove(lbInfoDTO);
+            persistLBInfo(retrievedLbInfoDAO);
+        } else {
+            log.info("No persisted LB Information found, hence unable to 
remove information of LB: " + lbInfoDTO.getName());
+        }
+    }
+
+    @Override
+    public synchronized void clear () throws PersistenceException {
+
+        LBInfoDAO retrievedLbInfoDAO = retrieveLBInfo();
+        if (retrievedLbInfoDAO == null) {
+            retrievedLbInfoDAO = new LBInfoDAO();
+        }
+
+        retrievedLbInfoDAO.clear();
+        persistLBInfo(retrievedLbInfoDAO);
+    }
+
+    private void persistLBInfo (LBInfoDAO lbInfoDAO) throws 
PersistenceException {
+
+        FileOutputStream fileOutStream = null;
+        ObjectOutputStream ObjOutStream = null;
+        try {
+            fileOutStream = new FileOutputStream(lbInfoFilePath);
+            ObjOutStream = new ObjectOutputStream(fileOutStream);
+            ObjOutStream.writeObject(lbInfoDAO);
+
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            throw new PersistenceException(e.getMessage(), e);
+
+        } finally {
+            try {
+                if (ObjOutStream != null) {
+                    ObjOutStream.close();
+                }
+                if (fileOutStream != null) {
+                    fileOutStream.close();
+                }
+
+            } catch (IOException e) {
+                log.error(e.getMessage(), e);
+                if (fileOutStream != null) {
+                    try {
+                        fileOutStream.close();
+                    } catch (IOException e1) {}
+                }
+                throw new PersistenceException(e.getMessage(), e);
+            }
+
+        }
+    }
+
+    private LBInfoDAO retrieveLBInfo () throws PersistenceException {
+
+        FileInputStream fileInStream = null;
+        ObjectInputStream objInStream = null;
+
+        try {
+            fileInStream = new FileInputStream(lbInfoFilePath);
+            objInStream = new ObjectInputStream(fileInStream);
+            return (LBInfoDAO) objInStream.readObject();
+
+        } catch (FileNotFoundException e) {
+            log.warn("File lbinformation.ser not found, any previously 
persisted LB information will not be reflected");
+            return null;
+
+        } catch (IOException e) {
+            log.error(e.getMessage(), e);
+            throw new PersistenceException(e.getMessage(), e);
+
+        } catch (ClassNotFoundException e) {
+            log.error(e.getMessage(), e);
+            throw new PersistenceException(e.getMessage(), e);
+
+        } finally {
+            try {
+                if (objInStream != null) {
+                    objInStream.close();
+                }
+                if (fileInStream != null) {
+                    fileInStream.close();
+                }
+
+            } catch (IOException e) {
+                log.error(e.getMessage(), e);
+                if (fileInStream != null) {
+                    try {
+                        fileInStream.close();
+                    } catch (IOException e1) {}
+                }
+                throw new PersistenceException(e.getMessage(), e);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/PersistenceManager.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/PersistenceManager.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/PersistenceManager.java
new file mode 100644
index 0000000..ab7853a
--- /dev/null
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/PersistenceManager.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.stratos.aws.extension.persistence;
+
+import org.apache.stratos.aws.extension.exception.PersistenceException;
+import org.apache.stratos.aws.extension.persistence.dto.LBInfoDTO;
+
+import java.util.Set;
+
+public interface PersistenceManager {
+
+    public void persist (LBInfoDTO lbInfoDTO) throws PersistenceException;
+
+    public Set<LBInfoDTO> retrieve () throws PersistenceException;
+
+    public void remove (LBInfoDTO lbInfoDTO) throws PersistenceException;
+
+    public void clear () throws PersistenceException;
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dao/LBInfoDAO.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dao/LBInfoDAO.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dao/LBInfoDAO.java
new file mode 100644
index 0000000..29af4cf
--- /dev/null
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dao/LBInfoDAO.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.stratos.aws.extension.persistence.dao;
+
+import org.apache.stratos.aws.extension.persistence.dto.LBInfoDTO;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+public class LBInfoDAO implements Serializable {
+
+    private static final long serialVersionUID = 6429853257198804560L;
+    private final Set<LBInfoDTO> lbInformation;
+
+    public LBInfoDAO() {
+        lbInformation = new HashSet<>();
+    }
+
+    public void add (LBInfoDTO lbInfo) {
+        lbInformation.add(lbInfo);
+    }
+
+    public void remove (LBInfoDTO lbInfo) {
+        lbInformation.remove(lbInfo);
+    }
+
+    public void clear () {
+        lbInformation.clear();
+    }
+
+    public Set<LBInfoDTO> get () {
+        return lbInformation;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dto/LBInfoDTO.java
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dto/LBInfoDTO.java
 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dto/LBInfoDTO.java
new file mode 100644
index 0000000..215eb69
--- /dev/null
+++ 
b/extensions/load-balancer/modules/aws-extension/src/main/java/org/apache/stratos/aws/extension/persistence/dto/LBInfoDTO.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.stratos.aws.extension.persistence.dto;
+
+import java.io.Serializable;
+
+public class LBInfoDTO implements Serializable {
+
+    private static final long serialVersionUID = -3788551425235723608L;
+    private String name;
+    private String clusterId;
+    private String region;
+
+    public LBInfoDTO(String name, String clusterId, String region) {
+        this.name = name;
+        this.clusterId = clusterId;
+        this.region = region;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getClusterId () {
+        return clusterId;
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        LBInfoDTO lbInfoDTO = (LBInfoDTO) o;
+
+        if (!name.equals(lbInfoDTO.name)) return false;
+        if (!clusterId.equals(lbInfoDTO.clusterId)) return false;
+        return region.equals(lbInfoDTO.region);
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name.hashCode();
+        result = 31 * result + clusterId.hashCode();
+        result = 31 * result + region.hashCode();
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/stratos/blob/d68a6d50/extensions/load-balancer/modules/aws-extension/src/main/security/client-truststore.jks
----------------------------------------------------------------------
diff --git 
a/extensions/load-balancer/modules/aws-extension/src/main/security/client-truststore.jks
 
b/extensions/load-balancer/modules/aws-extension/src/main/security/client-truststore.jks
index be441f3..4da2690 100644
Binary files 
a/extensions/load-balancer/modules/aws-extension/src/main/security/client-truststore.jks
 and 
b/extensions/load-balancer/modules/aws-extension/src/main/security/client-truststore.jks
 differ

Reply via email to