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

com.marklogic.client.DatabaseClientFactory Maven / Gradle / Ivy

/*
 * Copyright 2012-2015 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.client;

import java.io.Serializable;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.marklogic.client.extra.httpclient.HttpClientConfigurator;
import com.marklogic.client.impl.DatabaseClientImpl;
import com.marklogic.client.impl.HandleFactoryRegistryImpl;
import com.marklogic.client.impl.JerseyServices;
import com.marklogic.client.io.marker.ContentHandle;
import com.marklogic.client.io.marker.ContentHandleFactory;

/**
 * A Database Client Factory configures a database client for making
 * database requests.
 */
public class DatabaseClientFactory {
	static final private Logger logger = LoggerFactory.getLogger(DatabaseClientFactory.class);

	static private ClientConfigurator clientConfigurator;
	static private HandleFactoryRegistry handleRegistry =
		HandleFactoryRegistryImpl.newDefault();

	/**
	 * Authentication enumerates the methods for verifying a user and
	 * password with the database.
	 */
	public enum Authentication {
	    /**
	     * Minimal security unless used with SSL.
	     */
		BASIC,
		/**
		 * Moderate security without SSL.
		 */
		DIGEST;

		/**
		 * Returns the enumerated value for the case-insensitive name.
		 * @param name	the name of the enumerated value
		 * @return	the enumerated value
		 */
		static public Authentication valueOfUncased(String name) {
			return Authentication.valueOf(name.toUpperCase());
		}
	}

	/**
	 * An SSLHostnameVerifier checks whether a hostname is acceptable
	 * during SSL authentication.
	 */
	public interface SSLHostnameVerifier {
		/**
		 * The ANY SSLHostnameVerifier allows any hostname, which
		 * can be useful during initial development but is not
		 * recommended for production.
		 */
		final static public Builtin ANY    = new Builtin("ANY");
		/**
		 * The COMMON SSLHostnameVerifier applies common rules
		 * for checking hostnames during SSL authentication (similar
		 * to org.apache.http.conn.ssl.BrowserCompatHostnameVerifier).
		 */
		final static public Builtin COMMON = new Builtin("COMMON");
		/**
		 * The STRICT SSLHostnameVerifier applies strict rules
		 * for checking hostnames during SSL authentication (similar
		 * to org.apache.http.conn.ssl.StrictHostnameVerifier).
		 */
		final static public Builtin STRICT = new Builtin("STRICT");

		/**
		 * Checks a hostname during SSL authentication.
		 * @param hostname	the name of the checked host
		 * @param cns	common names for the checked host
		 * @param subjectAlts	alternative subject names for the checked host
		 */
		public void verify(String hostname, String[] cns, String[] subjectAlts) throws SSLException;

		/**
		 * Builtin supports builtin implementations of SSLHostnameVerifier.
		 */
		public class Builtin implements SSLHostnameVerifier {
			private String name;
			private Builtin(String name) {
				super();
				this.name = name;
			}
			@Override
			public void verify(String hostname, String[] cns, String[] subjectAlts) throws SSLException {
				throw new MarkLogicInternalException(
						"SSLHostnameVerifier.Builtin called directly instead of passed as parameter");
			}
			/**
			 * Returns the name of the built-in.
			 * @return	the built-in name
			 */
			public String getName() {
				return name;
			}
		}
	}

