001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2009-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS. 026 */ 027 028package org.forgerock.opendj.examples; 029 030import java.io.IOException; 031import java.util.LinkedList; 032import java.util.List; 033 034import org.forgerock.opendj.ldap.ConnectionFactory; 035import org.forgerock.opendj.ldap.Connections; 036import org.forgerock.opendj.ldap.LdapException; 037import org.forgerock.opendj.ldap.LDAPClientContext; 038import org.forgerock.opendj.ldap.LDAPConnectionFactory; 039import org.forgerock.opendj.ldap.LDAPListener; 040import org.forgerock.opendj.ldap.LDAPListenerOptions; 041import org.forgerock.opendj.ldap.RequestContext; 042import org.forgerock.opendj.ldap.RequestHandlerFactory; 043import org.forgerock.opendj.ldap.RoundRobinLoadBalancingAlgorithm; 044import org.forgerock.opendj.ldap.ServerConnectionFactory; 045import org.forgerock.opendj.ldap.requests.Requests; 046 047/** 048 * An LDAP load balancing proxy which forwards requests to one or more remote 049 * Directory Servers. This is implementation is very simple and is only intended 050 * as an example: 051 * <ul> 052 * <li>It does not support SSL connections 053 * <li>It does not support StartTLS 054 * <li>It does not support Abandon or Cancel requests 055 * <li>Very basic authentication and authorization support. 056 * </ul> 057 * This example takes the following command line parameters: 058 * 059 * <pre> 060 * {@code <listenAddress> <listenPort> <proxyDN> <proxyPassword> <remoteAddress1> <remotePort1> 061 * [<remoteAddress2> <remotePort2> ...]} 062 * </pre> 063 */ 064public final class Proxy { 065 /** 066 * Main method. 067 * 068 * @param args 069 * The command line arguments: listen address, listen port, 070 * remote address1, remote port1, remote address2, remote port2, 071 * ... 072 */ 073 public static void main(final String[] args) { 074 if (args.length < 6 || args.length % 2 != 0) { 075 System.err.println("Usage: listenAddress listenPort " 076 + "proxyDN proxyPassword remoteAddress1 remotePort1 " 077 + "remoteAddress2 remotePort2 ..."); 078 System.exit(1); 079 } 080 081 // Parse command line arguments. 082 final String localAddress = args[0]; 083 final int localPort = Integer.parseInt(args[1]); 084 085 final String proxyDN = args[2]; 086 final String proxyPassword = args[3]; 087 088 // Create load balancer. 089 // --- JCite pools --- 090 final List<ConnectionFactory> factories = new LinkedList<>(); 091 final List<ConnectionFactory> bindFactories = new LinkedList<>(); 092 for (int i = 4; i < args.length; i += 2) { 093 final String remoteAddress = args[i]; 094 final int remotePort = Integer.parseInt(args[i + 1]); 095 096 factories.add(Connections.newCachedConnectionPool(Connections 097 .newAuthenticatedConnectionFactory(Connections 098 .newHeartBeatConnectionFactory(new LDAPConnectionFactory(remoteAddress, 099 remotePort)), Requests.newSimpleBindRequest(proxyDN, 100 proxyPassword.toCharArray())))); 101 bindFactories.add(Connections.newCachedConnectionPool(Connections 102 .newHeartBeatConnectionFactory(new LDAPConnectionFactory(remoteAddress, 103 remotePort)))); 104 } 105 // --- JCite pools --- 106 107 // --- JCite load balancer --- 108 final RoundRobinLoadBalancingAlgorithm algorithm = 109 new RoundRobinLoadBalancingAlgorithm(factories); 110 final RoundRobinLoadBalancingAlgorithm bindAlgorithm = 111 new RoundRobinLoadBalancingAlgorithm(bindFactories); 112 final ConnectionFactory factory = Connections.newLoadBalancer(algorithm); 113 final ConnectionFactory bindFactory = Connections.newLoadBalancer(bindAlgorithm); 114 // --- JCite load balancer --- 115 116 // --- JCite backend --- 117 /* 118 * Create a server connection adapter which will create a new proxy 119 * backend for each inbound client connection. This is required because 120 * we need to maintain authorization state between client requests. 121 */ 122 final RequestHandlerFactory<LDAPClientContext, RequestContext> proxyFactory = 123 new RequestHandlerFactory<LDAPClientContext, RequestContext>() { 124 @Override 125 public ProxyBackend handleAccept(LDAPClientContext clientContext) 126 throws LdapException { 127 return new ProxyBackend(factory, bindFactory); 128 } 129 }; 130 final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = 131 Connections.newServerConnectionFactory(proxyFactory); 132 // --- JCite backend --- 133 134 // --- JCite listener --- 135 // Create listener. 136 final LDAPListenerOptions options = new LDAPListenerOptions().setBacklog(4096); 137 LDAPListener listener = null; 138 try { 139 listener = new LDAPListener(localAddress, localPort, connectionHandler, options); 140 System.out.println("Press any key to stop the server..."); 141 System.in.read(); 142 } catch (final IOException e) { 143 System.out.println("Error listening on " + localAddress + ":" + localPort); 144 e.printStackTrace(); 145 } finally { 146 if (listener != null) { 147 listener.close(); 148 } 149 } 150 // --- JCite listener --- 151 } 152 153 private Proxy() { 154 // Not used. 155 } 156}