/*
* JacORB - a free Java ORB
*
* Copyright (C) 1997-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or modify it under the terms of the
* GNU Library General Public License as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
* USA.
*/
package org.jacorb.orb.util;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import org.jacorb.orb.ORB;
import org.jacorb.orb.ParsedIOR;
import org.jacorb.orb.iiop.IIOPAddress;
import org.jacorb.orb.iiop.IIOPProfile;
import org.jacorb.orb.miop.MIOPProfile;
import org.omg.ETF.Factories;
import org.omg.ETF.Profile;
import org.omg.GIOP.Version;
import org.omg.MIOP.UIPMC_ProfileBody;
import org.omg.PortableGroup.TagGroupTaggedComponent;
/**
* @author Gerald Brose
*/
public class CorbaLoc
{
private final ORB orb;
private String keyString;
private byte[] key;
private String bodyString;
private boolean is_rir;
public Profile[] profileList;
public CorbaLoc(ORB orb, String addr)
{
this.orb = orb;
is_rir = false;
parse(addr);
}
public boolean rir()
{
return is_rir;
}
@Override
public String toString()
{
return "corbaloc:" + body();
}
private String body()
{
StringBuffer buffer = new StringBuffer();
buffer.append(bodyString);
if (keyString != null)
{
buffer.append('/');
buffer.append(keyString);
}
return buffer.toString();
}
public String getKeyString()
{
return keyString;
}
public byte[] getKey()
{
return key;
}
private void defaultKeyString(String defaultKey)
{
if (keyString == null)
{
keyString = defaultKey;
}
else
{
throw new IllegalStateException("KeyString not empty, cannot default to " + defaultKey);
}
}
public String toCorbaName(String str_name)
{
if (getKeyString() == null)
{
defaultKeyString("NameService");
}
if (str_name != null && str_name.length() > 0)
{
try
{
return "corbaname:" + body() + "#" + str_name;
}
catch (Exception e)
{
return null;
}
}
return "corbaname:" + body();
}
/**
* parses a string representing a corbaloc: reference
*/
private void parse(String addr)
{
if (addr == null || !addr.startsWith("corbaloc:"))
{
throw new IllegalArgumentException("URL must start with \'corbaloc:\'");
}
String sb;
boolean isMIOP = (addr.indexOf("miop") != -1);
if (isMIOP && addr.indexOf(",iiop") != -1)
{
throw new IllegalArgumentException("MIOP Profile does not support Gateway Profiles.");
}
if (!isMIOP && addr.indexOf('/') == -1)
{
sb = addr.substring(addr.indexOf(':') + 1);
if (addr.startsWith("corbaloc:rir:"))
{
is_rir = true;
// default key string for rir protocol
keyString = "NameService";
}
else
{
keyString = null;
}
key = new byte[0];
}
else
{
String iiopKey;
int startIndex;
int endIndex;
// MIOP plus another e.g. IIOP profile. Scan IIOP profile for key.
if (isMIOP && addr.indexOf(';') != -1)
{
iiopKey = addr.substring(addr.indexOf(';'));
startIndex = 1;
endIndex = iiopKey.indexOf('/');
}
else
{
iiopKey = addr;
startIndex = iiopKey.indexOf(':') + 1;
endIndex = (isMIOP ? iiopKey.length() : iiopKey.indexOf('/'));
}
sb = iiopKey.substring(startIndex, endIndex);
keyString = iiopKey.substring(iiopKey.indexOf('/') + 1);
key = parseKey(keyString);
}
// ! MIOP as we don't currently support gateway profiles.
if (!isMIOP && sb.indexOf(',') > 0)
{
StringTokenizer tokenizer = new StringTokenizer(sb, ",");
profileList = new Profile[tokenizer.countTokens()];
int pIndex = 0;
for (int i = 0; i < profileList.length; i++)
{
Profile p = parseAddress(tokenizer.nextToken());
if (p == null)
{
continue;
}
profileList[pIndex] = p;
pIndex++;
}
while (pIndex < profileList.length)
{
profileList[pIndex] = null;
pIndex++;
}
}
else
{
profileList = new Profile[] { parseAddress(sb) };
}
bodyString = sb;
}
private Profile parseAddress(String addr)
{
int colon = addr.indexOf(':');
if (colon == -1)
{
throw new IllegalArgumentException("Illegal object address format: " + addr);
}
if ("rir:".equals(addr))
{
is_rir = true;
/* resolve initials references protocol */
return null;
}
Profile result = null;
if (orb == null && (colon == 0 || addr.startsWith("iiop:") || addr.startsWith("ssliop:")))
{
result = new IIOPProfile(addr);
}
else if (orb != null)
{
List<Factories> factories = orb.getTransportManager().getFactoriesList();
for (Iterator<Factories> i = factories.iterator(); result == null && i.hasNext();)
{
org.omg.ETF.Factories f = i.next();
result = f.decode_corbaloc(addr);
}
}
if (result == null)
{
throw new IllegalArgumentException("Unknown protocol in object address format: " + addr);
}
return result;
}
private static boolean legalChar(char c)
{
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
{
return true;
}
return (c == ';' || c == '/' || c == ':' || c == '?' || c == '@' || c == '&' || c == '=' || c == '+'
|| c == '$' || c == ',' || c == '_' || c == '.' || c == '!' || c == '~' || c == '*' || c == '\''
|| c == '-' || c == '(' || c == ')');
}
private static byte hexValue(char c)
{
return (byte) ((c >= 'a') ? (10 + c - 'a') : ((c >= 'A') ? (10 + c - 'A') : (c - '0')));
}
private static char hexDigit(byte b)
{
if ((b & 0xf0) != 0)
{
throw new IllegalArgumentException("Hex digit out of range " + b);
}
return (char) (b < 10 ? '0' + (char) b : 'A' + (char) b - 10);
}
private static boolean isHex(char c)
{
return ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
public static byte[] parseKey(String s)
{
char[] tmp = s.toCharArray();
int count = tmp.length;
for (int i = 0; i < tmp.length; i++)
{
if (!legalChar(tmp[i]))
{
if (tmp[i] == '%')
{
if (isHex(tmp[i + 1]) && isHex(tmp[i + 2]))
{
count -= 2;
i += 2;
}
else
{
throw new IllegalArgumentException("Illegal escape in URL character");
}
}
else
{
throw new IllegalArgumentException("URL character out of range: " + tmp[i]);
}
}
}
byte[] result = new byte[count];
int idx = 0;
for (int i = 0; i < count; i++)
{
if (legalChar(tmp[idx]))
{
result[i] = (byte) tmp[idx++];
}
else
{
result[i] = (byte) ((hexValue(tmp[idx + 1])) << 4 | hexValue(tmp[idx + 2]));
idx += 3;
}
}
return result;
}
public static String parseKey(byte[] key)
{
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < key.length; i++)
{
if (!legalChar((char) key[i]))
{
buffer.append('%');
// Mask the bytes before shift to ensure 10001001 doesn't get
// shifted to 11111000 but 00001000 (linden java faq).
buffer.append(hexDigit((byte) ((key[i] & 0xff) >> 4)));
buffer.append(hexDigit((byte) (key[i] & 0x0f)));
}
else
{
buffer.append((char) key[i]);
}
}
return buffer.toString();
}
public static String generateCorbaloc(org.omg.CORBA.ORB orb, org.omg.CORBA.Object ref)
{
ParsedIOR pior = new ParsedIOR((org.jacorb.orb.ORB) orb, orb.object_to_string(ref));
Profile profile = pior.getEffectiveProfile();
if (profile instanceof IIOPProfile)
{
return createCorbalocForIIOPProfile((IIOPProfile) profile);
}
else if (profile instanceof MIOPProfile)
{
return createCorbalocForMIOPProfile((MIOPProfile) profile);
}
else
{
throw new IllegalArgumentException("Profile type not suported: tag number=" + profile.tag());
}
}
/**
* Create a corbaloc string for a MIOP profile.
*
* @param profile
* the MIOP profile
* @return the created crobaloc string
*/
private static String createCorbalocForMIOPProfile(MIOPProfile profile)
{
StringBuffer sb = new StringBuffer("miop:");
sb.append(createString(profile.version()));
sb.append("@");
sb.append(createString(profile.getTagGroup()));
sb.append("/");
sb.append(createString(profile.getUIPMCProfile()));
// group's IIOP component
sb.append(";");
sb.append(createCorbalocForIIOPProfile(profile.getGroupIIOPProfile()));
return sb.toString();
}
/**
* Returns a String version of the tag_group.
*
* @param groupInfo
* @return the created corbaloc string
*/
private static String createString(TagGroupTaggedComponent groupInfo)
{
StringBuffer sb = new StringBuffer();
sb.append(createString(groupInfo.group_version));
sb.append("-");
sb.append(groupInfo.group_domain_id);
sb.append("-");
sb.append(groupInfo.object_group_id);
if (groupInfo.object_group_ref_version != 0)
{
sb.append("-");
sb.append(groupInfo.object_group_ref_version);
}
return sb.toString();
}
/**
* Returns a String version of the uipmc profile address.
*
* @param uipmc
* @return the created crobaloc string
*/
private static String createString(UIPMC_ProfileBody uipmc)
{
StringBuffer sb = new StringBuffer();
sb.append(uipmc.the_address);
sb.append(":");
sb.append(uipmc.the_port);
return sb.toString();
}
/**
* Returns a String version of the Version.
*
* @param version
* @return the created corbaloc string
*/
private static String createString(Version version)
{
StringBuffer sb = new StringBuffer();
sb.append(version.major);
sb.append(".");
sb.append(version.minor);
return sb.toString();
}
public static String generateCorbalocForMultiIIOPProfiles(org.omg.CORBA.ORB orb, org.omg.CORBA.Object ref)
{
return generateCorbalocForMultiIIOPProfiles(orb, orb.object_to_string(ref));
}
public static String generateCorbalocForMultiIIOPProfiles(org.omg.CORBA.ORB orb, String ref)
{
ParsedIOR pior = new ParsedIOR((org.jacorb.orb.ORB) orb, ref);
String result = null;
String object_key = null;
Iterator<Profile> iterator;
for (iterator = pior.getProfiles().iterator(); iterator.hasNext();)
{
Profile profile = iterator.next();
if (profile instanceof IIOPProfile)
{
String s = createCorbalocForIIOPProfile((IIOPProfile) profile, true);
if (result != null)
{
result += "," + s;
}
else
{
result = "corbaloc:" + s;
object_key = parseKey(profile.get_object_key());
}
}
}
if (result != null)
{
result += "/" + object_key;
}
return result;
}
public static String createCorbalocForIIOPProfile(IIOPProfile profile)
{
return createCorbalocForIIOPProfile(profile, false).concat('/' + parseKey(profile.get_object_key()));
}
/**
* Returns a iiop list ; note this function does not add the object_key.
*
* @param profile
* @param addAlternates
* boolean whether to add alternate profiles to this corbaloc
* @return
*/
private static String createCorbalocForIIOPProfile(IIOPProfile profile, boolean addAlternates)
{
StringBuffer sb = new StringBuffer("iiop:");
sb.append(createString(profile.version()));
sb.append("@");
sb.append(wrapIPv6(((IIOPAddress) profile.getAddress()).getOriginalHost()));
sb.append(":");
sb.append(((IIOPAddress) profile.getAddress()).getPort());
for (Iterator<IIOPAddress> iter = profile.getAlternateAddresses().iterator(); addAlternates && iter.hasNext();)
{
IIOPAddress address = iter.next();
sb.append(",iiop:");
sb.append(createString(profile.version()));
sb.append("@");
sb.append(wrapIPv6(address.getOriginalHost()));
sb.append(":");
sb.append(address.getPort());
}
return sb.toString();
}
private static String wrapIPv6(String addr)
{
String result = addr;
InetAddress address;
try
{
address = InetAddress.getByName(addr);
if (address instanceof Inet6Address)
{
result = '[' + result + ']';
}
}
catch (UnknownHostException e)
{
}
return result;
}
public static void main(String[] args)
{
String[] noarg = new String[] {};
ORB orb = (org.jacorb.orb.ORB) ORB.init(noarg, null);
for (int i = 0; i < args.length; i++)
{
System.out.println(new CorbaLoc(orb, args[i]).toString());
}
}
}