	/**
	 * A HandleFactoryRegistry associates IO representation classes
	 * with handle factories. The API uses the registry to create 
	 * a content handle to act as an adapter for a supported
	 * IO representation class.  The IO class and its instances can
	 * then be passed directly to convenience methods.
	 * The default registry associates the content handles provided 
	 * by the API and the supported IO representation classes.
	 * Create instances of this interface only if you need to modify
	 * the default registry.
	 * @see DatabaseClientFactory#getHandleRegistry()
	 * @see DatabaseClientFactory.Bean#getHandleRegistry()
	 */
	public interface HandleFactoryRegistry {
		/**
		 * Associates a factory for content handles with the classes
		 * for IO representations known to the factory.
		 * @param factory	a factory for creating content handle instances
		 */
		public void register(ContentHandleFactory factory);
		/**
		 * Associates a factory for content handles with the specified classes
		 * for IO representations.
		 * @param factory	a factory for creating content handle instances
		 * @param ioClasses	the IO classes for which the factory should create handles
		 */
		public void register(ContentHandleFactory factory, Class... ioClasses);
		/**
		 * Returns whether the registry associates the class with a factory.
		 * @param ioClass	the class for an IO representation
		 * @return	true if a factory has been registered
		 */
		public boolean isRegistered(Class ioClass);
		/**
		 * Returns the classes for the IO representations for which a factory
		 * has been registered.
		 * @return	the IO classes
		 */
		public Set> listRegistered();
		/**
		 * Creates a ContentHandle if the registry has a factory
		 * for the class of the IO representation.
		 * @param type	the class for an IO representation
		 * @return	a content handle or null if no factory supports the class
		 */
		public  ContentHandle makeHandle(Class type);
		/**
		 * Removes the classes from the registry
		 * @param ioClasses	one or more registered classes for an IO representation
		 */
		public void unregister(Class... ioClasses);
		/**
		 * Create a copy of the current registry
		 * @return	a copy of the current registry
		 */
		public HandleFactoryRegistry copy();
	}

	/**
	 * A ClientConfigurator provides custom configuration for the communication library
	 * used to sending client requests and receiving server responses.
	 * @see com.marklogic.client.extra.httpclient.HttpClientConfigurator
	 * @param 	the configurable class for the communication library
	 */
	public interface ClientConfigurator {
		/**
		 * Called as the last step in configuring the communication library.
		 * @param client	the configurable object for the communication library
		 */
		public void configure(T client);
	}

	private DatabaseClientFactory() {
	}

	/**
	 * Creates a client to access the database by means of a REST server
	 * without any authentication. Such clients can be convenient for
	 * experimentation but should not be used in production. 
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port) {
		return newClient(host, port, null, null, null, null, null, null);
	}

	/**
	 * Creates a client to access the database by means of a REST server
	 * without any authentication. Such clients can be convenient for
	 * experimentation but should not be used in production. 
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @param database	the database to access (default: configured database for the REST server)
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port, String database) {
		return newClient(host, port, database, null, null, null, null, null);
	}

	/**
	 * Creates a client to access the database by means of a REST server.
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @param user	the user with read, write, or administrative privileges
	 * @param password	the password for the user
	 * @param type	the type of authentication applied to the request
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port, String user, String password, Authentication type) {
		return newClient(host, port, null, user, password, type, null, null);
	}
	/**
	 * Creates a client to access the database by means of a REST server.
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @param database	the database to access (default: configured database for the REST server)
	 * @param user	the user with read, write, or administrative privileges
	 * @param password	the password for the user
	 * @param type	the type of authentication applied to the request
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port, String database, String user, String password, Authentication type) {
		return newClient(host, port, database, user, password, type, null, null);
	}
	/**
	 * Creates a client to access the database by means of a REST server.
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @param user	the user with read, write, or administrative privileges
	 * @param password	the password for the user
	 * @param type	the type of authentication applied to the request
	 * @param context	the SSL context for authenticating with the server
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port, String user, String password, Authentication type, SSLContext context) {
		return newClient(host, port, null, user, password, type, context, SSLHostnameVerifier.COMMON);
	}
	/**
	 * Creates a client to access the database by means of a REST server.
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @param database	the database to access (default: configured database for the REST server)
	 * @param user	the user with read, write, or administrative privileges
	 * @param password	the password for the user
	 * @param type	the type of authentication applied to the request
	 * @param context	the SSL context for authenticating with the server
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port, String database, String user, String password, Authentication type, SSLContext context) {
		return newClient(host, port, database, user, password, type, context, SSLHostnameVerifier.COMMON);
	}
	/**
	 * Creates a client to access the database by means of a REST server.
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @param user	the user with read, write, or administrative privileges
	 * @param password	the password for the user
	 * @param type	the type of authentication applied to the request
	 * @param context	the SSL context for authenticating with the server
	 * @param verifier	a callback for checking hostnames
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port, String user, String password, Authentication type, SSLContext context, SSLHostnameVerifier verifier) {
		DatabaseClientImpl client = newClientImpl(host, port, null, user, password, type, context, verifier);
		client.setHandleRegistry(getHandleRegistry().copy());
		return client;
	}
	/**
	 * Creates a client to access the database by means of a REST server.
	 * 
	 * @param host	the host with the REST server
	 * @param port	the port for the REST server
	 * @param database	the database to access (default: configured database for the REST server)
	 * @param user	the user with read, write, or administrative privileges
	 * @param password	the password for the user
	 * @param type	the type of authentication applied to the request
	 * @param context	the SSL context for authenticating with the server
	 * @param verifier	a callback for checking hostnames
	 * @return	a new client for making database requests
	 */
	static public DatabaseClient newClient(String host, int port, String database, String user, String password, Authentication type, SSLContext context, SSLHostnameVerifier verifier) {
		DatabaseClientImpl client = newClientImpl(host, port, database, user, password, type, context, verifier);
		client.setHandleRegistry(getHandleRegistry().copy());
		return client;
	}
	static private DatabaseClientImpl newClientImpl(String host, int port, String database, String user, String password, Authentication type, SSLContext context, SSLHostnameVerifier verifier) {
		logger.debug("Creating new database client for server at "+host+":"+port);
		JerseyServices services = new JerseyServices();
		services.connect(host, port, database, user, password, type, context, verifier);

		if (clientConfigurator != null) {
			((HttpClientConfigurator) clientConfigurator).configure(
				services.getClientImplementation()
				);
		}

		return new DatabaseClientImpl(services);		
	}

