blob: ef0299dab3fd5eca5f1adffe05ef56605d370931 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.vinci.transport.context;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.vinci.debug.Debug;
import org.apache.vinci.transport.ServiceDownException;
import org.apache.vinci.transport.ServiceException;
import org.apache.vinci.transport.Transportable;
import org.apache.vinci.transport.TransportableFactory;
import org.apache.vinci.transport.VNSException;
import org.apache.vinci.transport.VinciClient;
import org.apache.vinci.transport.VinciFrame;
import org.apache.vinci.transport.vns.client.ResolveResult;
/**
* <p>
* This class can be used to globally affect various behaviors of Vinci clients and servers under
* its control (for example, which VNS to contact). There is one "global" VinciContext that is used
* by default, though anyone can create an alternate context should multiple sets of defaults be
* required in a single program. Each VinciContext also serves to cache resolve results for all
* clients under its control (for a default of 1 minute).
* </p>
*
* <p>
* For the most part, Vinci library users won't have to directly deal with this class, since there
* is a global context used by default which is almost always adequate.
* </p>
*
* <p>
* The most common use of this class is to programmatically specify a VNS hostname other than the
* default (which is the one specified by the Java property VNS_HOST).
* </p>
*/
public class VinciContext {
public static final int DEFAULT_VNS_CACHE_SIZE = 1000;
private static final String VNS_HOST_PROPERTY = "VNS_HOST";
private static final String VNS_HOST_PROPERTY_2 = "VNSHOST";
private static final String VNS_PORT_PROPERTY = "VNS_PORT";
private static final String VNS_PORT_PROPERTY_2 = "VNSPORT";
private static final int DEFAULT_VNS_PORT = 9000;
static private VinciContext globalContext;
static {
String portString = System.getProperty(VNS_PORT_PROPERTY);
if (portString == null) {
portString = System.getProperty(VNS_PORT_PROPERTY_2);
}
int port;
if (portString != null) {
try {
port = Integer.parseInt(portString);
} catch (Exception e) {
Debug.reportException(e);
port = DEFAULT_VNS_PORT;
}
} else {
port = DEFAULT_VNS_PORT;
}
String host = System.getProperty(VNS_HOST_PROPERTY);
if (host == null) {
host = System.getProperty(VNS_HOST_PROPERTY_2);
}
globalContext = new VinciContext(host, port);
}
private static final int DEFAULT_RESOLVE_TIMEOUT = 20000;
private static final int DEFAULT_SERVEON_TIMEOUT = 60000;
// Default time to live for cached VNS entries.
private static final int DEFAULT_TTL = 60000;
private int vnsResolveTimeout = DEFAULT_RESOLVE_TIMEOUT;
private int vnsServeonTimeout = DEFAULT_SERVEON_TIMEOUT;
private int ttlMillis = DEFAULT_TTL;
// Whether or not to use stale cached entries
// in the event VNS is inaccessible.
private boolean allowStaleLookups = true;
private int vnsCacheSize = DEFAULT_VNS_CACHE_SIZE;
private String host;
private int port;
private boolean socketKeepAliveEnabled = true;
static class CachedVNSResult {
CachedVNSResult(ResolveResult r) {
this.r = r;
entryTime = System.currentTimeMillis();
}
ResolveResult r;
long entryTime;
}
/**
* Set the size of the VNS cache. This method can be invoked at any time, however if the cache
* size is ever reduced, it might not take effect.
*
* @param to
* The limit on the number of entries that will be maintained in the VNS cache.
*/
synchronized public void setVNSCacheSize(int to) {
vnsCacheSize = to;
}
private LinkedHashMap vnsCache = new LinkedHashMap(16, .75f, true) {
private static final long serialVersionUID = 7138871637782205744L;
protected boolean removeEldestEntry(Map.Entry e) {
return size() > vnsCacheSize;
}
};
/**
* @pre myport &ge; 0
* @pre myport &lt; 65536
* @param myhost -
* @param myport -
*/
public VinciContext(String myhost, int myport) {
this.host = myhost;
this.port = myport;
}
/**
* Return the VNS hostname. When the global instance of this class is first loaded, it will set
* the hostname from the java property VNS_HOST. To set the VNS_HOST using this java property, you
* must therefore specify the property before the class is ever referenced, e.g. through the
* command-line property option -DVNS_HOST=[hostname], or by calling
* System.setProperty("VNS_HOST", [hostname]) before ever invoking any Vinci client code.
* Otherwise, you can set the hostname using the setVNSHost() method provided by this class.
*
* @return -
* @throws IllegalStateException
* if the VNS host has not been specified.
*/
public String getVNSHost() {
if (host == null) {
throw new IllegalStateException(
"No VNS host or IP address has been specified! You can specify the VNS host or IP address through the Java command-line option -DVNS_HOST=[hostname], or programmatically using either System.setProperty(\"VNS_HOST\",[hostname]) or VinciContext.getGlobalContext().setVNSHost([hostname]).");
} else {
return host;
}
}
/**
* Return the VNS listener port. When the global instance of this class is first loaded, it will
* attempt to set the port number from the java property VNS_PORT. To set the port using this java
* property, you must therefore specify the VNS_PORT property before the class is ever referenced,
* e.g. through the command-line property option -DVNS_PORT=[hostname], or by calling
* System.setProperty("VNS_PORT", [hostname]) before ever invoking any Vinci client code.
* Otherwise, the port will default to 9000. You can override this default (or any
* property-specified value) by calling the setPort() method provided by this class.
* @return -
*/
public int getVNSPort() {
return port;
}
/**
* Set the VNS hostname.
* @param h -
*/
public void setVNSHost(String h) {
host = h;
flushAll(); // Flush the cache in case entries are cached from previous VNS setting
}
/**
* Set the VNS port.
*
* @pre port &ge; 0
* @pre port &lt; 65536
* @param p -
*/
public void setVNSPort(int p) {
port = p;
flushAll(); // Flush the cache in case entries are cached from previous VNS setting
}
/**
* Returns whether clients can use stale resolve cache entries for service location in the event
* VNS is unreachable.
* @return -
*/
public boolean areStaleLookupsAllowed() {
return allowStaleLookups;
}
/**
* Set whether clients can use stale resolve cache entries for service location in the event VNS
* is unreachable. Default is true.
* @param b -
*/
public void setAllowStaleLookups(boolean b) {
allowStaleLookups = b;
}
/**
* Get the time-to-live of cached service locators (resolve results).
* @return -
*/
public int getResolveCacheTTL() {
return ttlMillis;
}
/**
* Set the time-to-live of cached service locators (resolve results). Default is 1 minute. Set to
* 0 to disable caching completely.
* @param millis -
*/
public void setResolveCacheTTL(int millis) {
ttlMillis = millis;
}
/**
* Get the timeout setting of VNS resolve queries.
* @return -
*/
public int getVNSResolveTimeout() {
return vnsResolveTimeout;
}
/**
* Set the timeout of VNS resolve queries. Default is 20 seconds.
* @param millis -
*/
public void setVNSResolveTimeout(int millis) {
vnsResolveTimeout = millis;
}
/**
* Get the timeout setting of VNS serveon queries.
* @return -
*/
public int getVNSServeonTimeout() {
return vnsServeonTimeout;
}
/**
* Set the timeout of VNS serveon queries. Default is 60 seconds.
* @param millis -
*/
public void setVNSServeonTimeout(int millis) {
vnsServeonTimeout = millis;
}
/**
* Returns whether socket keepAlive is enabled.
* @see java.net.Socket#setKeepAlive(boolean)
* @return -
*/
public boolean isSocketKeepAliveEnabled() {
return socketKeepAliveEnabled;
}
/**
* Set whether socket keepAlive is enabled. Default is true.
* @see java.net.Socket#setKeepAlive(boolean)
* @param b -
*/
public void setSocketKeepAliveEnabled(boolean b) {
socketKeepAliveEnabled = b;
}
/**
* Get the global VinciContext used by Vinci classes when no context is explicitly specified.
* @return -
*/
static public VinciContext getGlobalContext() {
return globalContext;
}
/**
* Get a cached resolve result (if any).
*
* @param serviceName -
* @return the cached resolve result, or null if none is cached.
*
* @pre serviceName != null
*/
synchronized public ResolveResult getCachedResolveResult(String serviceName) {
CachedVNSResult r = (CachedVNSResult) vnsCache.get(serviceName);
if (r != null) {
long now = System.currentTimeMillis();
if (now - r.entryTime <= ttlMillis) {
return r.r;
}
}
return null;
}
/**
* Get a cached resolve result (if any), but allow returning stale cache entries.
*
* @param serviceName -
* @return the cached resolve result, or null if none is cached.
*
* @pre serviceName != null
*/
synchronized public ResolveResult getStaleCachedResolveResult(String serviceName) {
CachedVNSResult r = (CachedVNSResult) vnsCache.get(serviceName);
if (r != null) {
return r.r;
}
return null;
}
/**
* Provide a resolve result to cache.
*
* @pre serviceName != null
* @pre r != null
* @param serviceName -
* @param r -
*/
synchronized public void cacheResolveResult(String serviceName, ResolveResult r) {
CachedVNSResult c = (CachedVNSResult) vnsCache.get(serviceName);
if (c == null) {
vnsCache.put(serviceName, new CachedVNSResult(r));
} else {
c.r = r;
c.entryTime = System.currentTimeMillis();
}
// long now = System.currentTimeMillis();
}
/**
* Flush any cache entries pertaining to the specified service.
*
* @pre serviceName != null
* @param serviceName -
*/
synchronized public void flushFromCache(String serviceName) {
vnsCache.remove(serviceName);
}
synchronized public void flushAll() {
vnsCache.clear();
}
/**
* See documentation for VinciClient.sendAndReceive().
*
* @see org.apache.vinci.transport.VinciClient
*
* @param in -
* @param service_name -
* @param factory -
* @return -
* @throws IOException -
* @throws ServiceException -
* @throws ServiceDownException -
* @throws VNSException -
* @throws IllegalStateException
* if the VNS host has not been specified.
*
* @pre in != null
* @pre service_name != null
* @pre factory != null
*/
public Transportable sendAndReceive(Transportable in, String service_name,
TransportableFactory factory) throws IOException, ServiceException, ServiceDownException,
VNSException {
VinciClient tempClient = new VinciClient(service_name, factory, this);
try {
return tempClient.sendAndReceive(in);
} finally {
tempClient.close();
}
}
/**
* See documentation for VinciClient.sendAndReceive().
*
* @see org.apache.vinci.transport.VinciClient
*
* @param in -
* @param service_name -
* @param factory -
* @param socket_timeout -
* @return -
* @throws IOException -
* @throws ServiceException -
* @throws IllegalStateException
* if the VNS host has not been specified.
*
* @pre in != null
* @pre service_name != null
* @pre factory != null
* @pre socket_timeout &ge; 0
*/
public Transportable sendAndReceive(Transportable in, String service_name,
TransportableFactory factory, int socket_timeout) throws IOException, ServiceException {
VinciClient tempClient = new VinciClient(service_name, factory, this);
tempClient.setSocketTimeout(socket_timeout);
try {
return tempClient.sendAndReceive(in);
} finally {
tempClient.close();
}
}
/**
* See documentation for VinciClient.sendAndReceive().
*
* WARNING: This method relies on JDK-1.4 specific functions. USE IT ONLY if you don't need to
* maintain JDK1.3 compatability.
*
* @see org.apache.vinci.transport.VinciClient
*
* @param in -
* @param service_name -
* @param factory -
* @param socket_timeout -
* @param connect_timeout -
* @return -
* @throws IOException -
* @throws ServiceException -
* @throws IllegalStateException
* if the VNS host has not been specified.
*
* @pre in != null
* @pre service_name != null
* @pre factory != null
* @pre socket_timeout &ge; 0
*/
public Transportable sendAndReceive(Transportable in, String service_name,
TransportableFactory factory, int socket_timeout, int connect_timeout)
throws IOException, ServiceException {
VinciClient tempClient = new VinciClient(service_name, factory, this, connect_timeout);
tempClient.setSocketTimeout(socket_timeout);
try {
return tempClient.sendAndReceive(in);
} finally {
tempClient.close();
}
}
/**
* See documentation for VinciClient.rpc().
*
* @see org.apache.vinci.transport.VinciClient
*
* @param in -
* @param service_name -
* @return -
* @throws IOException -
* @throws ServiceException -
* @throws ServiceDownException -
* @throws VNSException -
* @throws IllegalStateException
* if the VNS host has not been specified.
*
* @pre in != null
* @pre service_name != null
*/
public VinciFrame rpc(Transportable in, String service_name) throws IOException,
ServiceException, ServiceDownException, VNSException {
VinciClient tempClient = new VinciClient(service_name, this);
try {
return tempClient.rpc(in);
} finally {
tempClient.close();
}
}
/**
* See documentation for VinciClient.rpc().
*
* @see org.apache.vinci.transport.VinciClient
*
* @param in -
* @param service_name -
* @param timeout -
* @return -
* @throws IOException -
* @throws ServiceException -
* @throws ServiceDownException -
* @throws VNSException -
* @throws IllegalStateException
* if the VNS host has not been specified.
*
* @pre in != null
* @pre service_name != null
* @pre timeout &ge; 0
*/
public VinciFrame rpc(Transportable in, String service_name, int timeout) throws IOException,
ServiceException, ServiceDownException, VNSException {
VinciClient tempClient = new VinciClient(service_name, this);
tempClient.setSocketTimeout(timeout);
try {
return tempClient.rpc(in);
} finally {
tempClient.close();
}
}
/**
* See documentation for VinciClient.rpc().
*
* WARNING: This method relies on JDK-1.4 specific functions. USE IT ONLY if you don't need to
* maintain JDK1.3 compatability.
*
* @see org.apache.vinci.transport.VinciClient
*
* @param in -
* @param service_name -
* @param socket_timeout -
* @param connect_timeout -
* @return -
* @throws IOException -
* @throws ServiceException -
* @throws ServiceDownException -
* @throws VNSException -
* @throws IllegalStateException
* if the VNS host has not been specified.
*
* @pre in != null
* @pre service_name != null
* @pre timeout &ge; 0
*/
public VinciFrame rpc(Transportable in, String service_name, int socket_timeout,
int connect_timeout) throws IOException, ServiceException, ServiceDownException,
VNSException {
VinciClient tempClient = new VinciClient(service_name, this, connect_timeout);
tempClient.setSocketTimeout(socket_timeout);
try {
return tempClient.rpc(in);
} finally {
tempClient.close();
}
}
}