2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package com
.sun
.star
.lib
.uno
.helper
;
20 import java
.io
.UnsupportedEncodingException
;
21 import java
.nio
.ByteBuffer
;
22 import java
.util
.HashMap
;
25 * Object representation and parsing of Uno Urls,
26 * which allow to locate a named Uno object in a
27 * different process. An Uno Url consists of the
28 * specification of a connection, protocol and
29 * rootOid delimited with a ';'.
30 * The syntax of an Uno Url is
33 * [uno:]connection-type,parameters;protocol-name,parameters;objectname";
36 * An example Uno Url will look like this:
39 * socket,host=localhost,port=2002;urp;StarOffice.ServiceManager
42 * For more information about Uno Url please consult
43 * <a href="http://udk.openoffice.org/common/man/spec/uno-url.html">
44 * http://udk.openoffice.org/common/man/spec/uno-url.html</a>
49 * UnoUrl url = UnoUrl.parseUnoUrl("socket,host=localhost,port=2002;urp;StarOffice.ServiceManager");
54 private static final String FORMAT_ERROR
=
55 "syntax: [uno:]connection-type,parameters;protocol-name,parameters;objectname";
57 private static final String VALUE_CHAR_SET
= "!$&'()*+-./:?@_~";
58 private static final String OID_CHAR_SET
= VALUE_CHAR_SET
+ ",=";
60 private final UnoUrlPart connection
;
61 private final UnoUrlPart protocol
;
62 private final String rootOid
;
64 private static class UnoUrlPart
{
66 private final String partTypeName
;
67 private final HashMap
<String
,String
> partParameters
;
68 private final String uninterpretedParameterString
;
71 String uninterpretedParameterString
,
73 HashMap
<String
,String
> partParameters
) {
74 this.uninterpretedParameterString
= uninterpretedParameterString
;
75 this.partTypeName
= partTypeName
;
76 this.partParameters
= partParameters
;
79 public String
getPartTypeName() {
83 public HashMap
<String
,String
> getPartParameters() {
84 return partParameters
;
87 public String
getUninterpretedParameterString() {
88 return uninterpretedParameterString
;
91 public String
getUninterpretedString() {
92 StringBuffer buf
= new StringBuffer(partTypeName
);
93 if (uninterpretedParameterString
.length() > 0) {
95 buf
.append(uninterpretedParameterString
);
97 return buf
.toString();
102 UnoUrlPart connectionPart
,
103 UnoUrlPart protocolPart
,
105 this.connection
= connectionPart
;
106 this.protocol
= protocolPart
;
107 this.rootOid
= rootOid
;
111 * Returns the name of the connection of this
112 * Uno Url. Encoded characters are not allowed.
114 * @return The connection name as string.
116 public String
getConnection() {
117 return connection
.getPartTypeName();
121 * Returns the name of the protocol of this
122 * Uno Url. Encoded characters are not allowed.
124 * @return The protocol name as string.
126 public String
getProtocol() {
127 return protocol
.getPartTypeName();
131 * Return the object name. Encoded character are
134 * @return The object name as String.
136 public String
getRootOid() {
141 * Returns the protocol parameters as
142 * a Hashmap with key/value pairs. Encoded
143 * characters like '%41' are decoded.
145 * @return a HashMap with key/value pairs for protocol parameters.
147 public HashMap
<String
,String
> getProtocolParameters() {
148 return protocol
.getPartParameters();
152 * Returns the connection parameters as
153 * a Hashmap with key/value pairs. Encoded
154 * characters like '%41' are decoded.
156 * @return a HashMap with key/value pairs for connection parameters.
158 public HashMap
<String
,String
> getConnectionParameters() {
159 return connection
.getPartParameters();
163 * Returns the raw specification of the protocol
164 * parameters. Encoded characters like '%41' are
167 * @return The uninterpreted protocol parameters as string.
169 public String
getProtocolParametersAsString() {
170 return protocol
.getUninterpretedParameterString();
174 * Returns the raw specification of the connection
175 * parameters. Encoded characters like '%41' are
178 * @return The uninterpreted connection parameters as string.
180 public String
getConnectionParametersAsString() {
181 return connection
.getUninterpretedParameterString();
185 * Returns the raw specification of the protocol
186 * name and parameters. Encoded characters like '%41' are
189 * @return The uninterpreted protocol name and parameters as string.
191 public String
getProtocolAndParametersAsString() {
192 return protocol
.getUninterpretedString();
196 * Returns the raw specification of the connection
197 * name and parameters. Encoded characters like '%41' are
200 * @return The uninterpreted connection name and parameters as string.
202 public String
getConnectionAndParametersAsString() {
203 return connection
.getUninterpretedString();
206 private static String
decodeUTF8(String s
)
207 throws com
.sun
.star
.lang
.IllegalArgumentException
{
209 if (!s
.contains("%")) {
213 int length
= s
.length();
214 ByteBuffer bb
= ByteBuffer
.allocate(length
);
215 for (int i
= 0; i
< length
; i
++) {
216 int ch
= s
.charAt(i
);
220 throw new com
.sun
.star
.lang
.IllegalArgumentException(
221 "Incomplete trailing escape (%) pattern");
223 ch
= Integer
.parseInt(s
.substring(i
+1,i
+3),16);
224 } catch (NumberFormatException e
) {
225 throw new com
.sun
.star
.lang
.IllegalArgumentException(e
);
228 throw new com
.sun
.star
.lang
.IllegalArgumentException(
229 "Illegal hex characters in escape (%) pattern - negative value");
233 bb
.put((byte) (ch
& 0xFF));
236 byte[] bytes
= new byte[bb
.position()];
237 System
.arraycopy(bb
.array(), 0, bytes
, 0, bytes
.length
);
238 return new String(bytes
, "UTF-8");
239 } catch (UnsupportedEncodingException e
) {
240 throw new com
.sun
.star
.lang
.IllegalArgumentException(e
,
241 "Couldn't convert parameter string to UTF-8 string");
245 private static HashMap
<String
,String
> buildParamHashMap(String paramString
)
246 throws com
.sun
.star
.lang
.IllegalArgumentException
{
247 HashMap
<String
,String
> params
= new HashMap
<String
,String
>();
254 StringBuffer sb
= new StringBuffer();
255 while ((pos
< paramString
.length())
256 && ((c
= paramString
.charAt(pos
++)) != '=')) {
259 String aKey
= sb
.toString();
261 sb
= new StringBuffer();
262 while ((pos
< paramString
.length())
263 && ((c
= paramString
.charAt(pos
++)) != ',')
267 String aValue
= sb
.toString();
269 if ((aKey
.length() > 0) && (aValue
.length() > 0)) {
271 if (!isAlphaNumeric(aKey
)) {
272 throw new com
.sun
.star
.lang
.IllegalArgumentException(
273 "The parameter key '"
275 + "' may only consist of alpha numeric ASCII characters.");
278 if (!isValidString(aValue
, VALUE_CHAR_SET
+ "%")) {
279 throw new com
.sun
.star
.lang
.IllegalArgumentException(
280 "The parameter value for key '" + aKey
+ "' contains illegal characters.");
283 params
.put(aKey
, decodeUTF8(aValue
));
286 if ((pos
>= paramString
.length()) || (c
!= ','))
294 private static UnoUrlPart
parseUnoUrlPart(String thePart
)
295 throws com
.sun
.star
.lang
.IllegalArgumentException
{
298 int index
= thePart
.indexOf(',');
300 partName
= thePart
.substring(0, index
).trim();
301 theParamPart
= thePart
.substring(index
+ 1).trim();
307 if (!isAlphaNumeric(partName
)) {
308 throw new com
.sun
.star
.lang
.IllegalArgumentException(
311 + "' may only consist of alpha numeric ASCII characters.");
314 HashMap
<String
,String
> params
= buildParamHashMap(theParamPart
);
316 return new UnoUrlPart(theParamPart
, partName
, params
);
319 private static boolean isAlphaNumeric(String s
) {
320 return isValidString(s
, null);
323 private static boolean isValidString(String identifier
, String validCharSet
) {
325 int len
= identifier
.length();
327 for (int i
= 0; i
< len
; i
++) {
329 int ch
= identifier
.charAt(i
);
331 boolean isValidChar
=
332 ('A' <= ch
&& ch
<= 'Z')
333 || ('a' <= ch
&& ch
<= 'z')
334 || ('0' <= ch
&& ch
<= '9');
336 if (!isValidChar
&& (validCharSet
!= null)) {
337 isValidChar
= (validCharSet
.indexOf(ch
) != -1);
348 * Parses the given Uno Url and returns
349 * an in memory object representation.
351 * @param unoUrl The given uno URl as string.
352 * @return Object representation of class UnoUrl.
353 * @throws IllegalArgumentException if Url cannot be parsed.
355 public static UnoUrl
parseUnoUrl(String unoUrl
)
356 throws com
.sun
.star
.lang
.IllegalArgumentException
{
360 int index
= url
.indexOf(':');
362 String unoStr
= url
.substring(0, index
).trim();
363 if (!"uno".equals(unoStr
)) {
364 throw new com
.sun
.star
.lang
.IllegalArgumentException(
365 "Uno Urls must start with 'uno:'. " + FORMAT_ERROR
);
369 url
= url
.substring(index
+ 1).trim();
371 index
= url
.indexOf(';');
373 throw new com
.sun
.star
.lang
.IllegalArgumentException("'"+unoUrl
+"' is an invalid Uno Url. " + FORMAT_ERROR
);
376 String connection
= url
.substring(0, index
).trim();
377 url
= url
.substring(index
+ 1).trim();
379 UnoUrlPart connectionPart
= parseUnoUrlPart(connection
);
381 index
= url
.indexOf(';');
383 throw new com
.sun
.star
.lang
.IllegalArgumentException("'"+unoUrl
+"' is an invalid Uno Url. " + FORMAT_ERROR
);
386 String protocol
= url
.substring(0, index
).trim();
387 url
= url
.substring(index
+ 1).trim();
389 UnoUrlPart protocolPart
= parseUnoUrlPart(protocol
);
391 String rootOid
= url
.trim();
392 if (!isValidString(rootOid
, OID_CHAR_SET
)) {
393 throw new com
.sun
.star
.lang
.IllegalArgumentException(
394 "Root OID '"+ rootOid
+ "' contains illegal characters.");
397 return new UnoUrl(connectionPart
, protocolPart
, rootOid
);