	/**
	 * Returns the default registry with factories for creating handles
	 * as adapters for IO representations. To create custom registries,
	 * use 
	 * @return	the default registry
	 */
	static public HandleFactoryRegistry getHandleRegistry() {
		return handleRegistry;
	}
	/**
	 * Removes the current registered associations so the
	 * handle registry is empty.
	 */
	static public void clearHandleRegistry() {
		handleRegistry = new HandleFactoryRegistryImpl();
	}
	/**
	 * Initializes a handle registry with the default associations
	 * between the content handles provided by the API and the supported
	 * IO representation classes.  Use this method only after clearing
	 * or overwriting associations in the handle registry.
	 */
	static public void registerDefaultHandles() {
		HandleFactoryRegistryImpl.registerDefaults(getHandleRegistry());
	}

	/**
	 * Adds a listener that provides custom configuration when a communication library
	 * is created.
	 * @see com.marklogic.client.extra.httpclient.HttpClientConfigurator
	 * @param configurator	the listener for configuring the communication library
	 */
	static public void addConfigurator(ClientConfigurator configurator) {
		if (!HttpClientConfigurator.class.isInstance(configurator)) {
			throw new IllegalArgumentException(
					"Configurator must implement HttpClientConfigurator"
					);
		}

		clientConfigurator = configurator;
	}

