blob: 45bec68f3adbd331abd5f47c73fee7e5d4328c7c [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.vns.client;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.vinci.debug.Debug;
import org.apache.vinci.transport.Frame;
import org.apache.vinci.transport.FrameComponent;
import org.apache.vinci.transport.FrameLeaf;
import org.apache.vinci.transport.TransportConstants;
import org.apache.vinci.transport.Transportable;
import org.apache.vinci.transport.TransportableFactory;
import org.apache.vinci.transport.VinciFrame;
import org.apache.vinci.transport.vns.VNSConstants;
/**
* Specialized document (Frame) for representing the result of resolving a service name to host/port
* through VNS. Also provides utility methods for manipulating qualified/unqualified service names.
* This class is used by VinciClient to locate the physical location of the requested service from
* its logical service name.
*/
public class ResolveResult extends Frame {
public int priority = -1;
static public TransportableFactory factory = new TransportableFactory() {
public Transportable makeTransportable() {
return new ResolveResult();
}
};
/**
* Strip the qualifications from this qualified service name.
*
* @pre service_name != null
* @param service_name -
* @return -
*/
static public String unqualifiedName(String service_name) {
if (isQualified(service_name)) {
service_name = service_name.trim();
int start = service_name.lastIndexOf('[');
return service_name.substring(0, start);
} else {
return service_name;
}
}
/**
* Check whether a service_name has qualifications (that is, any or all of level, host, instance
* are explicitly specified.)
*
* @pre service_name != null
* @param service_name -
* @return -
*/
static public boolean isQualified(String service_name) {
if (service_name.indexOf('[') != -1) {
return true;
}
return false;
}
/**
* Create a document representing the VNS resolve query for the specified service. This method
* accepts either qualified or unqualified service names.
*
* @pre service_name != null
* @param service_name -
* @return -
*/
static public Frame composeQuery(String service_name) {
VinciFrame query = new VinciFrame();
query.fadd(TransportConstants.COMMAND_KEY, VNSConstants.RESOLVE_COMMAND);
int start = service_name.indexOf('[');
if (start != -1) {
// qualified service name ... must parse out qualifications
int end = service_name.indexOf(']', start);
if (end != -1) {
String qualifications = service_name.substring(start + 1, end);
query.fadd(VNSConstants.SERVICE_KEY, service_name.substring(0, start));
StringTokenizer tokenizer = new StringTokenizer(qualifications, ",");
if (tokenizer.hasMoreTokens()) {
query.fadd(VNSConstants.LEVEL_KEY, tokenizer.nextToken());
if (tokenizer.hasMoreTokens()) {
query.fadd(VNSConstants.HOST_KEY, tokenizer.nextToken());
if (tokenizer.hasMoreTokens()) {
query.fadd(VNSConstants.INSTANCE_KEY, tokenizer.nextToken());
}
}
}
return query;
}
}
int at = service_name.indexOf('@');
if (at == -1) {
query.fadd(VNSConstants.SERVICE_KEY, service_name);
} else {
query.fadd(VNSConstants.SERVICE_KEY, service_name.substring(0, at));
}
return query;
}
/**
* Create a document representing the VNS resolve query for the highest priority service(s) whose
* priority is strictly below the specified priority. This method accepts either qualified or
* unqualified service names.
*
* @pre service_name != null
* @param service_name -
* @param mypriority -
* @return -
*/
static public Frame composeQuery(String service_name, int mypriority) {
VinciFrame query = (VinciFrame) composeQuery(service_name);
query.fadd("LEVEL", mypriority);
return query;
}
private List services = new ArrayList();
public ResolveResult() {
}
private int begin;
private int current;
/**
* Initialize the service listing iterator. This initializes to a random spot to implement simple
* load balancing across multiple equivalent service instances.
*/
public void initializeIterator() {
// Initialize the beginning to a random slot.
begin = (int) (Math.random() * services.size());
current = begin;
}
/**
* Determine if there are more service listing to be fetched.
* @return -
*/
public boolean hasMore() {
return (current - begin < services.size());
}
/**
* Fetch the next service listing.
*
* @pre hasMore()
* @return -
*/
public ServiceLocator getNext() {
ServiceLocator return_me = (ServiceLocator) services.get(current % services.size());
current++;
return return_me;
}
static public class ServiceLocator extends Frame {
public String host;
public int port;
public int instance;
// Note that "priority" is a member of ResolveResult instead of this member class, since
// all ServiceLocators for a particular query will always have the same priority.
/**
* Implement the Frame add() callback.
*
* @pre key != null
* @pre val != null
*/
public void add(String key, FrameComponent val) {
if (key.equals(VNSConstants.HOST_KEY)) {
host = ((FrameLeaf) val).toString();
} else if (key.equals(VNSConstants.PORT_KEY)) {
port = ((FrameLeaf) val).toInt();
} else if (key.equals(VNSConstants.INSTANCE_KEY)) {
instance = ((FrameLeaf) val).toInt();
}
}
}
/**
* Implement the frame add() callback.
*
* @pre key != null
* @pre val != null
* @pre {@code ((val instanceof ServiceLocator && key.equals(VNSConstants.SERVER_KEY)) || (val
* instanceof FrameLeaf && key.equals(VNSConstants.LEVEL_KEY)))}
*/
public void add(String key, FrameComponent val) {
if (key.equals(VNSConstants.SERVER_KEY)) {
Debug.Assert(val instanceof ServiceLocator);
services.add(val);
} else if (key.equals(VNSConstants.LEVEL_KEY)) {
priority = ((FrameLeaf) val).toInt();
}
}
/**
* Override the Frame createSubFrame method to create a ServiceLocator.
*/
public Frame createSubFrame(String key, int capacity) {
return new ServiceLocator();
}
// END Frame implementation
/*
* static public void main(String[] args_) { System.out.println(composeQuery(args_[0]).toXML()); }
*/
}