001: // @(#)ServersList.java 1.1 "@(#)ServersList.java 1.1 99/09/24 Sun Microsystems"
002:
003: /*
004: * Reads the following properties from the Gateway profile - stored in DSAME
005: *
006: * 1. sunPortalGatewayPortalServerList
007: * List of portal server instances that this gateway is configured to service
008: *
009: * 2. sunPortalGatewayServerRetryInterval
010: * Time interval - frequency at which the gateway should ping the portal
011: * server to find whether the server is available
012: *
013: * Maintains two list list of available server and unavailable server and pings
014: * at the frequency as defined by the server retry interval. Creates a worker thread
015: * to continously carry out this activity
016: *
017: * Typically in multi-instance of portal server it is possible to have the following config
018: *
019: * |----------- PS 1 (http)
020: * LB---------|
021: * |----------- PS 2 (http)
022: * LB - Load Balancer
023: *
024: * This is valid as long as PS1 and PS2 have same config esp protocol i.e either
025: * http or https so that the load balancer alternates b/w ps1 and ps2
026: *
027: * with the GW it should be possible to support
028: *
029: * |----------- PS 1 (http)
030: * GW---------|
031: * |----------- PS 2 (https)
032: *
033: * with PS1 and PS2 having different protocol.
034: *
035: * @ adding Event Generation mechanism in case a portal server instance goes
036: * down or up, used by com.sun.portal.rproxy.configservlet.client.SrapClient
037: *
038: * @ modified Rajesh T
039: * @ date 24-7-2002
040: */
041: package com.sun.portal.util;
042:
043: import java.io.IOException;
044: import java.net.URL;
045: import java.util.ArrayList;
046: import java.util.HashMap;
047: import java.util.HashSet;
048: import java.util.Iterator;
049: import java.util.List;
050: import java.util.Map;
051: import java.util.Set;
052: import java.util.logging.Level;
053: import java.util.logging.Logger;
054:
055: import com.sun.portal.log.common.PortalLogger;
056: import com.sun.portal.rproxy.configservlet.client.GatewayProfile;
057: import java.util.Collections;
058: import com.sun.portal.rproxy.configservlet.client.PlatformProfile;
059:
060: public class ServersList extends HostAvailabilityListener {
061:
062: static Set _servers = new HashSet();
063:
064: public static Map _unavailable_servers = new HashMap();
065:
066: private static Iterator iterator;
067:
068: // static Logger logger = Logger.getLogger("com.sun.portal.sra.rproxy");
069: private static Logger logger = PortalLogger
070: .getLogger(ServersList.class);
071:
072: private static ServersList instance = new ServersList();
073:
074: static {
075: List all_identity_servers = getISServersList();
076:
077: List all_portal_servers = GatewayProfile
078: .getStringList("PortalServerList");
079:
080: List all_servers = getIntersection(all_identity_servers,
081: all_portal_servers);
082:
083: Iterator it = all_servers.iterator();
084: String pshostUrl = null;
085: String protocol = null, port = null, host = null;
086: int indx1, indx2, indx3;
087:
088: while (it.hasNext()) {
089: pshostUrl = it.next().toString().trim().toLowerCase();
090: int tmpindx = pshostUrl.indexOf('|');
091: if (tmpindx > 0) {
092: pshostUrl = pshostUrl.substring(0, tmpindx).trim();
093: }
094:
095: indx1 = pshostUrl.indexOf(":/");
096: if (indx1 == -1) {
097: // Add protocol info
098: indx1 = pshostUrl.indexOf(':');
099: if (indx1 == -1) {
100: // No protocol and port !! , default to http 80
101: pshostUrl = "http://" + pshostUrl + ":80";
102: } else {
103: // Port present , no protocol.
104: indx2 = pshostUrl.indexOf('/', indx1);
105: if (indx2 == -1) {
106: indx2 = pshostUrl.length();
107: }
108: host = pshostUrl.substring(0, indx1);
109: port = pshostUrl.substring(indx1 + 1, indx2);
110: int portVal = -1;
111: try {
112: portVal = Integer.parseInt(port);
113: } catch (NumberFormatException nfex) {
114: portVal = -1;
115: }
116: if (portVal == -1) {
117: portVal = 80;
118: }
119: if (portVal == 80) {
120: protocol = "http://";
121: } else if (portVal == 443) {
122: protocol = "https://";
123: } else {
124: // What do we do ?
125: // Do we ignore this entry , or let it stay ?
126: // If welet it stay , this will break other code
127: // in Session.java. Or do we default to http ?
128: // Ignoring the entry after discussions with Rajesh
129: // - Mridul
130: continue;
131: }
132: pshostUrl = protocol + host + ":" + portVal;
133: }
134: } else {
135: indx2 = pshostUrl.indexOf(':', indx1 + 1);
136: if (indx2 == -1) {
137: // No port info.
138: // Add port info depending on protocol.
139: protocol = pshostUrl.substring(0, indx1);
140: if (protocol.equals("http")) {
141: port = ":80";
142: } else if (protocol.equals("https")) {
143: port = ":443";
144: } else {
145: // Ignore this entry
146: continue;
147: }
148: if (pshostUrl.endsWith("/")) {
149: // Handle proto://host/
150: pshostUrl = pshostUrl.substring(0, pshostUrl
151: .length() - 1);
152: }
153: pshostUrl = pshostUrl + port;
154: }
155: // else - full URL given and so no issues...
156: }
157: _servers.add(pshostUrl);
158: }
159: iterator = _servers.iterator();
160: }
161:
162: public static ServersList getInstance() {
163: return instance;
164: }
165:
166: /*
167: * @ returns true if the specified server is present in the portal servers
168: * list
169: */
170:
171: private static List getISServersList() {
172: List isServersList = new ArrayList();
173: String igString = com.sun.portal.util.SystemProperties
174: .get("gateway.ignoreServerList");
175:
176: if (igString != null && igString.equalsIgnoreCase("true")) {
177: String protocol = null, port = null, host = null;
178: protocol = com.iplanet.am.util.SystemProperties
179: .get("com.iplanet.am.server.protocol");
180: host = com.iplanet.am.util.SystemProperties
181: .get("com.iplanet.am.server.host");
182: port = com.iplanet.am.util.SystemProperties
183: .get("com.iplanet.am.server.port");
184: String url = protocol + "://" + host + ":" + port;
185: GWDebug.debug.message("ServersList::<init>: adding server "
186: + url);
187: isServersList.add(url);
188: } else {
189: isServersList = PlatformProfile
190: .getStringList("server-list");
191: }
192: return isServersList;
193: }
194:
195: /**
196: * @param all_identity_servers
197: * @param all_portal_servers
198: * @return
199: */
200: private static List getIntersection(List all_identity_servers,
201: List all_portal_servers) {
202: List all_servers = new ArrayList();
203:
204: Iterator is_iter = all_identity_servers.iterator();
205:
206: for (; is_iter.hasNext();) {
207: String currentIS = (String) is_iter.next();
208: Iterator ps_iter = all_portal_servers.iterator();
209: while (ps_iter.hasNext()) {
210: String currentPS = ((String) ps_iter.next()).trim();
211: if (currentIS.startsWith(currentPS))
212: all_servers.add(currentIS);
213: }
214:
215: }
216:
217: if (all_servers.size() == 0)
218: all_servers = all_identity_servers;
219:
220: return all_servers;
221: }
222:
223: private ServersList() {
224: addHostAvailabilityListener(this );
225: }
226:
227: public static boolean contains(String server) {
228: if (server == null || server.trim().length() == 0) {
229: return false;
230: }
231: return (_servers.contains(server.toLowerCase()));
232: }
233:
234: /*
235: * @returns the next available server. A simple round-robin load balancing
236: * algorithm implementation with iterators.
237: */
238:
239: private static synchronized String getServer() {
240: if (iterator.hasNext()) {
241: return iterator.next().toString();
242: } else {
243: iterator = _servers.iterator();
244: return iterator.next().toString();
245: }
246: }
247:
248: public void hostAvailabilityChanged(HostAvailabilityEvent hae) {
249: // TODO :: check for proper host type and host status
250: if (hae.getHostType() == hae.IS_HOST) {
251: synchronized (_unavailable_servers) {
252: if (hae.getHostStatus() == hae.HOST_AVAILABLE) {
253: _unavailable_servers.remove(hae.getHost());
254: } else if (hae.getHostStatus() == hae.HOST_UNAVAILABLE) {
255: long time = System.currentTimeMillis();
256: _unavailable_servers.put(hae.getHost(), (new Long(
257: time)));
258: }
259: }
260: }
261: }
262:
263: /*
264: * @ returns true if the specified server is alive Using URLConnection
265: * object respects only JVM proxy parameters. There is no way to specify
266: * multiple proxies for domains/subdomains etc. Hence using
267: * PingServiceRequest
268: *
269: * Generates HostAvailabaliltyEvent when a particular portal instance goes
270: * down or up @ see com.sun.portal.rproxy.configservlet.HostChooser @ see
271: * con.sun.portal.util.HostAvailabilityEvent @ see
272: * con.sun.portal.util.HostAvailabilityMediator @ see
273: * con.sun.portal.util.HostAvailabilityEventImpl
274: *
275: */
276:
277: private static boolean aLive(String server) {
278:
279: synchronized (_unavailable_servers) {
280: if (!_unavailable_servers.isEmpty()
281: && _unavailable_servers.get(server) != null) {
282: return false; // do not use it!
283: }
284: }
285: try {
286: URL url = new URL(server);
287:
288: return HostChecker.isHostAvailable(url,
289: HostAvailabilityEvent.IS_HOST);
290: } catch (IOException e) {
291: // logger.log(Level.SEVERE, "Proxy Authentication Failed", e);
292: logger.log(Level.SEVERE, "PSSR_CSPU068", e);
293: }
294: return false;
295: }
296:
297: /*
298: * get a alive server and return uses
299: */
300:
301: public String getServeraLive() {
302: String server = null;
303: boolean alive = false;
304: int total = _servers.size();
305: int count = 0;
306: while (!alive && count < total) {
307: server = getServer();
308: alive = aLive(server);
309: count++;
310: }
311: return server;
312: }
313:
314: /*
315: * If the requested server is alive return it else return any other live
316: * server
317: */
318:
319: public String getServeraLive(String server) {
320: if (aLive(server)) {
321: return server;
322: }
323:
324: return (instance.getServeraLive());
325: }
326:
327: public static Set getAllSessionServersSet() {
328: return _servers;
329: }
330:
331: public static List getAMServerList() {
332: List list = getISServersList();
333: return Collections.unmodifiableList(list);
334: }
335:
336: }
|