1a5b190bfSAndrew Rist /************************************************************** 2a5b190bfSAndrew Rist * 3a5b190bfSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4a5b190bfSAndrew Rist * or more contributor license agreements. See the NOTICE file 5a5b190bfSAndrew Rist * distributed with this work for additional information 6a5b190bfSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7a5b190bfSAndrew Rist * to you under the Apache License, Version 2.0 (the 8a5b190bfSAndrew Rist * "License"); you may not use this file except in compliance 9a5b190bfSAndrew Rist * with the License. You may obtain a copy of the License at 10a5b190bfSAndrew Rist * 11a5b190bfSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12a5b190bfSAndrew Rist * 13a5b190bfSAndrew Rist * Unless required by applicable law or agreed to in writing, 14a5b190bfSAndrew Rist * software distributed under the License is distributed on an 15a5b190bfSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16a5b190bfSAndrew Rist * KIND, either express or implied. See the License for the 17a5b190bfSAndrew Rist * specific language governing permissions and limitations 18a5b190bfSAndrew Rist * under the License. 19a5b190bfSAndrew Rist * 20a5b190bfSAndrew Rist *************************************************************/ 21a5b190bfSAndrew Rist 22a5b190bfSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir package com.sun.star.lib.uno.helper; 25cdf0e10cSrcweir import java.io.UnsupportedEncodingException; 26cdf0e10cSrcweir import java.util.HashMap; 27cdf0e10cSrcweir import java.util.Vector; 28cdf0e10cSrcweir 29cdf0e10cSrcweir /** 30cdf0e10cSrcweir * Object representation and parsing of Uno Urls, 31cdf0e10cSrcweir * which allow to locate a named Uno object in a 32cdf0e10cSrcweir * different process. An Uno Url consists of the 33cdf0e10cSrcweir * specification of a connection, protocol and 34cdf0e10cSrcweir * rootOid delimited with a ';'. 35cdf0e10cSrcweir * The syntax of an Uno Url is 36cdf0e10cSrcweir * 37cdf0e10cSrcweir * <code> 38cdf0e10cSrcweir * [uno:]connection-type,parameters;protocol-name,parameters;objectname"; 39cdf0e10cSrcweir * </code> 40cdf0e10cSrcweir * 41cdf0e10cSrcweir * An example Uno Url will look like this: 42cdf0e10cSrcweir * 43cdf0e10cSrcweir * <code> 44cdf0e10cSrcweir * socket,host=localhost,port=2002;urp;StarOffice.ServiceManager 45cdf0e10cSrcweir * </code> 46cdf0e10cSrcweir * 47cdf0e10cSrcweir * For more information about Uno Url please consult 48cdf0e10cSrcweir * <a href="http://udk.openoffice.org/common/man/spec/uno-url.html"> 49cdf0e10cSrcweir * http://udk.openoffice.org/common/man/spec/uno-url.html</a> 50cdf0e10cSrcweir * 51cdf0e10cSrcweir * Usage: 52cdf0e10cSrcweir * 53cdf0e10cSrcweir * <code> 54cdf0e10cSrcweir * UnoUrl url = UnoUrl.parseUnoUrl("socket,host=localhost,port=2002;urp;StarOffice.ServiceManager"); 55cdf0e10cSrcweir * </code> 56cdf0e10cSrcweir * 57cdf0e10cSrcweir * @author Joerg Brunsmann 58cdf0e10cSrcweir */ 59cdf0e10cSrcweir public class UnoUrl { 60cdf0e10cSrcweir 61cdf0e10cSrcweir private static final String FORMAT_ERROR = 62cdf0e10cSrcweir "syntax: [uno:]connection-type,parameters;protocol-name,parameters;objectname"; 63cdf0e10cSrcweir 64cdf0e10cSrcweir private static final String VALUE_CHAR_SET = "!$&'()*+-./:?@_~"; 65cdf0e10cSrcweir private static final String OID_CHAR_SET = VALUE_CHAR_SET + ",="; 66cdf0e10cSrcweir 67cdf0e10cSrcweir private UnoUrlPart connection; 68cdf0e10cSrcweir private UnoUrlPart protocol; 69cdf0e10cSrcweir private String rootOid; 70cdf0e10cSrcweir 71cdf0e10cSrcweir static private class UnoUrlPart { 72cdf0e10cSrcweir 73cdf0e10cSrcweir private String partTypeName; 74cdf0e10cSrcweir private HashMap partParameters; 75cdf0e10cSrcweir private String uninterpretedParameterString; 76cdf0e10cSrcweir UnoUrlPart( String uninterpretedParameterString, String partTypeName, HashMap partParameters)77cdf0e10cSrcweir public UnoUrlPart( 78cdf0e10cSrcweir String uninterpretedParameterString, 79cdf0e10cSrcweir String partTypeName, 80cdf0e10cSrcweir HashMap partParameters) { 81cdf0e10cSrcweir this.uninterpretedParameterString = uninterpretedParameterString; 82cdf0e10cSrcweir this.partTypeName = partTypeName; 83cdf0e10cSrcweir this.partParameters = partParameters; 84cdf0e10cSrcweir } 85cdf0e10cSrcweir getPartTypeName()86cdf0e10cSrcweir public String getPartTypeName() { 87cdf0e10cSrcweir return partTypeName; 88cdf0e10cSrcweir } 89cdf0e10cSrcweir getPartParameters()90cdf0e10cSrcweir public HashMap getPartParameters() { 91cdf0e10cSrcweir return partParameters; 92cdf0e10cSrcweir } 93cdf0e10cSrcweir getUninterpretedParameterString()94cdf0e10cSrcweir public String getUninterpretedParameterString() { 95cdf0e10cSrcweir return uninterpretedParameterString; 96cdf0e10cSrcweir } 97cdf0e10cSrcweir getUninterpretedString()98cdf0e10cSrcweir public String getUninterpretedString() { 99cdf0e10cSrcweir StringBuffer buf = new StringBuffer(partTypeName); 100cdf0e10cSrcweir if (uninterpretedParameterString.length() > 0) { 101cdf0e10cSrcweir buf.append(','); 102cdf0e10cSrcweir buf.append(uninterpretedParameterString); 103cdf0e10cSrcweir } 104cdf0e10cSrcweir return buf.toString(); 105cdf0e10cSrcweir } 106cdf0e10cSrcweir } 107cdf0e10cSrcweir UnoUrl( UnoUrlPart connectionPart, UnoUrlPart protocolPart, String rootOid)108cdf0e10cSrcweir private UnoUrl( 109cdf0e10cSrcweir UnoUrlPart connectionPart, 110cdf0e10cSrcweir UnoUrlPart protocolPart, 111cdf0e10cSrcweir String rootOid) { 112cdf0e10cSrcweir this.connection = connectionPart; 113cdf0e10cSrcweir this.protocol = protocolPart; 114cdf0e10cSrcweir this.rootOid = rootOid; 115cdf0e10cSrcweir } 116cdf0e10cSrcweir 117cdf0e10cSrcweir /** 118cdf0e10cSrcweir * Returns the name of the connection of this 119cdf0e10cSrcweir * Uno Url. Encoded characters are not allowed. 120cdf0e10cSrcweir * 121cdf0e10cSrcweir * @return The connection name as string. 122cdf0e10cSrcweir */ getConnection()123cdf0e10cSrcweir public String getConnection() { 124cdf0e10cSrcweir return connection.getPartTypeName(); 125cdf0e10cSrcweir } 126cdf0e10cSrcweir 127cdf0e10cSrcweir /** 128cdf0e10cSrcweir * Returns the name of the protocol of this 129cdf0e10cSrcweir * Uno Url. Encoded characters are not allowed. 130cdf0e10cSrcweir * 131cdf0e10cSrcweir * @return The protocol name as string. 132cdf0e10cSrcweir */ getProtocol()133cdf0e10cSrcweir public String getProtocol() { 134cdf0e10cSrcweir return protocol.getPartTypeName(); 135cdf0e10cSrcweir } 136cdf0e10cSrcweir 137cdf0e10cSrcweir /** 138cdf0e10cSrcweir * Return the object name. Encoded character are 139cdf0e10cSrcweir * not allowed. 140cdf0e10cSrcweir * 141cdf0e10cSrcweir * @return The object name as String. 142cdf0e10cSrcweir */ getRootOid()143cdf0e10cSrcweir public String getRootOid() { 144cdf0e10cSrcweir return rootOid; 145cdf0e10cSrcweir } 146cdf0e10cSrcweir 147cdf0e10cSrcweir /** 148cdf0e10cSrcweir * Returns the protocol parameters as 149cdf0e10cSrcweir * a Hashmap with key/value pairs. Encoded 150cdf0e10cSrcweir * characters like '%41' are decoded. 151cdf0e10cSrcweir * 152cdf0e10cSrcweir * @return a HashMap with key/value pairs for protocol parameters. 153cdf0e10cSrcweir */ getProtocolParameters()154cdf0e10cSrcweir public HashMap getProtocolParameters() { 155cdf0e10cSrcweir return protocol.getPartParameters(); 156cdf0e10cSrcweir } 157cdf0e10cSrcweir 158cdf0e10cSrcweir /** 159cdf0e10cSrcweir * Returns the connection parameters as 160cdf0e10cSrcweir * a Hashmap with key/value pairs. Encoded 161cdf0e10cSrcweir * characters like '%41' are decoded. 162cdf0e10cSrcweir * 163cdf0e10cSrcweir * @return a HashMap with key/value pairs for connection parameters. 164cdf0e10cSrcweir */ getConnectionParameters()165cdf0e10cSrcweir public HashMap getConnectionParameters() { 166cdf0e10cSrcweir return connection.getPartParameters(); 167cdf0e10cSrcweir } 168cdf0e10cSrcweir 169cdf0e10cSrcweir /** 170cdf0e10cSrcweir * Returns the raw specification of the protocol 171cdf0e10cSrcweir * parameters. Encoded characters like '%41' are 172cdf0e10cSrcweir * not decoded. 173cdf0e10cSrcweir * 174cdf0e10cSrcweir * @return The uninterpreted protocol parameters as string. 175cdf0e10cSrcweir */ getProtocolParametersAsString()176cdf0e10cSrcweir public String getProtocolParametersAsString() { 177cdf0e10cSrcweir return protocol.getUninterpretedParameterString(); 178cdf0e10cSrcweir } 179cdf0e10cSrcweir 180cdf0e10cSrcweir /** 181cdf0e10cSrcweir * Returns the raw specification of the connection 182cdf0e10cSrcweir * parameters. Encoded characters like '%41' are 183cdf0e10cSrcweir * not decoded. 184cdf0e10cSrcweir * 185cdf0e10cSrcweir * @return The uninterpreted connection parameters as string. 186cdf0e10cSrcweir */ getConnectionParametersAsString()187cdf0e10cSrcweir public String getConnectionParametersAsString() { 188cdf0e10cSrcweir return connection.getUninterpretedParameterString(); 189cdf0e10cSrcweir } 190cdf0e10cSrcweir 191cdf0e10cSrcweir /** 192cdf0e10cSrcweir * Returns the raw specification of the protocol 193cdf0e10cSrcweir * name and parameters. Encoded characters like '%41' are 194cdf0e10cSrcweir * not decoded. 195cdf0e10cSrcweir * 196cdf0e10cSrcweir * @return The uninterpreted protocol name and parameters as string. 197cdf0e10cSrcweir */ getProtocolAndParametersAsString()198cdf0e10cSrcweir public String getProtocolAndParametersAsString() { 199cdf0e10cSrcweir return protocol.getUninterpretedString(); 200cdf0e10cSrcweir } 201cdf0e10cSrcweir 202cdf0e10cSrcweir /** 203cdf0e10cSrcweir * Returns the raw specification of the connection 204cdf0e10cSrcweir * name and parameters. Encoded characters like '%41' are 205cdf0e10cSrcweir * not decoded. 206cdf0e10cSrcweir * 207cdf0e10cSrcweir * @return The uninterpreted connection name and parameters as string. 208cdf0e10cSrcweir */ getConnectionAndParametersAsString()209cdf0e10cSrcweir public String getConnectionAndParametersAsString() { 210cdf0e10cSrcweir return connection.getUninterpretedString(); 211cdf0e10cSrcweir } 212cdf0e10cSrcweir hexToInt(int ch)213cdf0e10cSrcweir private static int hexToInt(int ch) 214cdf0e10cSrcweir throws com.sun.star.lang.IllegalArgumentException { 215cdf0e10cSrcweir int c = Character.toLowerCase((char) ch); 216cdf0e10cSrcweir boolean isDigit = ('0' <= c && c <= '9'); 217cdf0e10cSrcweir boolean isValidChar = ('a' <= c && c <= 'f') || isDigit; 218cdf0e10cSrcweir 219cdf0e10cSrcweir if (!isValidChar) 220cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException( 221cdf0e10cSrcweir "Invalid UTF-8 hex byte '" + c + "'."); 222cdf0e10cSrcweir 223cdf0e10cSrcweir return isDigit ? ch - '0' : 10 + ((char) c - 'a') & 0xF; 224cdf0e10cSrcweir } 225cdf0e10cSrcweir decodeUTF8(String s)226cdf0e10cSrcweir private static String decodeUTF8(String s) 227cdf0e10cSrcweir throws com.sun.star.lang.IllegalArgumentException { 228cdf0e10cSrcweir Vector v = new Vector(); 229cdf0e10cSrcweir 230cdf0e10cSrcweir for (int i = 0; i < s.length(); i++) { 231cdf0e10cSrcweir int ch = s.charAt(i); 232cdf0e10cSrcweir 233cdf0e10cSrcweir if (ch == '%') { 234cdf0e10cSrcweir int hb = hexToInt(s.charAt(++i)); 235cdf0e10cSrcweir int lb = hexToInt(s.charAt(++i)); 236cdf0e10cSrcweir ch = (hb << 4) | lb; 237cdf0e10cSrcweir } 238cdf0e10cSrcweir 239*5b5659a7SDamjan Jovanovic v.addElement(ch); 240cdf0e10cSrcweir } 241cdf0e10cSrcweir 242cdf0e10cSrcweir int size = v.size(); 243cdf0e10cSrcweir byte[] bytes = new byte[size]; 244cdf0e10cSrcweir for (int i = 0; i < size; i++) { 245cdf0e10cSrcweir Integer anInt = (Integer) v.elementAt(i); 246cdf0e10cSrcweir bytes[i] = (byte) (anInt.intValue() & 0xFF); 247cdf0e10cSrcweir } 248cdf0e10cSrcweir 249cdf0e10cSrcweir try { 250cdf0e10cSrcweir return new String(bytes, "UTF-8"); 251cdf0e10cSrcweir } catch (UnsupportedEncodingException e) { 252cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException( 253cdf0e10cSrcweir "Couldn't convert parameter string to UTF-8 string:" + e.getMessage()); 254cdf0e10cSrcweir } 255cdf0e10cSrcweir } 256cdf0e10cSrcweir buildParamHashMap(String paramString)257cdf0e10cSrcweir private static HashMap buildParamHashMap(String paramString) 258cdf0e10cSrcweir throws com.sun.star.lang.IllegalArgumentException { 259cdf0e10cSrcweir HashMap params = new HashMap(); 260cdf0e10cSrcweir 261cdf0e10cSrcweir int pos = 0; 262cdf0e10cSrcweir 263cdf0e10cSrcweir while (true) { 264cdf0e10cSrcweir char c = ','; 265cdf0e10cSrcweir String aKey = ""; 266cdf0e10cSrcweir String aValue = ""; 267cdf0e10cSrcweir 268cdf0e10cSrcweir while ((pos < paramString.length()) 269cdf0e10cSrcweir && ((c = paramString.charAt(pos++)) != '=')) { 270cdf0e10cSrcweir aKey += c; 271cdf0e10cSrcweir } 272cdf0e10cSrcweir 273cdf0e10cSrcweir while ((pos < paramString.length()) 274cdf0e10cSrcweir && ((c = paramString.charAt(pos++)) != ',') 275cdf0e10cSrcweir && c != ';') { 276cdf0e10cSrcweir aValue += c; 277cdf0e10cSrcweir } 278cdf0e10cSrcweir 279cdf0e10cSrcweir if ((aKey.length() > 0) && (aValue.length() > 0)) { 280cdf0e10cSrcweir 281cdf0e10cSrcweir if (!isAlphaNumeric(aKey)) { 282cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException( 283cdf0e10cSrcweir "The parameter key '" 284cdf0e10cSrcweir + aKey 285cdf0e10cSrcweir + "' may only consist of alpha numeric ASCII characters."); 286cdf0e10cSrcweir } 287cdf0e10cSrcweir 288cdf0e10cSrcweir if (!isValidString(aValue, VALUE_CHAR_SET + "%")) { 289cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException( 290cdf0e10cSrcweir "The parameter value for key '" + aKey + "' contains illegal characters."); 291cdf0e10cSrcweir } 292cdf0e10cSrcweir 293cdf0e10cSrcweir params.put(aKey, decodeUTF8(aValue)); 294cdf0e10cSrcweir } 295cdf0e10cSrcweir 296cdf0e10cSrcweir if ((pos >= paramString.length()) || (c != ',')) 297cdf0e10cSrcweir break; 298cdf0e10cSrcweir 299cdf0e10cSrcweir } 300cdf0e10cSrcweir 301cdf0e10cSrcweir return params; 302cdf0e10cSrcweir } 303cdf0e10cSrcweir parseUnoUrlPart(String thePart)304cdf0e10cSrcweir private static UnoUrlPart parseUnoUrlPart(String thePart) 305cdf0e10cSrcweir throws com.sun.star.lang.IllegalArgumentException { 306cdf0e10cSrcweir String partName = thePart; 307cdf0e10cSrcweir String theParamPart = ""; 308cdf0e10cSrcweir int index = thePart.indexOf(","); 309cdf0e10cSrcweir if (index != -1) { 310cdf0e10cSrcweir partName = thePart.substring(0, index).trim(); 311cdf0e10cSrcweir theParamPart = thePart.substring(index + 1).trim(); 312cdf0e10cSrcweir } 313cdf0e10cSrcweir 314cdf0e10cSrcweir if (!isAlphaNumeric(partName)) { 315cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException( 316cdf0e10cSrcweir "The part name '" 317cdf0e10cSrcweir + partName 318cdf0e10cSrcweir + "' may only consist of alpha numeric ASCII characters."); 319cdf0e10cSrcweir } 320cdf0e10cSrcweir 321cdf0e10cSrcweir HashMap params = buildParamHashMap(theParamPart); 322cdf0e10cSrcweir 323cdf0e10cSrcweir return new UnoUrlPart(theParamPart, partName, params); 324cdf0e10cSrcweir } 325cdf0e10cSrcweir isAlphaNumeric(String s)326cdf0e10cSrcweir private static boolean isAlphaNumeric(String s) { 327cdf0e10cSrcweir return isValidString(s, null); 328cdf0e10cSrcweir } 329cdf0e10cSrcweir isValidString(String identifier, String validCharSet)330cdf0e10cSrcweir private static boolean isValidString(String identifier, String validCharSet) { 331cdf0e10cSrcweir 332cdf0e10cSrcweir int len = identifier.length(); 333cdf0e10cSrcweir 334cdf0e10cSrcweir for (int i = 0; i < len; i++) { 335cdf0e10cSrcweir 336cdf0e10cSrcweir int ch = identifier.charAt(i); 337cdf0e10cSrcweir 338cdf0e10cSrcweir boolean isValidChar = 339cdf0e10cSrcweir ('A' <= ch && ch <= 'Z') 340cdf0e10cSrcweir || ('a' <= ch && ch <= 'z') 341cdf0e10cSrcweir || ('0' <= ch && ch <= '9'); 342cdf0e10cSrcweir 343cdf0e10cSrcweir if (!isValidChar && (validCharSet != null)) { 344cdf0e10cSrcweir isValidChar = (validCharSet.indexOf(ch) != -1); 345cdf0e10cSrcweir } 346cdf0e10cSrcweir 347cdf0e10cSrcweir if (!isValidChar) 348cdf0e10cSrcweir return false; 349cdf0e10cSrcweir } 350cdf0e10cSrcweir 351cdf0e10cSrcweir return true; 352cdf0e10cSrcweir } 353cdf0e10cSrcweir 354cdf0e10cSrcweir /** 355cdf0e10cSrcweir * Parses the given Uno Url and returns 356cdf0e10cSrcweir * an in memory object representation. 357cdf0e10cSrcweir * 358cdf0e10cSrcweir * @param unoUrl The given uno URl as string. 359cdf0e10cSrcweir * @return Object representation of class UnoUrl. 360cdf0e10cSrcweir * @throws IllegalArgumentException if Url cannot be parsed. 361cdf0e10cSrcweir */ parseUnoUrl(String unoUrl)362cdf0e10cSrcweir public static UnoUrl parseUnoUrl(String unoUrl) 363cdf0e10cSrcweir throws com.sun.star.lang.IllegalArgumentException { 364cdf0e10cSrcweir 365cdf0e10cSrcweir String url = unoUrl; 366cdf0e10cSrcweir 367cdf0e10cSrcweir int index = url.indexOf(':'); 368cdf0e10cSrcweir if (index != -1) { 369cdf0e10cSrcweir String unoStr = url.substring(0, index).trim(); 370cdf0e10cSrcweir if (!"uno".equals(unoStr)) { 371cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException( 372cdf0e10cSrcweir "Uno Urls must start with 'uno:'. " + FORMAT_ERROR); 373cdf0e10cSrcweir } 374cdf0e10cSrcweir } 375cdf0e10cSrcweir 376cdf0e10cSrcweir url = url.substring(index + 1).trim(); 377cdf0e10cSrcweir 378cdf0e10cSrcweir index = url.indexOf(';'); 379cdf0e10cSrcweir if (index == -1) { 380cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException("'"+unoUrl+"' is an invalid Uno Url. " + FORMAT_ERROR); 381cdf0e10cSrcweir } 382cdf0e10cSrcweir 383cdf0e10cSrcweir String connection = url.substring(0, index).trim(); 384cdf0e10cSrcweir url = url.substring(index + 1).trim(); 385cdf0e10cSrcweir 386cdf0e10cSrcweir UnoUrlPart connectionPart = parseUnoUrlPart(connection); 387cdf0e10cSrcweir 388cdf0e10cSrcweir index = url.indexOf(';'); 389cdf0e10cSrcweir if (index == -1) { 390cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException("'"+unoUrl+"' is an invalid Uno Url. " + FORMAT_ERROR); 391cdf0e10cSrcweir } 392cdf0e10cSrcweir 393cdf0e10cSrcweir String protocol = url.substring(0, index).trim(); 394cdf0e10cSrcweir url = url.substring(index + 1).trim(); 395cdf0e10cSrcweir 396cdf0e10cSrcweir UnoUrlPart protocolPart = parseUnoUrlPart(protocol); 397cdf0e10cSrcweir 398cdf0e10cSrcweir String rootOid = url.trim(); 399cdf0e10cSrcweir if (!isValidString(rootOid, OID_CHAR_SET)) { 400cdf0e10cSrcweir throw new com.sun.star.lang.IllegalArgumentException( 401cdf0e10cSrcweir "Root OID '"+ rootOid + "' contains illegal characters."); 402cdf0e10cSrcweir } 403cdf0e10cSrcweir 404cdf0e10cSrcweir return new UnoUrl(connectionPart, protocolPart, rootOid); 405cdf0e10cSrcweir 406cdf0e10cSrcweir } 407cdf0e10cSrcweir 408cdf0e10cSrcweir } 409