/* $Id$ * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ module org.apache.etch.services.ns /** * The NameService provides translation from an abstract name for a service to a * uri that may be used to contact the service. A given service may offer * several different connection schemes, and a client may only support a subset * of those. So, when a client wishes to connect to a service, it may query * the NameService with both abstract name and desired schemes in order to find * a suitable match. * * Some example queries: * * All services with servicename='Foo' and instancename='bar' and qualifier='tcp' * * sourceUri='Foo/bar/tcp' * * Same as the query above, but written out longhand: * * servicename='Foo' and instancename='bar' and qualifier='tcp' * * Fully qualified sourceUri: * * sourceUri='Foo/bar/tcp/1' * * Any instance of service Foo located in Austin, TX: * * servicename='Foo' and qualities.location='Austin, TX' * * Instances of service Foo with capacity >= 400: * * servicename='Foo' and qualities.capacity>=400 * * Relative operations on qualities require that the quality be present and be * comparable (with mixed types some type promotion is supported). But you might * be surprised, qualities which are absent will give a negative comparison no * matter which sense is used: both qualities.x > 50 and qualities.x < 50 are * false whenever qualities.x is null. Consider this test: not qualities.x < 50. * This is not the same as qualities.x >= 50. It is the same as qualities.x = * null or qualities.x >= 50. */ @Timeout( 30000 ) service NameService { /** An entry describing a service. */ struct Entry ( /** A service description uri, composed of * servicename/instancename/qualifier[/priority]. */ string sourceUri, /** Qualities of this service instance. */ Map qualities, /** Etch service connection uri, for example * tcp://localhost:9000?filter=KeepAlive */ string targetUri, /** Lifetime in seconds from last update. */ int ttl, /** Who created or last update. */ string who, /** Date / time of create or last update. */ Datetime lastUpdate, /** Flag indicating entry has been removed. */ boolean removed ) /** * Look up an entry by matching it against the sourceUri. * * @param source source uri * * @return entry matching the source uri. In the case of an * absent instance name or qualifier, the implementation * can decide which Entry to return. */ @Authorize( canLookup, source ) Entry lookup( string source ) /** * Looks up entries by matching them against the query string. Entries are * returned in a stable and consistent order, increasing alphabetical by * servicename, instancename, and scheme, and then increasing numerical by * priority. If a scheme search term appears with a list, schemes are * returned in the specified order (e.g., scheme='tls,tcp'). * * @param query a sql-like query expression using the elements of the * sourceUri, targetUri, and qualities. If query is null or the empty * string, all entries are matched. * * @param offset offset in the list of matched items of the first item to * return. This parameter and the count parameter are used to step through * the result set when there are many results. * * @param count number of items to return. * * @return entries matching query. If you requested 10 items and 10 are * returned, there could be more. To get the next batch, add results.length * to offset and call find again: * * int i = 0; * int n = 10; * Entry[] results; * while ((results = service.find( null, i, n )).length > 0) * { * for (Entry e: results) * processEntry( e ); * if (results.length < n) * break; * i += results.length; * } */ @Authorize( canFind, query ) Entry[] find( string query, int offset, int count ) /** * Adds or updates the specified entry. The given parameters replace any * existing values in an Entry whose key is sourceUri, whereas who and * lastUpdate are set to the current user and current date / time, * respectively. * * @param sourceUri the uri describing the service. The uri should be of * the form "servicename/instancename/scheme[/priority]", where servicename * is a valid fully qualified service name (e.g., * etch.services.ns.NameService"), instancename is a valid etch identifier * (e.g, fred, alice01), scheme is a valid uri scheme (e.g., tcp, tls), and * priority is an integer >= 1. If priority is omitted, it is defaulted to * 1. * * @param qualities a map which may be used to describe additional features * of the entry, such as purpose, licenses, capacity, location, owner, * whatever. Query strings may test values of qualities using a variety of * sql-like operators. Qualities may be null. * * @param targetUri the uri describing the contact information for the * service. * * @param ttl the lifetime of the entry specified as seconds. 0 means * forever, -1 means remove immediately when the connection to the * NameService is dropped. */ @Authorize( canRegister, sourceUri, qualities, targetUri ) void register( string sourceUri, Map qualities, string targetUri, int ttl ) /** * Registers a number of entries all in one operation. Identical to calling * register with each entry in turn. * * @param entries a sequence of Entry records with sourceUri, targetUri, * qualities, and ttl as specified in register() above. Who and lastUpdate * fields are ignored. */ @Authorize( canRegisterBulk, entries ) void registerBulk( Entry[] entries ) /** * Removes the specified entry. * * @param sourceUri the uri describing the service. */ @Authorize( canUnregister, sourceUri, deleteEntry ) void unregister( string sourceUri, boolean deleteEntry ) /** * Adds a request for notification of changes to entries matching the query. * The current value of all matching entries is delivered via entryChanged * client message, as well as any updates or new entries. * * @param query a sql-like query expression using the elements of the * sourceUri, targetUri, and qualities. If query is null or the empty * string, all entries are matched. */ @Authorize( canFind, query ) void subscribe( string query ) /** * Removes a request for notification of changes to entries matching the * query. * * @param query a query previously passed to subscribe. The string must * match exactly. */ void unsubscribe( string query ) /** * Removes all requests for notification of changes to entries. This * operation is implicitly performed when the connection to the NameService * is dropped. */ void unsubscribeAll() //////////////////// // RIGHTS TESTING // //////////////////// /** * Tests whether the current user is authorized to lookup the source. * @param source the complete specification api/instance/scheme. */ boolean canLookup( string source ) /** * Tests whether the current user is authorized to run the query. * * @param query a sql-like query expression using the elements of the * sourceUri, targetUri, and qualities. If query is null or the empty * string, all entries are matched. * * @return true if the current user is authorized to run the query. */ boolean canFind( string query ) /** * Tests whether the current user is authorized to register the service. * * @param sourceUri the uri describing the service. * * @param qualities a map which may be used to describe additional features * of the entry. * * @param targetUri the actual uri of the service * * @return true if the current user is authorized to register the service. */ boolean canRegister( string sourceUri, Map qualities, string targetUri ) /** * Tests whether the current user is authorized to unregister the service. * * @param sourceUri the uri describing the service. * * @param deleteEntry if true, the entire entry matching the sourceUri * would be deleted. if false, only the target uri matching the sourceUri * would be deleted, but the entry would be intact. * * @return true if the current user is authorized to register the service. */ boolean canUnregister( string sourceUri, boolean deleteEntry ) /** * Tests whether the current user is authorized to register the entries. * This is the same as: * * for (Entry entry: entries) * if (!canRegister( entry.sourceUri, entry.qualities )) * return false; * return true; * * @param entries a sequence of Entry records with sourceUri, targetUri, * qualities, and ttl as specified in register() above. Who and lastUpdate * fields are ignored. * * @return true if the current user is authorized to register the entries. * This is an all or nothing proposition. */ boolean canRegisterBulk( Entry[] entries ) //////////////////// // CLIENT METHODS // //////////////////// /** * Notifies the client of a change in an entry. The entry might have been * created, updated, or removed. * * Note: while this might have normally been an event, we made it a call * to slow down the processing of what might otherwise be a rather large * change set. * * Note: when keeping track of entries, always keep the one with the latest * lastUpdate. * * @param query the query which triggered the notification. * * @param entry the entry which has changed. */ @Direction( client ) void entryChanged( string query, Entry entry ) }