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.Socket;
022import java.net.URI;
023import java.net.URISyntaxException;
024import java.net.UnknownHostException;
025import java.nio.ByteBuffer;
026import java.util.Map;
027
028import javax.net.ServerSocketFactory;
029import javax.net.SocketFactory;
030import javax.net.ssl.SSLContext;
031import javax.net.ssl.SSLEngine;
032import javax.net.ssl.SSLSocketFactory;
033
034import org.apache.activemq.broker.SslContext;
035import org.apache.activemq.transport.Transport;
036import org.apache.activemq.transport.TransportServer;
037import org.apache.activemq.transport.tcp.SslTransport;
038import org.apache.activemq.transport.tcp.TcpTransport;
039import org.apache.activemq.transport.tcp.TcpTransport.InitBuffer;
040import org.apache.activemq.transport.tcp.TcpTransportServer;
041import org.apache.activemq.util.IOExceptionSupport;
042import org.apache.activemq.util.IntrospectionSupport;
043import org.apache.activemq.wireformat.WireFormat;
044import org.slf4j.Logger;
045import org.slf4j.LoggerFactory;
046
047public class NIOSSLTransportFactory extends NIOTransportFactory {
048    private static final Logger LOG = LoggerFactory.getLogger(NIOSSLTransportFactory.class);
049
050    protected SSLContext context;
051
052    @Override
053    protected TcpTransportServer createTcpTransportServer(URI location, ServerSocketFactory serverSocketFactory) throws IOException, URISyntaxException {
054        return new NIOSSLTransportServer(context, this, location, serverSocketFactory);
055    }
056
057    @Override
058    public TransportServer doBind(URI location) throws IOException {
059        if (SslContext.getCurrentSslContext() != null) {
060            try {
061                context = SslContext.getCurrentSslContext().getSSLContext();
062            } catch (Exception e) {
063                throw new IOException(e);
064            }
065        }
066        return super.doBind(location);
067    }
068
069    /**
070     * Overriding to allow for proper configuration through reflection but
071     * delegate to get common configuration
072     */
073    @Override
074    public Transport compositeConfigure(Transport transport, WireFormat format, Map options) {
075        if (transport instanceof SslTransport) {
076            SslTransport sslTransport = (SslTransport) transport.narrow(SslTransport.class);
077            IntrospectionSupport.setProperties(sslTransport, options);
078        } else if (transport instanceof NIOSSLTransport) {
079            NIOSSLTransport sslTransport = (NIOSSLTransport) transport.narrow(NIOSSLTransport.class);
080            IntrospectionSupport.setProperties(sslTransport, options);
081        }
082
083        return super.compositeConfigure(transport, format, options);
084    }
085
086    /**
087     * Overriding to use SslTransports.
088     */
089    @Override
090    protected Transport createTransport(URI location, WireFormat wf) throws UnknownHostException, IOException {
091
092        URI localLocation = null;
093        String path = location.getPath();
094        // see if the path is a local URI location
095        if (path != null && path.length() > 0) {
096            int localPortIndex = path.indexOf(':');
097            try {
098                Integer.parseInt(path.substring(localPortIndex + 1, path.length()));
099                String localString = location.getScheme() + ":/" + path;
100                localLocation = new URI(localString);
101            } catch (Exception e) {
102                LOG.warn("path isn't a valid local location for SslTransport to use", e);
103            }
104        }
105        SocketFactory socketFactory = createSocketFactory();
106        return new SslTransport(wf, (SSLSocketFactory) socketFactory, location, localLocation, false);
107    }
108
109    @Override
110    public TcpTransport createTransport(WireFormat wireFormat, Socket socket,
111            SSLEngine engine, InitBuffer initBuffer, ByteBuffer inputBuffer)
112            throws IOException {
113        return new NIOSSLTransport(wireFormat, socket, engine, initBuffer, inputBuffer);
114    }
115
116    /**
117     * Creates a new SSL SocketFactory. The given factory will use user-provided
118     * key and trust managers (if the user provided them).
119     *
120     * @return Newly created (Ssl)SocketFactory.
121     * @throws IOException
122     */
123    @Override
124    protected SocketFactory createSocketFactory() throws IOException {
125        if (SslContext.getCurrentSslContext() != null) {
126            SslContext ctx = SslContext.getCurrentSslContext();
127            try {
128                return ctx.getSSLContext().getSocketFactory();
129            } catch (Exception e) {
130                throw IOExceptionSupport.create(e);
131            }
132        } else {
133            return SSLSocketFactory.getDefault();
134        }
135
136    }
137
138}