	/**
	 * A Database Client Factory Bean provides an object for specifying configuration
	 * before creating a client to make database requests.
	 * 
	 * 

For instance, a Spring configuration file might resemble the following * example:

*
	 * <bean name="databaseClientFactory"
	 * 	   class="com.marklogic.client.DatabaseClientFactory.Bean">
	 *   <property name="host"                value="localhost"/>
	 *   <property name="port"                value="8012"/>
	 *   <property name="user"                value="rest-writer-user"/>
	 *   <property name="password"            value="rest-writer-password"/>
	 *   <property name="authenticationValue" value="digest"/>
	 * </bean>
	 * 
	 * <bean name="databaseClient"
	 * 	   class="com.marklogic.client.DatabaseClient"
	 * 	   factory-bean="databaseClientFactory"
	 * 	   factory-method="newClient"/>
	 * 
*/ static public class Bean implements Serializable { private static final long serialVersionUID = 1L; private String host; private int port; private String database; private String user; private String password; private Authentication authentication; private HandleFactoryRegistry handleRegistry = HandleFactoryRegistryImpl.newDefault(); transient private SSLContext context; transient private SSLHostnameVerifier verifier; /** * Zero-argument constructor for bean applications. Other * applications can use the static newClient() factory methods * of DatabaseClientFactory. */ public Bean() { super(); } /** * Returns the host for clients created with a * DatabaseClientFactory.Bean object. * @return the client host */ public String getHost() { return host; } /** * Specifies the host for clients created from a * DatabaseClientFactory.Bean object. * @param host the client host */ public void setHost(String host) { this.host = host; } /** * Returns the port for clients created with a * DatabaseClientFactory.Bean object. * @return the client port */ public int getPort() { return port; } /** * Specifies the port for clients created with a * DatabaseClientFactory.Bean object. * @param port the client port */ public void setPort(int port) { this.port = port; } /** * Returns the user authentication for clients created with a * DatabaseClientFactory.Bean object. * @return the user */ public String getUser() { return user; } /** * Specifies the user authentication for clients created with a * DatabaseClientFactory.Bean object. * @param user the user */ public void setUser(String user) { this.user = user; } /** * Returns the password authentication for clients created with a * DatabaseClientFactory.Bean object. * @return the password */ public String getPassword() { return password; } /** * Specifies the password authentication for clients created with a * DatabaseClientFactory.Bean object. * @param password the password */ public void setPassword(String password) { this.password = password; } /** * Returns the authentication type for clients created with a * DatabaseClientFactory.Bean object. * @return the authentication type */ public Authentication getAuthentication() { return authentication; } /** * Specifies the authentication type for clients created with a * DatabaseClientFactory.Bean object. * @param authentication the authentication type */ public void setAuthentication(Authentication authentication) { this.authentication = authentication; } /** * Specifies the authentication type for clients created with a * DatabaseClientFactory.Bean object based on a string value. * @param authentication the authentication type */ public void setAuthenticationValue(String authentication) { this.authentication = Authentication.valueOfUncased(authentication); } /** * Returns the SSLContext for SSL clients created with a * DatabaseClientFactory.Bean object. * @return the SSL context */ public SSLContext getContext() { return context; } /** * Specifies the SSLContext for clients created with a * DatabaseClientFactory.Bean object that authenticate with SSL. * @param context the SSL context */ public void setContext(SSLContext context) { this.context = context; } /** * Returns the host verifier for clients created with a * DatabaseClientFactory.Bean object. * @return the host verifier */ public SSLHostnameVerifier getVerifier() { return verifier; } /** * Specifies the host verifier for clients created with a * DatabaseClientFactory.Bean object that verify hosts for * additional security. * @param verifier the host verifier */ public void setVerifier(SSLHostnameVerifier verifier) { this.verifier = verifier; } /** * Returns the registry for associating * IO representation classes with handle factories. * @return the registry instance */ public HandleFactoryRegistry getHandleRegistry() { return handleRegistry; } /** * Removes the current registered associations so the * handle registry is empty. */ public void clearHandleRegistry() { this.handleRegistry = new HandleFactoryRegistryImpl(); } /** * Initializes a handle registry with the default associations * between the content handles provided by the API and the supported * IO representation classes. Use this method only after clearing * or overwriting associations in the handle registry. */ public void registerDefaultHandles() { HandleFactoryRegistryImpl.registerDefaults(getHandleRegistry()); } /** * Creates a client for bean applications based on the properties. * Other applications can use the static newClient() factory methods * of DatabaseClientFactory. * The client accesses the database by means of a REST server. * @return a new client for making database requests */ public DatabaseClient newClient() { DatabaseClientImpl client = newClientImpl(host, port, database, user, password, authentication, context, verifier); client.setHandleRegistry(getHandleRegistry().copy()); return client; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy