001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.activemq.transport.nio;
019
020import java.io.IOException;
021import java.net.URI;
022import java.net.URISyntaxException;
023import java.net.UnknownHostException;
024import java.util.Map;
025
026import javax.net.ServerSocketFactory;
027import javax.net.SocketFactory;
028import javax.net.ssl.SSLContext;
029import javax.net.ssl.SSLSocketFactory;
030
031import org.apache.activemq.broker.SslContext;
032import org.apache.activemq.transport.Transport;
033import org.apache.activemq.transport.TransportServer;
034import org.apache.activemq.transport.tcp.SslTransport;
035import org.apache.activemq.transport.tcp.TcpTransportServer;
036import org.apache.activemq.util.IOExceptionSupport;
037import org.apache.activemq.util.IntrospectionSupport;
038import org.apache.activemq.wireformat.WireFormat;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042public class NIOSSLTransportFactory extends NIOTransportFactory {
043    private static final Logger LOG = LoggerFactory.getLogger(NIOSSLTransportFactory.class);
044
045    protected SSLContext context;
046
047    protected TcpTransportServer createTcpTransportServer(URI location, ServerSocketFactory serverSocketFactory) throws IOException, URISyntaxException {
048        return new NIOSSLTransportServer(context, this, location, serverSocketFactory);
049    }
050
051    @Override
052    public TransportServer doBind(URI location) throws IOException {
053        if (SslContext.getCurrentSslContext() != null) {
054            try {
055                context = SslContext.getCurrentSslContext().getSSLContext();
056            } catch (Exception e) {
057                throw new IOException(e);
058            }
059        }
060        return super.doBind(location);
061    }
062
063    /**
064     * Overriding to allow for proper configuration through reflection but
065     * delegate to get common configuration
066     */
067    public Transport compositeConfigure(Transport transport, WireFormat format, Map options) {
068        if (transport instanceof SslTransport) {
069            SslTransport sslTransport = (SslTransport) transport.narrow(SslTransport.class);
070            IntrospectionSupport.setProperties(sslTransport, options);
071        } else if (transport instanceof NIOSSLTransport) {
072            NIOSSLTransport sslTransport = (NIOSSLTransport) transport.narrow(NIOSSLTransport.class);
073            IntrospectionSupport.setProperties(sslTransport, options);
074        }
075
076        return super.compositeConfigure(transport, format, options);
077    }
078
079    /**
080     * Overriding to use SslTransports.
081     */
082    protected Transport createTransport(URI location, WireFormat wf) throws UnknownHostException, IOException {
083
084        URI localLocation = null;
085        String path = location.getPath();
086        // see if the path is a local URI location
087        if (path != null && path.length() > 0) {
088            int localPortIndex = path.indexOf(':');
089            try {
090                Integer.parseInt(path.substring(localPortIndex + 1, path.length()));
091                String localString = location.getScheme() + ":/" + path;
092                localLocation = new URI(localString);
093            } catch (Exception e) {
094                LOG.warn("path isn't a valid local location for SslTransport to use", e);
095            }
096        }
097        SocketFactory socketFactory = createSocketFactory();
098        return new SslTransport(wf, (SSLSocketFactory) socketFactory, location, localLocation, false);
099    }
100
101    /**
102     * Creates a new SSL SocketFactory. The given factory will use user-provided
103     * key and trust managers (if the user provided them).
104     *
105     * @return Newly created (Ssl)SocketFactory.
106     * @throws IOException
107     */
108    protected SocketFactory createSocketFactory() throws IOException {
109        if (SslContext.getCurrentSslContext() != null) {
110            SslContext ctx = SslContext.getCurrentSslContext();
111            try {
112                return ctx.getSSLContext().getSocketFactory();
113            } catch (Exception e) {
114                throw IOExceptionSupport.create(e);
115            }
116        } else {
117            return SSLSocketFactory.getDefault();
118        }
119
120    }
121
122}