blob: 6207c4f413c5878c4735949fdcde0c50937899c4 [file] [log] [blame]
Richard S. Hall930fecc2005-08-16 18:33:34 +00001/*
2 * $Header: /cvshome/build/org.osgi.service.condpermadmin/src/org/osgi/service/condpermadmin/ConditionInfo.java,v 1.6 2005/05/13 20:33:31 hargrave Exp $
3 *
4 * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
5 *
6 * This program and the accompanying materials are made available under the
7 * terms of the Eclipse Public License v1.0 which accompanies this
8 * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
9 */
10
11package org.osgi.service.condpermadmin;
12
13import java.util.Vector;
14
15/**
16 * Condition representation used by the Conditional Permission Admin service.
17 *
18 * <p>
19 * This class encapsulates two pieces of information: a Condition <i>type</i>
20 * (class name), which must implement <tt>Condition</tt>, and the arguments
21 * passed to its constructor.
22 *
23 * <p>
24 * In order for a Condition represented by a <tt>ConditionInfo</tt> to be
25 * instantiated and considered during a permission check, its Condition class
26 * must be available from the system classpath.
27 *
28 */
29
30public class ConditionInfo {
31
32 private String type;
33
34 private String args[];
35
36 /**
37 * Constructs a <tt>ConditionInfo</tt> from the given type and args.
38 *
39 * @param type
40 * The fully qualified class name of the condition represented by
41 * this <tt>ConditionInfo</tt>. The class must implement
42 * <tt>Condition</tt> and must define a constructor that takes
43 * a <tt>Bundle</tt> and the correct number of argument
44 * strings.
45 *
46 * @param args
47 * The arguments that will be passed to the constructor of the
48 * <tt>Conditon</tt> class identified by <tt>type</tt>.
49 *
50 * @exception java.lang.NullPointerException
51 * if <tt>type</tt> is <tt>null</tt>.
52 */
53 public ConditionInfo(String type, String args[]) {
54 this.type = type;
55 this.args = args;
56 if (type == null) {
57 throw new NullPointerException("type is null");
58 }
59 }
60
61 /**
62 * Constructs a <tt>ConditionInfo</tt> object from the given encoded
63 * <tt>ConditionInfo</tt> string.
64 *
65 * @param encodedCondition
66 * The encoded <tt>ConditionInfo</tt>.
67 * @see #getEncoded
68 * @exception java.lang.IllegalArgumentException
69 * if <tt>encodedCondition</tt> is not properly formatted.
70 */
71 public ConditionInfo(String encodedCondition) {
72 if (encodedCondition == null) {
73 throw new NullPointerException("missing encoded permission");
74 }
75 if (encodedCondition.length() == 0) {
76 throw new IllegalArgumentException("empty encoded permission");
77 }
78
79 try {
80 char[] encoded = encodedCondition.toCharArray();
81
82 /* the first character must be '[' */
83 if (encoded[0] != '[') {
84 throw new IllegalArgumentException(
85 "first character not open bracket");
86 }
87
88 /* type is not quoted or encoded */
89 int end = 1;
90 int begin = end;
91
92 while ((encoded[end] != ' ') && (encoded[end] != ')')) {
93 end++;
94 }
95
96 if (end == begin) {
97 throw new IllegalArgumentException("expecting type");
98 }
99
100 this.type = new String(encoded, begin, end - begin);
101
102 Vector args = new Vector();
103 /* type may be followed by name which is quoted and encoded */
104 while (encoded[end] == ' ') {
105 end++;
106
107 if (encoded[end] != '"') {
108 throw new IllegalArgumentException("expecting quoted name");
109 }
110
111 end++;
112 begin = end;
113
114 while (encoded[end] != '"') {
115 if (encoded[end] == '\\') {
116 end++;
117 }
118
119 end++;
120 }
121
122 args.add(decodeString(encoded, begin, end));
123 end++;
124 }
125 this.args = (String[]) args.toArray(new String[0]);
126 /* the final character must be ')' */
127 if ((encoded[end] != ']') || (end + 1 != encoded.length)) {
128 throw new IllegalArgumentException("last character not "
129 + "close bracket");
130 }
131 } catch (ArrayIndexOutOfBoundsException e) {
132 throw new IllegalArgumentException("parsing terminated abruptly");
133 }
134 }
135
136 /**
137 * Returns the string encoding of this <tt>ConditionInfo</tt> in a form
138 * suitable for restoring this <tt>ConditionInfo</tt>.
139 *
140 * <p>
141 * The encoding format is:
142 *
143 * <pre>
144 *
145 * [type &quot;arg0&quot; &quot;arg1&quot; ...]
146 *
147 * </pre>
148 *
149 * where <i>argX</i> are strings that are encoded for proper parsing.
150 * Specifically, the <tt>"</tt>, <tt>\</tt>, carriage return, and
151 * linefeed characters are escaped using <tt>\"</tt>, <tt>\\</tt>,
152 * <tt>\r</tt>, and <tt>\n</tt>, respectively.
153 *
154 * <p>
155 * The encoded string must contain no leading or trailing whitespace
156 * characters. A single space character must be used between type and "<i>arg0</i>"
157 * and between all arguments.
158 *
159 * @return The string encoding of this <tt>ConditionInfo</tt>.
160 */
161 public final String getEncoded() {
162 StringBuffer output = new StringBuffer();
163 output.append('[');
164 output.append(type);
165
166 for (int i = 0; i < args.length; i++) {
167 output.append(" \"");
168 encodeString(args[i], output);
169 output.append('\"');
170 }
171
172 output.append(']');
173
174 return (output.toString());
175 }
176
177 /**
178 * Returns the string representation of this <tt>ConditionInfo</tt>. The
179 * string is created by calling the <tt>getEncoded</tt> method on this
180 * <tt>ConditionInfo</tt>.
181 *
182 * @return The string representation of this <tt>ConditionInfo</tt>.
183 */
184 public String toString() {
185 return (getEncoded());
186 }
187
188 /**
189 * Returns the fully qualified class name of the condition represented by
190 * this <tt>ConditionInfo</tt>.
191 *
192 * @return The fully qualified class name of the condition represented by
193 * this <tt>ConditionInfo</tt>.
194 */
195 public final String getType() {
196 return (type);
197 }
198
199 /**
200 * Returns arguments of this <tt>ConditionInfo</tt>.
201 *
202 * @return The arguments of this <tt>ConditionInfo</tt>. have a name.
203 */
204 public final String[] getArgs() {
205 return (args);
206 }
207
208 /**
209 * Determines the equality of two <tt>ConditionInfo</tt> objects.
210 *
211 * This method checks that specified object has the same type and args as
212 * this <tt>ConditionInfo</tt> object.
213 *
214 * @param obj
215 * The object to test for equality with this
216 * <tt>ConditionInfo</tt> object.
217 * @return <tt>true</tt> if <tt>obj</tt> is a <tt>ConditionInfo</tt>,
218 * and has the same type and args as this <tt>ConditionInfo</tt>
219 * object; <tt>false</tt> otherwise.
220 */
221 public boolean equals(Object obj) {
222 if (obj == this) {
223 return (true);
224 }
225
226 if (!(obj instanceof ConditionInfo)) {
227 return (false);
228 }
229
230 ConditionInfo other = (ConditionInfo) obj;
231
232 if (!type.equals(other.type) || args.length != other.args.length)
233 return false;
234
235 for (int i = 0; i < args.length; i++) {
236 if (!args[i].equals(other.args[i]))
237 return false;
238 }
239 return true;
240 }
241
242 /**
243 * Returns the hash code value for this object.
244 *
245 * @return A hash code value for this object.
246 */
247
248 public int hashCode() {
249 int hash = type.hashCode();
250
251 for (int i = 0; i < args.length; i++) {
252 hash ^= args[i].hashCode();
253 }
254 return (hash);
255 }
256
257 /**
258 * This escapes the quotes, backslashes, \n, and \r in the string using a
259 * backslash and appends the newly escaped string to a StringBuffer.
260 */
261 private static void encodeString(String str, StringBuffer output) {
262 int len = str.length();
263
264 for (int i = 0; i < len; i++) {
265 char c = str.charAt(i);
266
267 switch (c) {
268 case '"':
269 case '\\':
270 output.append('\\');
271 output.append(c);
272 break;
273 case '\r':
274 output.append("\\r");
275 break;
276 case '\n':
277 output.append("\\n");
278 break;
279 default:
280 output.append(c);
281 break;
282 }
283 }
284 }
285
286 /**
287 * Takes an encoded character array and decodes it into a new String.
288 */
289 private static String decodeString(char[] str, int begin, int end) {
290 StringBuffer output = new StringBuffer(end - begin);
291
292 for (int i = begin; i < end; i++) {
293 char c = str[i];
294
295 if (c == '\\') {
296 i++;
297
298 if (i < end) {
299 c = str[i];
300
301 if (c == 'n') {
302 c = '\n';
303 } else if (c == 'r') {
304 c = '\r';
305 }
306 }
307 }
308
309 output.append(c);
310 }
311
312 return (output.toString());
313 }
314}