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 //  SLPTemplateRegistry.java: Service object for registering a new service
28 //			  template.
29 //  Author:           James Kempf
30 //  Created On:       Tue May 27 15:04:35 1997
31 //  Last Modified By: James Kempf
32 //  Last Modified On: Thu Jan  7 14:25:20 1999
33 //  Update Count:     134
34 //
35 
36 package com.sun.slp;
37 
38 import java.util.*;
39 
40 /**
41  * The SLPTemplateRegistry class registers and unregisters service templates,
42  * looks up the template based on the service type name, and returns an
43  * attribute verifier for the service.It subclasses the TemplateRegistry
44  * abstract class.
45  *
46  * An slp-template URL has the following format:
47  *
48  *   service:slp-template:<document URL>;type=<service type>;
49  *				          version=<version no.>;
50  *					  language=<language locale>
51  *
52  * @author James Kempf
53  *
54  */
55 
56 class SLPTemplateRegistry extends TemplateRegistry {
57 
58     /**
59      * Attribute id for attribute describing service type name.
60      * String, single valued attribute.
61      */
62 
63     static final String SERVICE_ATTR_ID = "template-type";
64 
65     /**
66      * Attribute id for attribute describing help text.
67      * String, single valued, required attribute, .
68      */
69 
70     static final String DESCRIPTION_ATTR_ID = "template-description";
71 
72     /**
73      * Attribute id for attribute describing service version. The
74      * version number is of the form ``n.m'', where n and m are integers.
75      * String, single valued, required attribute.
76      */
77 
78     static final String VERSION_ATTR_ID = "template-version";
79 
80     /**
81      * Attribute id for attribute describing service URL url part grammer.
82      * String, single valued, required attribute.
83      */
84 
85     static final String SERVICE_URL_ATTR_ID = "template-url-syntax";
86 
87     /**
88      * The service type name for the template type.
89      */
90 
91     static final String TEMPLATE_SERVICE_TYPE = "service:slp-template";
92 
93     // The distinguished template registry object.
94 
95     private static TemplateRegistry registry = null;
96 
97     // Package private constructor for singleton pattern maintained
98     // by the ServiceLocationManager.
99 
SLPTemplateRegistry()100     SLPTemplateRegistry() throws ServiceLocationException {
101 
102     }
103 
104     //
105     // Public implementation.
106     //
107 
108     /**
109      * Register the new service.
110      *
111      * @param serviceType	Name of the service.
112      * @param documentURL	URL of the template document.
113      * @param languageLocale	Locale of the template langugae.
114      * @param version		Version number of template document.
115      * @exception ServiceLocationException Error code is
116      *				    INVALID_REGISTRATION
117      *					   if the service already exists or
118      *					   the registration fails.
119      *					   Throws
120      *				    SYSTEM_ERROR
121      *					   if the scope vector is null or
122      *					   empty.
123      *					   Throws
124      *				    PARSE_ERROR
125      *					   if an attribute is bad.
126      * @exception IllegalArgumentException Thrown if any parameters are null.
127      *
128      */
129 
registerServiceTemplate(ServiceType serviceType, String documentURL, Locale languageLocale, String version)130     public void registerServiceTemplate(ServiceType serviceType,
131 					String documentURL,
132 					Locale languageLocale,
133 					String version)
134 	throws ServiceLocationException {
135 
136 	// Check for illegal parameters.
137 
138 	Assert.nonNullParameter(serviceType, "serviceType");
139 
140 	Assert.nonNullParameter(documentURL, "documentURL");
141 
142 	Assert.nonNullParameter(languageLocale, "language");
143 
144 	Assert.nonNullParameter(version, "version");
145 
146 	String language = languageLocale.getLanguage();
147 
148 	if (language == null || language.length() <= 0) {
149 	    throw
150 		new IllegalArgumentException(
151 		SLPConfig.getSLPConfig().formatMessage("template_lang_null",
152 						       new Object[] {
153 		    documentURL}));
154 	}
155 
156 	String turl = null;
157 
158 	try {
159 
160 	    turl = findTemplateURL(serviceType,
161 				   languageLocale,
162 				   version);
163 
164 	} catch (ServiceLocationException ex) {
165 
166 	    // Ignore if language not supported, it just means there
167 	    //  isn't any.
168 
169 	    if (ex.getErrorCode() !=
170 		ServiceLocationException.LANGUAGE_NOT_SUPPORTED) {
171 		throw ex;
172 
173 	    }
174 	}
175 
176 	// Throw an exception if it exists.
177 
178 	if (turl != null) {
179 	    throw
180 		new ServiceLocationException(
181 				ServiceLocationException.INVALID_REGISTRATION,
182 				"template_already_registered",
183 				new Object[] {
184 		    documentURL,
185 			version,
186 			languageLocale});
187 	}
188 
189 	// Construct attributes for the registration.
190 
191 	Vector attributes = new Vector();
192 
193 	// Add the service type name.
194 
195 	Vector values = new Vector();
196 	values.addElement(serviceType.toString());
197 	ServiceLocationAttribute attr =
198 	    new ServiceLocationAttribute(SERVICE_ATTR_ID, values);
199 
200 	attributes.addElement(attr);
201 
202 	// Add the version.
203 
204 	values = new Vector();
205 	values.addElement(version);
206 	attr =
207 	    new ServiceLocationAttribute(VERSION_ATTR_ID, values);
208 
209 	attributes.addElement(attr);
210 
211 	// Construct a service URL for the template.
212 
213 	ServiceURL surl =
214 	    new ServiceURL(TEMPLATE_SERVICE_TYPE +
215 			   ":"+
216 			   documentURL+
217 			   ";"+
218 			   SERVICE_ATTR_ID+
219 			   "="+
220 			   serviceType+
221 			   ";"+
222 			   VERSION_ATTR_ID+
223 			   "="+
224 			   version,
225 			   ServiceURL.LIFETIME_MAXIMUM);
226 
227 
228 	// Do the registration.
229 
230 	Advertiser serviceAgent =
231 	    ServiceLocationManager.getAdvertiser(languageLocale);
232 
233 	if (serviceAgent == null) {
234 	    throw
235 		new ServiceLocationException(
236 				ServiceLocationException.NOT_IMPLEMENTED,
237 				"no_advertiser",
238 				new Object[0]);
239 	}
240 
241 	serviceAgent.register(surl, attributes);
242 
243 	// Note that the assumption here is that the URL containing the
244 	//  path to the template document is written "somehow".
245 	//  It is up to the client to make sure that the template document
246 	//  has been written.
247 
248     }
249 
250     /**
251      * Deregister the template for service type.
252      *
253      * @param serviceType	Name of service.
254      * @param <i>languageLocale</i> Language locale of template.
255      * @param <i>version</i> Version of the template, null for latest.
256      * @exception ServiceLocationException Thrown if the deregistration
257      *					  fails.
258      * @exception IllegalArgumentException Thrown if the parameter is null.
259      *
260      */
261 
deregisterServiceTemplate(ServiceType serviceType, Locale languageLocale, String version)262     public void deregisterServiceTemplate(ServiceType serviceType,
263 					  Locale languageLocale,
264 					  String version)
265 	throws ServiceLocationException {
266 
267 	// Check the parameter.
268 
269 	Assert.nonNullParameter(serviceType, "serviceType");
270 
271 	Assert.nonNullParameter(languageLocale, "languageLocale");
272 
273 	// Get the template document URL for the service.
274 
275 	ServiceURL turl = findVersionedURL(serviceType,
276 					   languageLocale,
277 					   version);
278 
279 	// If there's no template, then throw an exception.
280 
281 	if (turl == null) {
282 	    throw
283 		new ServiceLocationException(
284 				ServiceLocationException.INVALID_REGISTRATION,
285 				"template_not_registered",
286 				new Object[] {
287 		    serviceType,
288 			version,
289 			languageLocale});
290 	}
291 
292 	// Deregister in all scopes.
293 
294 	Advertiser serviceAgent =
295 	    ServiceLocationManager.getAdvertiser(languageLocale);
296 
297 	if (serviceAgent == null) {
298 	    throw
299 		new ServiceLocationException(
300 				ServiceLocationException.NOT_IMPLEMENTED,
301 				"no_advertiser",
302 				new Object[0]);
303 	}
304 
305 	// Deregister the service URL.
306 
307 	serviceAgent.deregister(turl);
308 
309     }
310 
311 
312 
313     /**
314      * Find the service URL for the service.
315      *
316      * @param serviceType		Name of service.
317      * @param <i>languageLocale</i> Language locale of template.
318      * @param <i>version</i> Version of the template, null for latest.
319      * @return ServiceURL for the service template. If the service doesn't
320      *		exist, returns null.
321      * @exception ServiceLocationException Error code is
322      *				    SYSTEM_ERROR
323      *					   if the scope vector is null or
324      *					   empty or if more than one
325      *					   template URL is returned.
326      * @exception IllegalArgumentException Thrown if any parameters are null.
327      *
328      */
329 
findTemplateURL(ServiceType serviceType, Locale languageLocale, String version)330     public String findTemplateURL(ServiceType serviceType,
331 				  Locale languageLocale,
332 				  String version)
333 	throws ServiceLocationException {
334 
335 	// Check the parameter.
336 
337 	Assert.nonNullParameter(serviceType, "serviceType");
338 
339 	Assert.nonNullParameter(languageLocale, "languageLocale");
340 
341 	ServiceURL turl = findVersionedURL(serviceType,
342 					   languageLocale,
343 					   version);
344 
345 	// If nothing returned, then simply return.
346 
347 	if (turl == null) {
348 	    return null;
349 
350 	}
351 
352 	// Form the document URL.
353 
354 	ServiceType type = turl.getServiceType();
355 	String url = turl.toString();
356 	String abstractType = type.getAbstractTypeName();
357 
358 	if (!abstractType.equals(TEMPLATE_SERVICE_TYPE)) {
359 	    throw
360 		new ServiceLocationException(
361 				ServiceLocationException.PARSE_ERROR,
362 				"template_url_malformed",
363 				new Object[] {turl});
364 
365 	}
366 
367 	// Parse off the URL path.
368 
369 	int idx = url.indexOf(";"+SERVICE_ATTR_ID+"=");
370 
371 	if (idx == -1) {
372 	    throw
373 		new ServiceLocationException(
374 				ServiceLocationException.PARSE_ERROR,
375 				"template_url_malformed",
376 				new Object[] {turl});
377 
378 	}
379 
380 	int jdx = TEMPLATE_SERVICE_TYPE.length() + 1; // don't forget :!!!
381 
382 	// Return the document URL.
383 
384 	return url.substring(jdx, idx);
385     }
386 
387     // Return a URL given a version and language locale.
388 
findVersionedURL(ServiceType serviceType, Locale languageLocale, String version)389     private ServiceURL findVersionedURL(ServiceType serviceType,
390 					Locale languageLocale,
391 					String version)
392 	throws ServiceLocationException {
393 
394 	// Templates should be registered in all scopes. Look for them
395 	//  in all.
396 
397 	Vector scopes = ServiceLocationManager.findScopes();
398 
399 	// Set up query.
400 
401 	ServiceLocationEnumeration results = null;
402 	String query = "(" + SERVICE_ATTR_ID + "=" + serviceType + ")";
403 
404 	if (version != null) {
405 	    query = query + "(" + VERSION_ATTR_ID + "=" + version + ")";
406 
407 	}
408 
409 	query = "(&" + query + ")";
410 
411 	// Get user agent for query.
412 
413 	Locator userAgent =
414 	    ServiceLocationManager.getLocator(languageLocale);
415 
416 	if (userAgent == null) {
417 	    throw
418 		new ServiceLocationException(
419 				ServiceLocationException.NOT_IMPLEMENTED,
420 				"no_locator",
421 				new Object[0]);
422 	}
423 
424 	try {
425 	    ServiceType type = new ServiceType(TEMPLATE_SERVICE_TYPE);
426 
427 	    results =
428 		userAgent.findServices(type,
429 				       scopes,
430 				       query);
431 
432 	} catch (ServiceLocationException ex) {
433 
434 	    // If language not supported, it just means none there.
435 
436 	    if (ex.getErrorCode() !=
437 		ServiceLocationException.LANGUAGE_NOT_SUPPORTED) {
438 		throw ex;
439 
440 	    }
441 
442 	}
443 
444 	// If nothing came back, then return null.
445 
446 	if (!results.hasMoreElements()) {
447 	    return null;
448 
449 	}
450 
451 
452 	ServiceURL turl = null;
453 	float highest = (float)-1.0;
454 
455 	// If there's more than one service of this type registered, then
456 	//  take highest version if version number was null.
457 
458 	while (results.hasMoreElements()) {
459 	    ServiceURL surl = (ServiceURL)results.nextElement();
460 	    String urlPath = surl.getURLPath();
461 
462 	    if (version == null) {
463 
464 		// Get the version attribute from the URL.
465 
466 		String token = ";"+VERSION_ATTR_ID+"=";
467 
468 		int idx = urlPath.indexOf(token);
469 
470 		if (idx == -1) { // ignore, there may be more...
471 		    continue;
472 
473 		}
474 
475 		urlPath =
476 		    urlPath.substring(idx+token.length(), urlPath.length());
477 
478 		idx = urlPath.indexOf(";");
479 
480 		if (idx == -1) { // ignore, there may be more...
481 		    continue;
482 
483 		}
484 
485 		String temversion = urlPath.substring(0, idx);
486 		float current = (float)0.0;
487 
488 		// Convert to float.
489 
490 		try {
491 
492 		    current = Float.valueOf(temversion).floatValue();
493 
494 		} catch (NumberFormatException ex) {
495 
496 		    continue;  // ignore, there may be more...
497 
498 		}
499 
500 		// Identify if this is the highest version number so far.
501 
502 		if (current > highest) {
503 		    turl = surl;
504 		}
505 
506 	    } else {
507 
508 		// If we found more than one, may be a problem.
509 
510 		if (turl != null) {
511 
512 		    throw
513 			new ServiceLocationException(
514 				ServiceLocationException.INTERNAL_SYSTEM_ERROR,
515 				"template_multiple",
516 				new Object[] {
517 			    serviceType,
518 				version,
519 				languageLocale});
520 		}
521 
522 		turl = surl;
523 	    }
524 	}
525 
526 	return turl;
527     }
528 
529     /**
530      * Create an attribute verifier for the template document URL.
531      *
532      * @param documentURL A URL for the template document URL.
533      * @return An attribute verifier for the service
534      * @exception ServiceLocationException Throws
535      *					  PARSE_ERROR
536      *					  if any syntax errors
537      *					  are encountered during parsing
538      *					  of service's template definition.
539      *					  Throws
540      *					SYSTEM_ERROR
541      *					  if URL parsing error occurs.
542      *					  Throws ServiceLocationException
543      *					  if any other errors occur.
544      * @exception IllegalArgumentException Thrown if any parameters are null.
545      *
546      */
547 
attributeVerifier( String documentURL)548     public ServiceLocationAttributeVerifier attributeVerifier(
549 							String documentURL)
550 	throws ServiceLocationException {
551 
552 	// Check the parameter.
553 
554 	Assert.nonNullParameter(documentURL, "documentURL");
555 
556 	// Create a URL attribute parser to parse the document.
557 
558 	return new URLAttributeVerifier(documentURL);
559     }
560 
561 }
562