/*
 * Copyright (C) 2012-2016 Facebook, Inc.
 *
 * Licensed 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 com.facebook.nifty.ssl;

import com.google.common.base.Throwables;
import org.jboss.netty.handler.ssl.SslContext;
import org.jboss.netty.handler.ssl.SslHandler;

import javax.net.ssl.SSLException;
import java.io.File;
import java.net.InetSocketAddress;
import java.net.SocketAddress;

public class SslClientConfiguration {

    public static class Builder {
        Iterable<String> ciphers;
        File caFile;
        long sessionCacheSize = 10000;
        long sessionTimeoutSeconds = 86400;

        public Builder ciphers(Iterable<String> ciphers) {
            this.ciphers = ciphers;
            return this;
        }

        public Builder caFile(File caFile) {
            this.caFile = caFile;
            return this;
        }

        public Builder sessionCacheSize(long sessionCacheSize) {
            this.sessionCacheSize = sessionCacheSize;
            return this;
        }

        public Builder sessionTimeoutSeconds(long sessionTimeoutSeconds) {
            this.sessionTimeoutSeconds = sessionTimeoutSeconds;
            return this;
        }

        public SslClientConfiguration build() {
            return new SslClientConfiguration(this);
        }
    }

    public final Iterable<String> ciphers;
    public final File caFile;
    public final long sessionCacheSize;
    public final long sessionTimeoutSeconds;

    private SslContext clientContext;

    public SslClientConfiguration(Builder builder) {
        this.ciphers = builder.ciphers;
        this.caFile = builder.caFile;
        this.sessionCacheSize = builder.sessionCacheSize;
        this.sessionTimeoutSeconds = builder.sessionTimeoutSeconds;
        try {
            clientContext =
                    SslContext.newClientContext(
                            null,
                            null,
                            caFile,
                            null,
                            ciphers,
                            null,
                            sessionCacheSize,
                            sessionTimeoutSeconds);
        }
        catch (SSLException e) {
            Throwables.propagate(e);
        }
    }

    public SslHandler createHandler() throws Exception {
        return clientContext.newHandler();
    }

    public SslHandler createHandler(SocketAddress address) throws Exception {
        if (!(address instanceof InetSocketAddress)) {
            return createHandler();
        }
        InetSocketAddress netAddress = (InetSocketAddress) address;
        String host = netAddress.getHostString();
        if (host == null) {
            return createHandler();
        }

        return clientContext.newHandler(host, netAddress.getPort());
    }
}

@@ -1099,16 +1099,50 @@
 = 86400;
+%0A        SslContext clientContext;
 %0A%0A      
@@ -1723,299 +1723,514 @@
     
-public SslClientConfiguration build() %7B%0A            return new SslClientConfiguration(this);%0A        %7D
+/**%0A         * Overrides the SslContext with one explicitly provided by the caller. If this is not null, the other%0A         * builder parameters will be ignored. Currently only used for testing and may be removed in the future,
 %0A    
-%7D%0A%0A
+ 
     
-public final Iterable%3CString%3E ciphers;%0A    public final File caFile;%0A    public final long sessionCacheSize;%0A    public final long sessionTimeoutSeconds;%0A%0A    private Ssl
+* once we have netty support for client-side certs.%0A         *%0A         * @param clientContext the client context.%0A         * @return a reference to this builder.%0A         */%0A        public Builder sslContext(SslContext clientContext) %7B%0A            this.client
 Context
+ =
  cli
@@ -2237,25 +2237,64 @@
 entContext;%0A
-%0A
+            return this;%0A        %7D%0A%0A    
     public S
@@ -2318,24 +2318,15 @@
 tion
-(Builder
  build
-er
+(
 ) %7B%0A
@@ -2337,204 +2337,211 @@
     
-this.ciphers = builder.ciphers;%0A        this.caFile = builder.caFile;%0A        this.sessionCacheSize = builder.sessionCacheSize;%0A        this.sessionTimeoutSeconds = builder.sessionTimeoutSeconds;%0A
+    return new SslClientConfiguration(this);%0A        %7D%0A    %7D%0A%0A    private SslContext clientContext;%0A%0A    public SslClientConfiguration(Builder builder) %7B%0A        if (builder.clientContext == null) %7B%0A    
     
@@ -2550,16 +2550,20 @@
   try %7B%0A
+    
         
@@ -2651,38 +2651,30 @@
             
-    
 null,%0A
-    
             
@@ -2719,20 +2719,24 @@
     
-    
+builder.
 caFile,%0A
     
@@ -2731,20 +2731,16 @@
 caFile,%0A
-    
         
@@ -2785,20 +2785,24 @@
         
-    
+builder.
 ciphers,
@@ -2818,36 +2818,32 @@
                 
-  
-  
 null,%0A          
@@ -2852,28 +2852,32 @@
             
-    
+builder.
 sessionCache
@@ -2906,20 +2906,24 @@
         
- 
-   
+builder.
 sessionT
@@ -2945,26 +2945,22 @@
 %0A       
- %7D%0A
      
-  
+%7D
  catch (
@@ -2989,16 +2989,20 @@
         
+    
 Throwabl
@@ -3018,16 +3018,98 @@
 ate(e);%0A
+            %7D%0A        %7D else %7B%0A            clientContext = builder.clientContext;%0A
         

Allow manually specifying SslContext in SslClientConfiguration Needed for testing in a later commit