All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.marklogic.xcc.ContentSourceFactory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2024 MarkLogic Corporation
 *
 * 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.marklogic.xcc;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URLDecoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.marklogic.xcc.exceptions.XccConfigException;
import com.marklogic.xcc.impl.ContentSourceImpl;
import com.marklogic.xcc.impl.Credentials;
import com.marklogic.xcc.impl.SSLSocketPoolProvider;
import com.marklogic.xcc.impl.SocketPoolProvider;
import com.marklogic.xcc.spi.ConnectionProvider;

/**
 * 

* Static helper class with factory methods to create instances of {@link ContentSource} using * explicit connection parameters. *

* * @see ContentSource */ public class ContentSourceFactory { // private static final String SOCKET_PROVIDER_IMPL_PROPERTY = "com.marklogic.xcc.spi.ConnectionProvider"; // private static final String DEFAULT_CONNECTION_PROVIDER_CLASS = "com.marklogic.xcc.impl.SocketPoolProvider"; /** * Number of seconds the system sleeps before looking for expired * connections to close. */ static final long GC_INTERVAL = Integer.parseInt( System.getProperty("xcc.gcinterval", "10000")); private static final String[] knownSchemes = { "xcc", "xccs", "xdbc" }; private static final String[] secureSchemes = { "xccs" }; private ContentSourceFactory() { // cannot be instantiated } // 11.2.0 Support for OAuth private static Credentials getTokenBasedAuthCredentials(char[] authStr, String authType) { ContentSourceImpl.AuthType type = ContentSourceImpl.AuthType.valueOf(authType.toUpperCase()); switch (type) { case MLCLOUD: return new Credentials(authStr, null, null, 0); case OAUTH: return new Credentials(authStr); default: return new Credentials(); } } /** *

* Return a {@link ContentSource} object that will use the provided * {@link ConnectionProvider} instance to obtain connections to MarkLogic * Server (or the reverse proxy in front of it) using one of the token-based * authentication protocols (OAuth or MarkLogic Cloud), with the given * authentication string (OAuth JWT access token or MarkLogic Cloud api key), * contentbase and base path. Custom connection management policies may be * implemented by the {@link ConnectionProvider} object. *

*

* NOTE: This factory method should only be used by * advanced users. A misbehaving {@link ConnectionProvider} implementation * can result in connection failures and potentially even data loss. *

* * @param connectionProvider * An instance of {@link ConnectionProvider} that will be used to * obtain sockets to connect to the {@link ContentSource} when * needed. The client is responsible for properly initializing * this object with the information it needs to make the * appropriate connections. * @param authStr * JWT access token if using OAuth, apiKey if connecting to * MarkLogic Cloud. * @param authType * The token-based authentication type: use "OAUTH" for OAuth, * "MLCLOUD" for connecting to MarkLogic Cloud. * @param contentbaseName * The contentbase (database) on the {@link ContentSource} to run * queries against. The contentbase numeric id may be supplied * instead, if prepended by '#'. Pass null to use the default * configured on the server. * @param basePath * The base path configured on a reverse proxy which maps to a * MarkLogic Application Server through which operations run. * Pass null if not using reverse proxy. * @return A {@link ContentSource} instance representing the ContentSource. * @since 11.2.0 * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource( ConnectionProvider connectionProvider, char[] authStr, String authType, String contentbaseName, String basePath) { return new ContentSourceImpl(connectionProvider, getTokenBasedAuthCredentials(authStr, authType), contentbaseName, basePath); } /** * Return a {@link ContentSource} object that will serve as the source of * connections to the server (or the reverse proxy) on the given host and * port using one of the token-based authentication protocols (OAuth or * MarkLogic Cloud), with the given authentication string (OAuth JWT access * token or MarkLogic Cloud apiKey) contentbase and base path. * * @param host * The name or dotted-quad IP address of the server host or * reverse proxy. * @param port * The port on the host or reverse proxy to connect to. * @param authStr * JWT access token if using OAuth, apiKey if connecting to * MarkLogic Cloud. * @param authType * The token-based authentication type: use "OAUTH" for OAuth, * "MLCLOUD" for connecting to MarkLogic Cloud. * @param contentbaseName * The ContentBase (database) on the ContentSource to run queries * against. The contentbase numeric id may be supplied instead, * if prepended by '#'. Pass null to use the default configured * on the server. * @param basePath * The base path configured on a reverse proxy which maps to a * MarkLogic Application Server through which operations run. * Pass null if not using reverse proxy. * @param options * Security settings to be used for secure connections. Pass null * if not using secure connections. * @return A {@link ContentSource} instance representing the ContentSource. * @since 11.2.0 * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource( String host, int port, char[] authStr, String authType, String contentbaseName, String basePath, SecurityOptions options) { return newContentSource((options == null) ? defaultConnectionProvider(host, port) : defaultSecureConnectionProvider(host, port, options), authStr, authType, contentbaseName, basePath); } /** * Equivalent to * newContentSource(host, port, authStr, authType, contentbaseName, * basePath, null) * * @param host * The name or dotted-quad IP address of the reverse proxy host. * @param port * The port on the host or reverse proxy to connect to. * @param authStr * JWT access token if using OAuth, apiKey if connecting to * MarkLogic Cloud. * @param authType * The token-based authentication type: use "OAUTH" for OAuth, * "MLCLOUD" for connecting to MarkLogic Cloud. * @param contentbaseName * The ContentBase (database) on the ContentSource to run queries * against. The contentbase numeric id may be supplied instead, * if prepended by '#'. Pass null to use the default configured * on the server. * @param basePath * The base path configured on a reverse proxy which maps to a * MarkLogic Application Server through which operations run. * Pass null if not using reverse proxy. * @return A {@link ContentSource} instance representing the ContentSource. * The configured {@link ContentSource} implementation class cannot * be instantiated. * @since 11.2.0 * @see com.marklogic.xcc.ContentSource */ public static ContentSource newContentSource( String host, int port, char[] authStr, String authType, String contentbaseName, String basePath) { return newContentSource(host, port, authStr, authType, contentbaseName, basePath, null); } /** * Equivalent to * newContentSource(host, port, authStr, authType, contentbaseName, * null, null) * * @param host * The name or dotted-quad IP address of the reverse proxy host. * @param port * TThe port on the host or reverse proxy to connect to. * @param authStr * JWT access token if using OAuth, apiKey if connecting to * MarkLogic Cloud. * @param authType * The token-based authentication type: use "OAUTH" for OAuth, * "MLCLOUD" for connecting to MarkLogic Cloud. * @param contentbaseName * The ContentBase (database) on the ContentSource to run queries * against. The contentbase numeric id may be supplied instead, * if prepended by '#'. Pass null to use the default configured * on the server. * @return A {@link ContentSource} instance representing the ContentSource. * The configured {@link ContentSource} implementation class cannot * be instantiated. * @since 11.2.0 * @see com.marklogic.xcc.ContentSource */ public static ContentSource newContentSource( String host, int port, char[] authStr, String authType, String contentbaseName) { return newContentSource(host, port, authStr, authType, contentbaseName, null, null); } /** * Equivalent to * newContentSource(host, port, authStr, authType, null, null, null) * * * @param host * The name or dotted-quad IP address of the reverse proxy host. * @param port * The port on the host or reverse proxy to connect to. * @param authStr * JWT access token if using OAuth, apiKey if connecting to * MarkLogic Cloud. * @param authType * The token-based authentication type: use "OAUTH" for OAuth, * "MLCLOUD" for connecting to MarkLogic Cloud. * @return A {@link ContentSource} instance representing the ContentSource. * The configured {@link ContentSource} implementation class cannot * be instantiated. * @since 11.2.0 * @see com.marklogic.xcc.ContentSource */ public static ContentSource newContentSource( String host, int port, char[] authStr, String authType) { return newContentSource(host, port, authStr, authType, null, null, null); } // --------------------------------------------------------------- // 11.1.0 Support for base path /** *

* Return a {@link ContentSource} object that will use the provided * {@link ConnectionProvider} instance to obtain connections to the reverse * proxy, and to the server behind the reverse proxy, with the given default * login credentials, contentbase and base path values. Custom connection * management policies may be implemented by the {@link ConnectionProvider} * object. *

*

* NOTE: This factory method should only be used by * advanced users. A misbehaving {@link ConnectionProvider} implementation * can result in connection failures and potentially even data loss. *

* * @param connectionProvider * An instance of {@link ConnectionProvider} that will be used to * obtain sockets to connect to the {@link ContentSource} when * needed. The client is responsible for properly initializing * this object with the information it needs to make the * appropriate connections. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The contentbase (database) on the {@link ContentSource} to run * queries against. The contentbase numeric id may be supplied * instead, if prepended by '#'. Pass null to use the default * configured on the server. * @param basePath * The base path configured on a reverse proxy which maps to a * MarkLogic Application Server through which operations run. * @return A {@link ContentSource} instance representing the ContentSource. * @since 11.1.0 * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource( ConnectionProvider connectionProvider, String user, char[] password, String contentbaseName, String basePath) { return (new ContentSourceImpl(connectionProvider, user, password, contentbaseName, basePath)); } /** * Return a {@link ContentSource} object that will serve as the source of * connections to the reverse proxy on the given proxy host and proxy port, * and the server behind the reverse proxy, with login credentials of the * given user and password, contentbase name and base path. No * connections are made at this time. * * @param host * The name or dotted-quad IP address of the reverse proxy host. * @param port * The reverse proxy port to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The ContentBase (database) on the ContentSource to run queries * against. The contentbase numeric id may be supplied instead, * if prepended by '#'. Pass null to use the default configured * on the server. * @param basePath * The base path configured on a reverse proxy which maps to a * MarkLogic Application Server through which operations run. * @param options * Security settings to be used for secure connections. * @return A {@link ContentSource} instance representing the ContentSource. * @since 11.1.0 * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource( String host, int port, String user, char[] password, String contentbaseName, String basePath, SecurityOptions options) { return (newContentSource((options == null) ? defaultConnectionProvider(host, port) : defaultSecureConnectionProvider(host, port, options), user, password, contentbaseName, basePath)); } /** * Equivalent to * newContentSource (host, port, user, password, contentbaseName, * basePath, null) * * @param host * The name or dotted-quad IP address of the reverse proxy host. * @param port * The reverse proxy port to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The ContentBase (database) on the ContentSource to run. * @param basePath * The base path configured on a reverse proxy which maps to a * MarkLogic Application Server through which operations run. * @return A {@link ContentSource} instance representing the ContentSource. * The configured {@link ContentSource} implementation class cannot * be instantiated. * @since 11.1.0 * @see com.marklogic.xcc.ContentSource */ public static ContentSource newContentSource( String host, int port, String user, char[] password, String contentbaseName, String basePath) { return newContentSource( host, port, user, password, contentbaseName, basePath, null); } // --------------------------------------------------------------- // 11.1.0 Support connecting to ML Cloud // Hidden private static ContentSource newContentSource( ConnectionProvider connectionProvider, char[] apiKey, String contentbaseName, String basePath, String tokenEndpoint, String grantType, int tokenDuration) { return (new ContentSourceImpl(connectionProvider, apiKey, contentbaseName, basePath, tokenEndpoint, grantType, tokenDuration)); } /** *

* Return a {@link ContentSource} object that will use the provided * {@link ConnectionProvider} instance to obtain connections to MarkLogic * Cloud, with the given user api key, contentbase and base path. Custom * connection management policies may be implemented by the * {@link ConnectionProvider} object. *

*

* NOTE: This factory method should only be used by * advanced users. A misbehaving {@link ConnectionProvider} implementation * can result in connection failures and potentially even data loss. *

* * @param connectionProvider * An instance of {@link ConnectionProvider} that will be used to * obtain sockets to connect to the {@link ContentSource} when * needed. The client is responsible for properly initializing * this object with the information it needs to make the * appropriate connections. * @param apiKey * The unique key assigned to a MarkLogic Cloud user. * @param contentbaseName * The contentbase (database) on the {@link ContentSource} to run * queries against. The contentbase numeric id may be supplied * instead, if prepended by '#'. Pass null to use the default * configured on the server. * @param basePath * The base path configured on MarkLogic Cloud which maps to a * service hosted by MarkLogic Cloud through which operations * run. * @return A {@link ContentSource} instance representing the ContentSource. * @since 11.1.0 * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource( ConnectionProvider connectionProvider, char[] apiKey, String contentbaseName, String basePath) { return newContentSource(connectionProvider, apiKey, contentbaseName, basePath, null, null, 0); } // Hidden private static ContentSource newContentSource( String host, int port, char[] apiKey, String contentbaseName, String basePath, String tokenEndpoint, String grantType, int tokenDuration, SecurityOptions options) { return (newContentSource((options == null) ? defaultConnectionProvider(host, port) : defaultSecureConnectionProvider(host, port, options), apiKey, contentbaseName, basePath, tokenEndpoint, grantType, tokenDuration)); } /** * Return a {@link ContentSource} object that will serve as the source of * connections to MarkLogic Cloud on the given cloud tenancy URL and port * (by default the user should use 443), with the given user api key, * contentbase name and base path. No connections are made at this time. * The base path is mapped to a specific service hosted by MarkLogic Cloud. * * @param host * The name or dotted-quad IP address of the MarkLogic Cloud * Tenancy. * @param port * The MarkLogic Cloud port to connect to (by default the user * should use 443). * @param apiKey * The unique key assigned to a MarkLogic Cloud user. * @param contentbaseName * The ContentBase (database) on the ContentSource to run queries * against. The contentbase numeric id may be supplied instead, * if prepended by '#'. Pass null to use the default configured * on the server. * @param basePath * The base path configured on MarkLogic Cloud which maps to a * service hosted by MarkLogic Cloud through which operations * run. * @param options * Security settings to be used for secure connections. * @return A {@link ContentSource} instance representing the ContentSource. * @since 11.1.0 * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource( String host, int port, char[] apiKey, String contentbaseName, String basePath, SecurityOptions options) { return (newContentSource(host, port, apiKey, contentbaseName, basePath, null, null, 0, options)); } // Hidden /** *

* NOTE: Not meant for public use *

*/ public static ContentSource newContentSource( String host, int port, Credentials credentials, String contentbaseName, String basePath) { return newContentSource(host, port, credentials, contentbaseName, basePath, null); } // Hidden /** *

* NOTE: Not meant for public use *

*/ public static ContentSource newContentSource( String host, int port, Credentials credentials, String contentbaseName, String basePath, SecurityOptions options) { return new ContentSourceImpl((options == null) ? defaultConnectionProvider(host, port) : defaultSecureConnectionProvider(host, port, options), credentials, contentbaseName, basePath); } // --------------------------------------------------------------- /** *

* Return a {@link ContentSource} object that will use the provided {@link ConnectionProvider} * instance to obtain server connections, with the given default login credentials and * contentbase values. Custom connection management policies may be implemented by the * {@link ConnectionProvider} object. *

*

* NOTE: This factory method should only be used by advanced users. A * misbehaving {@link ConnectionProvider} implementation can result in connection failures and * potentially even data loss. *

* * @param connectionProvider * An instance of {@link ConnectionProvider} that will be used to obtain sockets to * connect to the {@link ContentSource} when needed. The client is responsible for * properly initializing this object with the information it needs to make the * appropriate connections. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The contentbase (database) on the {@link ContentSource} to run queries against. * The contentbase numeric id may be supplied instead, if prepended by '#'. Pass null * to use the default configured on the server. * @return A {@link ContentSource} instance representing the ContentSource. * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData * @deprecated */ @Deprecated public static ContentSource newContentSource( ConnectionProvider connectionProvider, String user, String password, String contentbaseName) { return (new ContentSourceImpl(connectionProvider, user, password == null ? null : password.toCharArray(), contentbaseName)); } /** *

* Return a {@link ContentSource} object that will use the provided {@link ConnectionProvider} * instance to obtain server connections, with the given default login credentials and * contentbase values. Custom connection management policies may be implemented by the * {@link ConnectionProvider} object. *

*

* NOTE: This factory method should only be used by advanced users. A * misbehaving {@link ConnectionProvider} implementation can result in connection failures and * potentially even data loss. *

* * @param connectionProvider * An instance of {@link ConnectionProvider} that will be used to obtain sockets to * connect to the {@link ContentSource} when needed. The client is responsible for * properly initializing this object with the information it needs to make the * appropriate connections. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The contentbase (database) on the {@link ContentSource} to run queries against. * The contentbase numeric id may be supplied instead, if prepended by '#'. Pass null * to use the default configured on the server. * @return A {@link ContentSource} instance representing the ContentSource. * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource( ConnectionProvider connectionProvider, String user, char[] password, String contentbaseName) { return (new ContentSourceImpl(connectionProvider, user, password, contentbaseName)); } // --------------------------------------------------------------- /** *

* Return a {@link ContentSource} object that will serve as the source of connections to the * server specified by the given URI. *

*

* The format of the URI is: xcc://user:password@host:port/contentbase. * For an SSL-enabled connection, the URI format is: * xccs://user:password@host:port[/contentbase]. * For example: xcc://joe:hush@myserver:8003, * xccs://joe:hush@myserver:8003/production. *

*

* From 11.1.0, to specify base path through the URI, the format is: * xcc://user:password@host:port[/contentbase]?basepath. * For example: * xcc://joe:[email protected]:8080/Documents?basepath=%2Fml%2Ftest%2Fmarklogic%2Fmlcp. * NOTE: Base path should be URL encoded. *

*

* From 11.1.0, to construct ContentSource that connects to MarkLogic Cloud, the format * is: xccs://host:port[/contentbase]?basepath&apikey. * For example: * xccs://cloud.marklogic.com:443/Documents?basepath=%2Fml%2Ftest%2Fmarklogic%2Fmlcp&apikey=XZvPaq%2B3HihncigeegZyA%3D%3D. * NOTE: To connect to MarkLogic Cloud, an SSL-enabled * connection (scheme xccs) should be used. Base path and api key should be URL encoded. *

*

* From 11.2.0, to construct ContentSource that uses OAuth to connect to * MarkLogic Server, the format is: * xcc://host:port[/contentbase]?oauthtoken. * NOTE: OAuth token should be URL encoded. *

*

* The contentbase name is optional. If not specified the default database * for the XDBC server configuration will be used. To reference a contentbase * by numeric id (see {@link ContentbaseMetaData#getContentBaseId()}), * prepend it with '#'. * For example: xcc://joe:hush@myserver:8003/#84635406972362574. *

*

* The supported connection schemes are currently "xcc" ("xdbc" is an alias) * for a non-secure connection and "xccs" for a secure connection, but * others may be added in the future. *

* * @param uri * A URI instance which encodes the connection scheme, host, port and optional user * and password. * @param options * Security settings to be used for "xccs" secure connections. * @return A {@link ContentSource} instance representing the ContentSource. * @throws XccConfigException * If there is a configuration problem or the configured {@link ContentSource} * implementation class cannot be instantiated. * @see ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource(URI uri, SecurityOptions options) throws XccConfigException { String scheme = uri.getScheme(); String host = uri.getHost(); int port = uri.getPort(); String userInfoStr = uri.getUserInfo(); String contentBase = uri.getPath(); // For basePath, apiKey, tokenEndpoint, grantType and OAuthToken String query = uri.getQuery(); if (!validScheme(scheme)) { throw new XccConfigException("Unrecognized connection scheme: " + scheme); } if ((!secureScheme(scheme)) && (options != null)) { throw new XccConfigException("Non-Secure connection requested but SecurityOptions is non-null"); } if (contentBase != null) { if (contentBase.startsWith("/")) { contentBase = contentBase.substring(1); } if (contentBase.length() == 0) { // in the case where a numeric is sent contentBase = uri.getFragment(); if (contentBase != null) { contentBase = "#" + contentBase; } } } return buildContentSourceFromURI(query, userInfoStr, host, port, contentBase, options); } /** * Equivalent to newContentSource(uri, null). * * @param uri * A URI instance which encodes the connection scheme, host, port and optional user * and password. The format of the URI is: * xcc://user:password@host:port/contentbase * @return A {@link ContentSource} instance representing the ContentSource. * @throws XccConfigException * If there is a configuration problem or the configured {@link ContentSource} * implementation class cannot be instantiated. */ public static ContentSource newContentSource(URI uri) throws XccConfigException { return newContentSource(uri, null); } // --------------------------------------------------------------- /** * Return a {@link ContentSource} object that will serve as the source of connections to the * server on the given host and port, with login credentials of the given user and password. No * connections are made at this time. Note that the {@link ContentSource} instance returned may * be shared with other callers or threads. The implementation may choose to pool and re-use * {@link ContentSource} objects for a particular host/port/user combination. * * @param host * The name or dotted-quad IP address of the server host. * @param port * The port on the host to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The ContentBase (database) on the ContentSource to run queries against. The * contentbase numeric id may be supplied instead, if prepended by '#'. Pass null to * use the default configured on the server. * @param options * Security settings to be used for secure connections. * @return A {@link ContentSource} instance representing the ContentSource. * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData * @deprecated */ @Deprecated public static ContentSource newContentSource(String host, int port, String user, String password, String contentbaseName, SecurityOptions options) { return (newContentSource((options == null) ? defaultConnectionProvider(host, port) : defaultSecureConnectionProvider(host, port, options), user, password, contentbaseName)); } /** * Return a {@link ContentSource} object that will serve as the source of connections to the * server on the given host and port, with login credentials of the given user and password. No * connections are made at this time. Note that the {@link ContentSource} instance returned may * be shared with other callers or threads. The implementation may choose to pool and re-use * {@link ContentSource} objects for a particular host/port/user combination. * * @param host * The name or dotted-quad IP address of the server host. * @param port * The port on the host to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The ContentBase (database) on the ContentSource to run queries against. The * contentbase numeric id may be supplied instead, if prepended by '#'. Pass null to * use the default configured on the server. * @param options * Security settings to be used for secure connections. * @return A {@link ContentSource} instance representing the ContentSource. * @see com.marklogic.xcc.ContentSource * @see ContentbaseMetaData */ public static ContentSource newContentSource(String host, int port, String user, char[] password, String contentbaseName, SecurityOptions options) { return (newContentSource((options == null) ? defaultConnectionProvider(host, port) : defaultSecureConnectionProvider(host, port, options), user, password, contentbaseName)); } /** * Equivalent to * newContentSource (host, port, user, password, contentbaseName, null) * * @param host * The name or dotted-quad IP address of the server host. * @param port * The port on the host to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The ContentBase (database) on the ContentSource to run * @return A {@link ContentSource} instance representing the ContentSource. the configured * {@link ContentSource} implementation class cannot be instantiated. * @see com.marklogic.xcc.ContentSource * @deprecated */ @Deprecated public static ContentSource newContentSource(String host, int port, String user, String password, String contentbaseName) { return (newContentSource(host, port, user, password, contentbaseName, null)); } /** * Equivalent to * newContentSource (host, port, user, password, contentbaseName, * null, null) * * @param host * The name or dotted-quad IP address of the server host. * @param port * The port on the host to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @param contentbaseName * The ContentBase (database) on the ContentSource to run * @return A {@link ContentSource} instance representing the ContentSource. the configured * {@link ContentSource} implementation class cannot be instantiated. * @see com.marklogic.xcc.ContentSource */ public static ContentSource newContentSource(String host, int port, String user, char[] password, String contentbaseName) { return newContentSource( host, port, user, password, contentbaseName, null, null); } /** * Equivalent to newContentSource (host, port, user, password, null) * * @param host * The name or dotted-quad IP address of the server host. * @param port * The port on the host to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @return A {@link ContentSource} instance representing the ContentSource. the configured * {@link ContentSource} implementation class cannot be instantiated. * @see com.marklogic.xcc.ContentSource * @deprecated */ @Deprecated public static ContentSource newContentSource(String host, int port, String user, String password) { return (newContentSource(host, port, user, password, null)); } /** * Equivalent to newContentSource (host, port, user, password, null) * * @param host * The name or dotted-quad IP address of the server host. * @param port * The port on the host to connect to. * @param user * The default User Name to use for authentication. * @param password * The default Password to use for authentication. * @return A {@link ContentSource} instance representing the ContentSource. the configured * {@link ContentSource} implementation class cannot be instantiated. * @see com.marklogic.xcc.ContentSource */ public static ContentSource newContentSource(String host, int port, String user, char[] password) { return (newContentSource(host, port, user, password, null)); } /** * Return a ContentSource object that will serve as the source of connections to the server on * the given host and port, with no default login credentials. Invoking newSession() on the * returned ContentSource object, without providing a user name/password, will throw an * IllegalStateException. * * @param host * The name or dotted-quad IP address of the server host. * @param port * The port on the host to connect to. * @return A ContentSource instance representing the ContentSource. * @see ContentSource */ public static ContentSource newContentSource(String host, int port) { return newContentSource(host, port, null, (char[])null, null); } // ---------------------------------------------------------------- // private static ContentSource instantiateContentSource (Class clazz, // ConnectionProvider socketProvider, String user, String password, String contentBase) // throws XDBCConfigException // { // Class [] paramTypes = { ConnectionProvider.class, String.class, String.class, String.class }; // Object [] params = { socketProvider, user, password, contentBase }; // Constructor constructor = null; // // try { // constructor = clazz.getConstructor (paramTypes); // } catch (NoSuchMethodException e) { // throw new XDBCConfigException ("Class '" + clazz.getName() // + "', does not have a four-arg constructor", e); // } // // try { // return (ContentSource) constructor.newInstance (params); // } catch (Exception e) { // throw new XDBCConfigException ("Cannot instantiate '" + clazz.getName() // + "': " + e.getMessage (), e); // } // } private static final int STANDARD_PROVIDER_CACHE_SIZE = Integer.getInteger( "xcc.connectionprovider.standard.cache.size", 8); private static final int SECURE_PROVIDER_CACHE_SIZE = Integer.getInteger( "xcc.connectionprovider.secure.cache.size", 8); private static final Map standardProviders = new ConcurrentHashMap(STANDARD_PROVIDER_CACHE_SIZE); private static final Map secureProviders = new ConcurrentHashMap(SECURE_PROVIDER_CACHE_SIZE); private static final ConnectionCollector gc = new ConnectionCollector(); static ConnectionProvider defaultConnectionProvider(String host, int port) { // try { // implClass = findClass (SOCKET_PROVIDER_IMPL_PROPERTY, DEFAULT_SOCKET_PROVIDER_CLASS); // } catch (ClassNotFoundException e) { // throw new XDBCConfigException ("ConnectionProvider configuration error, cannot load class: " + implName, e); // } // TODO: Look for property override setting? // return (new SocketPoolProvider (new InetSocketAddress (host, port))); InetSocketAddress address = new InetSocketAddress(host, port); if (address.isUnresolved()) { throw new IllegalArgumentException("Default provider - Not a usable net address: " + address); } ConnectionProvider provider = standardProviders.get(address); if (provider == null) { provider = new SocketPoolProvider(address); standardProviders.put(address, provider); } gc.checkAlive(); return (provider); } private static ConnectionProvider defaultSecureConnectionProvider(String host, int port, SecurityOptions options) { final InetSocketAddress address = new InetSocketAddress(host, port); if (address.isUnresolved()) { throw new IllegalArgumentException("Default secure provider - Not a usable net address: " + address); } final SecurityOptions securityOptions = new SecurityOptions(options); class Key { public InetSocketAddress getAddress() { return address; } public SecurityOptions getSecurityOptions() { return securityOptions; } @Override public int hashCode() { return address.hashCode() + securityOptions.hashCode(); } @Override public boolean equals(Object o) { if (o instanceof Key) { Key k = (Key)o; return (this == k) || (address.equals(k.getAddress()) && securityOptions.equals(k.getSecurityOptions())); } else { return false; } } } Key key = new Key(); ConnectionProvider provider = secureProviders.get(key); if (provider == null) { try { provider = new SSLSocketPoolProvider(address, securityOptions); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); // FIXME: auto-generated } catch (KeyManagementException e) { e.printStackTrace(); // FIXME: auto-generated } secureProviders.put(key, provider); } gc.checkAlive(); return (provider); } // ---------------------------------------------------------------- private static boolean validScheme(String scheme) { if (scheme == null) return false; for (int i = 0; i < knownSchemes.length; i++) { if (scheme.equalsIgnoreCase(knownSchemes[i])) { return true; } } return false; } private static boolean secureScheme(String scheme) { if (scheme == null) return false; for (int i = 0; i < secureSchemes.length; i++) { if (scheme.equalsIgnoreCase(secureSchemes[i])) { return true; } } return false; } /** URI format: * For general reverse proxy * xccs://username:password@host:port[/contentbase]?basepath * * For MarkLogic Cloud instances * xccs://host:port[/contentbase]?basepath&apikey * xccs://host:port[/contentbase]?basePath&apikey&tokenendpoint&granttype&tokenduration * * For OAuth * xccs://host:port[/contentbase]?basepath&oauthtoken */ private static ContentSource buildContentSourceFromURI(String query, String userInfoStr, String host, int port, String contentBase, SecurityOptions options) throws XccConfigException { // Parse query string Map queryPairs = new LinkedHashMap<>(); if (query != null) { try { String[] pairs = query.split("&"); for (String pair : pairs) { int i = pair.indexOf("="); queryPairs.put( URLDecoder.decode(pair.substring(0, i), "UTF-8"), URLDecoder.decode(pair.substring(i + 1), "UTF-8")); } } catch(UnsupportedEncodingException e) { throw new XccConfigException("Unsupported encoding in xcc URI.", e); } } // Parse user info String[] userInfo; if (userInfoStr != null) { userInfo = userInfoStr.split(":", 2); } else { userInfo = new String[0]; } String basePath = queryPairs.isEmpty()? null : queryPairs.get("basepath"); char[] apiKey = queryPairs.isEmpty()? null : (queryPairs.get("apikey") == null ? null : queryPairs.get("apikey").toCharArray()); String tokenEndpoint = queryPairs.isEmpty()? null : queryPairs.get("tokenendpoint"); String grantType = queryPairs.isEmpty()? null : queryPairs.get("granttype"); String tokenDuration = queryPairs.isEmpty()? null : queryPairs.get("tokenduration"); char[] OAuthToken = queryPairs.isEmpty()? null : (queryPairs.get("oauthtoken") == null ? null : queryPairs.get("oauthtoken").toCharArray()); Credentials credentials; if (apiKey != null) { // Use mlcloud auth if (basePath == null) throw new XccConfigException( "Base path cannot be empty."); credentials = new Credentials(apiKey, tokenEndpoint, grantType, (tokenDuration == null) ? 0 : Integer.parseInt(tokenDuration)); } else if (OAuthToken != null) { // Use OAuth credentials = new Credentials(OAuthToken); } else { if ((userInfo.length!=2) || (userInfo[0].length() == 0) || (userInfo[1].length() == 0)) { credentials = new Credentials(null, null); } else { credentials = new Credentials(userInfo[0], userInfo[1]. toCharArray()); } } return newContentSource(host, port, credentials, contentBase, basePath, options); } // private static Class findClass (String property, String defaultName) // throws ClassNotFoundException // { // String implName = System.getProperty (property); // // if (implName == null) { // implName = defaultName; // } // // return (Class.forName (implName)); // } /** * Wakes up periodically to close expired connections. */ static class ConnectionCollector extends Thread { @Override public void run() { while (true) { try { Thread.sleep(GC_INTERVAL); } catch (InterruptedException e) { } long currTime = System.currentTimeMillis(); for (ConnectionProvider pool : standardProviders.values()) { pool.closeExpired(currTime); } for (ConnectionProvider pool : secureProviders.values()) { pool.closeExpired(currTime); } } } synchronized public void checkAlive() { if (!isAlive()) { setDaemon(true); try { setPriority(Thread.MIN_PRIORITY); } catch (SecurityException e) {} start(); } } } }