1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 1999 by Sun Microsystems, Inc.
23  * All rights reserved.
24  *
25  */
26 
27 //  ServiceType.java: Model a service type.
28 //  Author:           James Kempf
29 //  Created On:       Thu Apr  9 09:23:18 1998
30 //  Last Modified By: James Kempf
31 //  Last Modified On: Mon Oct 19 15:43:18 1998
32 //  Update Count:     33
33 //
34 
35 package com.sun.slp;
36 
37 import java.util.*;
38 import java.io.*;
39 
40 
41 /**
42  * The ServiceType class conceals the complex details of whether a
43  * service type name is a simple URL scheme identifier, a service:
44  * type, an abstract type or protocol type.
45  *
46  * @author James Kempf
47  */
48 
49 public class ServiceType extends Object implements Serializable {
50 
51     boolean isServiceURL = true;	// was it originally a service: type?
52     private String type1 = "";	// scheme, abstract, or protocol.
53     private String type2 = "";	// concrete, if type was abstract.
54     private String na = "";	// naming authority.
55 
56     // For removing IANA.
57 
58     static final String IANA = "iana";
59 
60     /**
61      * Create a service type object from the type name. The name may
62      * take the form of any valid SLP service type name.
63      *
64      * @param t The type name.
65      * @return The ServiceType object.
66      * @exception IllegalArgumentException If the name is syntactically
67      *					 incorrect.
68      */
69 
ServiceType(String t)70     public ServiceType(String t) throws IllegalArgumentException {
71 
72 	parse(t);
73 
74     }
75 
76     /**
77      * Return true if type name was from a service: URL.
78      *
79      * @return True if type name came from service: URL.
80      */
81 
isServiceURL()82     public boolean isServiceURL() {
83 	return isServiceURL;
84 
85     }
86 
87     /**
88      * Return true if type name is for an abstract type.
89      *
90      * @return True if type name is for an abstract type.
91      */
92 
isAbstractType()93     public boolean isAbstractType() {
94 	return (type2.length() > 0);
95 
96     }
97 
98     /**
99      * Return true if naming authority is default.
100      *
101      * @return True if naming authority is default.
102      */
103 
isNADefault()104     public boolean isNADefault() {
105 	return (na.length() <= 0);
106 
107     }
108 
109     /**
110      * Return the concrete service type name without naming authority.
111      *
112      * @return concrete type name.
113      */
114 
getConcreteTypeName()115     public String getConcreteTypeName() {
116 	return type2;
117 
118     }
119 
120     /**
121      * Return the principle type name, which is either the abstract
122      * type name or the protocol name, without naming authority.
123      *
124      * @return Principle type name.
125      */
126 
getPrincipleTypeName()127     public String getPrincipleTypeName() {
128 	return type1;
129 
130     }
131 
132     /**
133      * Return the fully formatted abstract type name, if it is an abstract
134      * type, otherwise the empty string.
135      */
136 
getAbstractTypeName()137     public String getAbstractTypeName() {
138 	if (isAbstractType()) {
139 	    return "service:" + type1 + (na.length() > 0 ? ("." + na):"");
140 
141 	}
142 	return "";
143 
144     }
145 
146     /**
147      * Return the naming authority name.
148      *
149      * @return Naming authority name.
150      */
151 
getNamingAuthority()152     public String getNamingAuthority() {
153 	return na;
154 
155     }
156 
157     /**
158      *Validate a naming authority name.
159      */
160 
validateTypeComponent(String name)161     static void validateTypeComponent(String name)
162 	throws ServiceLocationException {
163 
164 	validateTypeComponentInternal(name, false);
165     }
166 
167     // Validate, allowing '.' if allowDot is true.
168 
169     static private void
validateTypeComponentInternal(String name, boolean allowDot)170 	validateTypeComponentInternal(String name, boolean allowDot)
171 	throws ServiceLocationException {
172 	int i, n = name.length();
173 
174 	for (i = 0; i < n; i++) {
175 	    char c = name.charAt(i);
176 
177 	    if ((Character.isLetterOrDigit(c) == false) &&
178 		(c != '+') && (c != '-')) {
179 		boolean throwIt = true;
180 
181 		// If dot is allowed, don't throw it.
182 
183 		if (allowDot && (c == '.')) {
184 		    throwIt = false;
185 
186 		}
187 
188 		if (throwIt) {
189 		    throw
190 			new IllegalArgumentException(
191 	SLPConfig.getSLPConfig().formatMessage("service_type_syntax",
192 					       new Object[] {name}));
193 		}
194 	    }
195 	}
196     }
197 
198     // Two service type names are equal if they have the same
199     //  types, naming authority, and same service: flag.
200 
equals(Object o)201     public boolean equals(Object o) {
202 
203 	if (o == this) {
204 	    return true;
205 
206 	}
207 
208 	if (!(o instanceof ServiceType)) {
209 	    return false;
210 
211 	}
212 
213 	ServiceType type = (ServiceType)o;
214 
215 	return
216 	    (isServiceURL == type.isServiceURL) &&
217 	    type1.equals(type.type1) &&
218 	    type2.equals(type.type2) &&
219 	    na.equals(type.na);
220 
221     }
222 
223     // Format the service type name for output.
224 
toString()225     public String toString() {
226 
227 	return
228 	    (isServiceURL ? "service:" : "") +
229 	    type1 +
230 	    (na.length() > 0 ? ("." + na) : "") +
231 	    (type2.length() > 0 ? (":" + type2) : "");
232 
233     }
234 
235     // Return a hash code for the type.
236 
hashCode()237     public int hashCode() {
238 
239 	return type1.hashCode() +
240 	    na.hashCode() +
241 	    type2.hashCode() +
242 	    (isServiceURL ? Defaults.SERVICE_PREFIX.hashCode():0);
243 
244     }
245 
246     // Parse a service type name with optional naming authority.
247 
parse(String t)248     private void parse(String t) {
249 	StringTokenizer st = new StringTokenizer(t, ":.", true);
250 
251 	try {
252 
253 	    // This loop is a kludgy way to break out of the parse so
254 	    //  we only throw at one location in the code.
255 
256 	    do {
257 
258 		String tok = st.nextToken();
259 
260 		if (tok.equals(":") || tok.equals(".")) {
261 		    break;  // error!
262 
263 		}
264 
265 		// Look for a nonservice: URL.
266 
267 		if (!tok.equalsIgnoreCase(Defaults.SERVICE_PREFIX)) {
268 		    isServiceURL = false;
269 
270 		    // Need to eat through all dots.
271 
272 		    do {
273 			type1 = type1 + tok.toLowerCase();
274 
275 			// Break when we run out of tokens.
276 
277 			if (!st.hasMoreTokens()) {
278 			    break;
279 
280 			}
281 
282 			tok = st.nextToken();
283 
284 		    } while (true);
285 
286 		    // Check for disallowed characters. Allow '.'.
287 
288 		    validateTypeComponentInternal(type1, true);
289 
290 		    // There should be no more tokens.
291 
292 		    if (st.hasMoreTokens()) {
293 			break; // error!
294 
295 		    }
296 
297 		    return; // done!
298 
299 		}
300 
301 		tok = st.nextToken();
302 
303 		if (!tok.equals(":")) {
304 		    break; // error!
305 
306 		}
307 
308 		// Get the protocol or abstract type name.
309 
310 		type1 = st.nextToken().toLowerCase();
311 
312 		validateTypeComponent(type1);
313 
314 		// From here on in, everything is optional, so be sure
315 		//  to check for no remaining tokens.
316 
317 		if (!st.hasMoreTokens()) {
318 		    return;
319 		// done! It's a simple protocol type w.o. naming authority.
320 
321 		}
322 
323 		// It's either got a naming authority or is an abstract
324 		//  type (or both).
325 
326 		tok = st.nextToken();
327 
328 		// Check for naming authorithy.
329 
330 		if (tok.equals(".")) {
331 		    tok = st.nextToken();
332 
333 		    validateTypeComponent(tok);
334 
335 		    if (!tok.equalsIgnoreCase(IANA)) {
336 
337 			na = tok.toLowerCase();
338 
339 		    } else {
340 
341 			// Error to have IANA.
342 
343 			break;
344 
345 		    }
346 
347 		    if (!st.hasMoreTokens()) {
348 			return;
349 		// done! It's a simple protocol type w. naming authority.
350 
351 		    }
352 
353 		    tok = st.nextToken();
354 
355 		}
356 
357 		// Should be at the separator to concrete type.
358 
359 		if (!tok.equals(":")) {
360 		    break; // error!
361 
362 		}
363 
364 		tok = st.nextToken();
365 
366 		// This is the concrete type name.
367 
368 		validateTypeComponent(tok);
369 
370 		type2 = tok.toLowerCase();
371 
372 		// Should be no more tokens.
373 
374 		if (st.hasMoreTokens()) {
375 		    break; // error!
376 
377 		}
378 
379 		return; // done!
380 
381 	    } while (false);
382 
383 	} catch (NoSuchElementException ex) {
384 	    throw
385 		new IllegalArgumentException(
386 		SLPConfig.getSLPConfig().formatMessage("service_type_syntax",
387 						       new Object[] {t}));
388 
389 	} catch (ServiceLocationException ex) {
390 	    throw
391 		new IllegalArgumentException(ex.getMessage());
392 
393 	}
394 
395 	throw
396 	    new IllegalArgumentException(
397 		SLPConfig.getSLPConfig().formatMessage("service_type_syntax",
398 						       new Object[] {t}));
399 
400     }
401 
402 }
403