org.apache.ace.connectionfactory.impl.ConnectionFactoryImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ace.connectionfactory.impl.ConnectionFactoryImpl.java

Source

/*
 * 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.ace.connectionfactory.impl;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;

import org.apache.ace.connectionfactory.ConnectionFactory;
import org.apache.ace.connectionfactory.impl.UrlCredentials.AuthType;
import org.apache.ace.connectionfactory.impl.UrlCredentialsFactory.MissingValueException;
import org.apache.commons.codec.binary.Base64;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedServiceFactory;
import org.osgi.service.useradmin.User;

/**
 * Provides a default implementation for {@link ConnectionFactory} based on the standard <code>java.net</code>
 * implementation of {@link URLConnection}.
 */
public class ConnectionFactoryImpl implements ConnectionFactory, ManagedServiceFactory {

    public static final String FACTORY_PID = "org.apache.ace.connectionfactory";

    private static final String HTTP_HEADER_AUTHORIZATION = "Authorization";

    private final Map<String /* config PID */, UrlCredentials> m_credentialMapping;

    /**
     * Creates a new {@link ConnectionFactoryImpl}.
     */
    public ConnectionFactoryImpl() {
        m_credentialMapping = new HashMap<>();
    }

    /**
     * {@inheritDoc}
     */
    public URLConnection createConnection(URL url) throws IOException {
        if (url == null) {
            throw new IllegalArgumentException("URL cannot be null!");
        }

        URLConnection conn = url.openConnection();

        UrlCredentials creds = getCredentials(url);
        if (creds != null) {
            supplyCredentials(conn, creds);
        }

        return conn;
    }

    /**
     * {@inheritDoc}
     */
    public URLConnection createConnection(URL url, User user) throws IOException {
        if (url == null) {
            throw new IllegalArgumentException("URL cannot be null!");
        }
        if (user == null) {
            throw new IllegalArgumentException("User cannot be null!");
        }

        URLConnection conn = url.openConnection();

        UrlCredentials creds = getCredentials(url);
        if (creds != null) {
            // TODO apply user!
            supplyCredentials(conn, creds);
        }

        return conn;
    }

    /**
     * {@inheritDoc}
     */
    public void deleted(String pid) {
        synchronized (m_credentialMapping) {
            m_credentialMapping.remove(pid);
        }
    }

    /**
     * {@inheritDoc}
     */
    public String getName() {
        return "HTTP Connection Factory";
    }

    /**
     * {@inheritDoc}
     */
    public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
        UrlCredentials creds;
        synchronized (m_credentialMapping) {
            creds = m_credentialMapping.get(pid);
        }

        try {
            creds = UrlCredentialsFactory.getCredentials(properties);

            synchronized (m_credentialMapping) {
                m_credentialMapping.put(pid, creds);
            }
        } catch (MissingValueException e) {
            throw new ConfigurationException(e.getProperty(), e.getMessage());
        }
    }

    /**
     * Returns the credentials to access the given URL.
     * 
     * @param url
     *            the URL to find the credentials for, cannot be <code>null</code>.
     * @return a {@link UrlCredentials} instance for the given URL, or <code>null</code> if none were found, or if none
     *         were necessary.
     */
    final UrlCredentials getCredentials(URL url) {
        Collection<UrlCredentials> creds;
        synchronized (m_credentialMapping) {
            creds = new ArrayList<>(m_credentialMapping.values());
        }

        for (UrlCredentials c : creds) {
            if (c.matches(url)) {
                return c;
            }
        }

        return null;
    }

    /**
     * Returns the authorization header for HTTP Basic Authentication.
     * 
     * @param values
     *            the credential values to supply, cannot be <code>null</code> and should be an array of two elements.
     * @return a string that denotes the basic authentication header ("Basic " + encoded credentials), never
     *         <code>null</code>.
     */
    final String getBasicAuthCredentials(Object[] values) {
        if ((values == null) || values.length < 2) {
            throw new IllegalArgumentException("Insufficient credentials passed: expected 2 values!");
        }

        StringBuilder sb = new StringBuilder();
        if (values[0] instanceof String) {
            sb.append((String) values[0]);
        } else if (values[0] instanceof byte[]) {
            sb.append(new String((byte[]) values[0]));
        }
        sb.append(':');
        if (values[1] instanceof String) {
            sb.append((String) values[1]);
        } else if (values[1] instanceof byte[]) {
            sb.append(new String((byte[]) values[1]));
        }

        return "Basic " + new String(Base64.encodeBase64(sb.toString().getBytes()));
    }

    /**
     * Applies basic authentication to the given connection, if it is a {@link HttpURLConnection}.
     * 
     * @param conn
     *            the connection to apply basic authentication to;
     * @param values
     *            the credentials to apply.
     */
    private void applyBasicAuthentication(URLConnection conn, Object[] values) {
        if (conn instanceof HttpURLConnection) {
            conn.setRequestProperty(HTTP_HEADER_AUTHORIZATION, getBasicAuthCredentials(values));
        }
    }

    /**
     * Applies the use of client certificates to the given connection, if it a {@link HttpsURLConnection}.
     * 
     * @param conn
     *            the connection to apply client certs to;
     * @param values
     *            the credentials to apply.
     */
    private void applyClientCertificate(URLConnection conn, Object[] values) {
        if (conn instanceof HttpsURLConnection) {
            ((HttpsURLConnection) conn).setSSLSocketFactory(((SSLContext) values[0]).getSocketFactory());
        }
    }

    /**
     * Supplies the actual credentials to the given {@link URLConnection}.
     * 
     * @param conn
     *            the connection to supply the credentials to, cannot be <code>null</code>;
     * @param urlCreds
     *            the URL credentials to supply, cannot be <code>null</code>.
     * @throws IOException
     *             in case of I/O problems.
     */
    private void supplyCredentials(URLConnection conn, UrlCredentials urlCreds) throws IOException {
        final AuthType type = urlCreds.getType();
        final Object[] creds = urlCreds.getCredentials();

        if (AuthType.BASIC.equals(type)) {
            applyBasicAuthentication(conn, creds);
        } else if (AuthType.CLIENT_CERT.equals(type)) {
            applyClientCertificate(conn, creds);
        } else if (!AuthType.NONE.equals(type)) {
            throw new IllegalArgumentException("Unknown authentication type: " + type);
        }
    }
}