/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.bigdata.rdf.sail.webapp.lbs; import java.io.IOException; import java.util.UUID; import com.bigdata.counters.CAT; import com.bigdata.ha.HAGlue; import com.bigdata.ha.IHAJournal; import com.bigdata.ha.QuorumService; import com.bigdata.journal.IIndexManager; import com.bigdata.quorum.Quorum; /** * Helper class caches metadata about an {@link HAGlue} service. */ public class ServiceScore { /** * The service {@link UUID} for the remote service. * * @see HAGlue#getServiceUUID() */ final private UUID serviceUUID; /** * The hostname for the remote service. * * @see HAGlue#getHostname() */ private String hostname; /** * The constructed <code>Request-URI</code> for the root of the servlet * context for the NSS on the remote service -or- <code>null</code> if * anything goes wrong. */ private String requestURI; /** * The service {@link UUID} for the remote service. * * @see HAGlue#getServiceUUID() */ public UUID getServiceUUID() { return serviceUUID; } /** * The hostname for the remote service -or- <code>null</code> if something * goes wrong. * * @see HAGlue#getHostname() */ public String getHostname() { return hostname; } /** * The <code>Request-URI</code> for the root of the web application on the * target host. This is assigned IFF everything succeeds. This is what we * will use to proxy a request to the service having the {@link UUID} given * to the constructor. * <p> * Note: This needs to be a URL, not just a relative path. Otherwise you get * an NPE. * <p> * This is formed as: * * <pre> * requestURI = "http://" + hostname + ":" + port + contextPath; * </pre> * * The <code>hostname</code> is obtained from {@link HAGlue#getHostname()}. * <p> * The <code>port</code> is obtained from {@link HAGlue#getNSSPort()}. * * TODO How do we configure the protocol for the remote NSS instance? This * code assumes that it is <code>http</code>, but <code>https</code> is also * possible. This could be handled by an {@link IHARequestURIRewriter} but * maybe the {@link HAGlue} interface should be declaring this too? */ public String getRequestURI() { return requestURI; } /** * The #of requests that have been directed to this service. */ public final CAT nrequests = new CAT(); @Override public String toString() { return getClass().getName() + "{serviceUUID=" + serviceUUID + ", hostname=" + hostname + ", requestURI=" + requestURI + ", nrequests=" + nrequests.get() + "}"; } /** * * @param serviceUUID * The {@link UUID} for the service. * @param hostname * The hostname of the host on which the service is running. * @param requestURI * The Request-URI for the service. * * @throws IllegalArgumentException * if any argument is <code>null</code>. */ ServiceScore(final UUID serviceUUID, final String hostname, final String requestURI) { if (serviceUUID == null) throw new IllegalArgumentException(); if (hostname == null) throw new IllegalArgumentException(); if (requestURI == null) throw new IllegalArgumentException(); this.serviceUUID = serviceUUID; this.hostname = hostname; this.requestURI = requestURI; } /** * Factory for {@link ServiceScore} instances. * * @param indexManager * The index manager (required). * @param contextPath * The Context-Path of the web application (/bigdata). * @param serviceUUID * The {@link UUID} of the service. * * @return The {@link ServiceScore}. * * @throws IllegalArgumentException * if any argument is <code>null</code>. * @throws ClassCastException * if the {@link IIndexManager} is not an {@link HAJournal}. * @throws IOException * If an RMI to the {@link HAGlue} proxy fails. * @throws RuntimeException * if anything else goes wrong. */ static public ServiceScore newInstance(final IIndexManager indexManager, final String contextPath, final UUID serviceUUID) throws IllegalArgumentException, ClassCastException, IOException, RuntimeException { if (indexManager == null) throw new IllegalArgumentException(); if (contextPath == null) throw new IllegalArgumentException(); if (serviceUUID == null) throw new IllegalArgumentException(); final IHAJournal journal = (IHAJournal) indexManager; final Quorum<HAGlue, QuorumService<HAGlue>> quorum = journal .getQuorum(); if (quorum == null) { // No quorum. return null; } /* * Note: This is the *local* HAGlueService. * * This page must be robust to some new failure modes. The ZooKeeper * client can now be associated with an expired session, River discovery * can now be disabled, and the HAQuorumService might not be available * from quorum.getClient(). All of those things can happen if there is a * zookeeper session expiration that forces us to terminate the * HAQuorumService. This condition will be cured automatically (unless * the service is being shutdown), but only limited status information * can be provided while the HAQuorumService is not running. */ final QuorumService<HAGlue> quorumService; { QuorumService<HAGlue> t; try { t = (QuorumService<HAGlue>) quorum.getClient(); } catch (IllegalStateException ex) { // Note: Not available (quorum.start() not called). throw ex; } quorumService = t; } final HAGlue haGlue; try { haGlue = quorumService.getService(serviceUUID); } catch (IllegalArgumentException ex) { // No such service. throw ex; } /* * TODO The hostname and port are RMIs. Use a smart proxy for HAGlue. Or * consult a cache of existing ServiceScore objects. [The caller DOES * consult a cache so this is partly addressed.] */ final String hostname; final int port; try { hostname = haGlue.getHostname(); port = haGlue.getNSSPort(); } catch (IOException ex) { // RMI error. throw ex; } // The default URL for that host. final String requestURI = "http://" + hostname + ":" + port + contextPath; return new ServiceScore(serviceUUID, hostname, requestURI); } }