001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.ksb.api.bus;
017
018import java.util.List;
019import java.util.Map;
020
021import javax.xml.namespace.QName;
022
023/**
024 * The {@code ServiceBus} is the primary api that client applications use to interact with the Kuali
025 * Service Bus. It provides capabilities to retrieve services endpoints for use when needing to
026 * invoke a service. It also provides a mechanism by which a client application can publish it's own
027 * services to the bus.
028 * 
029 * <p>
030 * The service bus may be backed by a service registry which can be used to locate services which
031 * other applications have published to the service registry. The service bus will synchronize it's
032 * known state with the of the registry, either through explicit invocations of the
033 * {@link #synchronize()} method or on a periodic basis (the details of which are up to the
034 * implementation).
035 * 
036 * <p>
037 * Note that the {@code ServiceBus} manages two primary collections of {@link Endpoint} classes.
038 * Those that have been published by this application (referred to as "local" endpoints) and those
039 * which have been published by other applications (referred to as "remote" endpoints).
040 * 
041 * @see Endpoint
042 * @see ServiceConfiguration
043 * @see ServiceDefinition
044 * 
045 * @author Kuali Rice Team (rice.collab@kuali.org)
046 * 
047 */
048public interface ServiceBus {
049
050    /**
051     * Returns the instance ID which identifies this client application to the service bus. The
052     * instance ID should be unique for each client of the service bus and will never be blank or
053     * null.
054     * 
055     * @return the instance ID for the application in which this service bus client is resident
056     */
057    String getInstanceId();
058
059    /**
060     * Returns an unmodifiable list of accessible endpoints that are available to the service bus
061     * with the given service name. This method will only return endpoints that the service bus
062     * believes are online, endpoints which are offline will not be included. In certain cases a
063     * specific service endpoint will be available both as a local and remote service. In these
064     * cases, the list returned from this method will preferentially include the local service. It
065     * will *not* include both the local and remote endpoint to the same service. This is important
066     * as this method may be used to get endpoints for broadcasting service calls to all endpoints
067     * with a given name. In these cases, it is not desirable to invoke the same endpoint twice.
068     * 
069     * @return a list of the remote endpoints that are available for the given service name, this
070     *         list will never be null but may be empty if there are no remote endpoints for the
071     *         given service name
072     * @throws IllegalArgumentException if serviceName is null
073     */
074    List<Endpoint> getEndpoints(QName serviceName);
075    
076    /**
077     * Returns an unmodifiable list of accessible endpoints that are available to the service bus
078     * with the given service name for the given application id. This method will only return
079     * endpoints that the service bus believes are online, endpoints which are offline will not be
080     * included. In certain cases a specific service endpoint will be available both as a local and
081     * remote service. In these cases, the list returned from this method will preferentially
082     * include the local service. It will *not* include both the local and remote endpoint to the
083     * same service. This is important as this method may be used to get endpoints for broadcasting
084     * service calls to all endpoints with a given name. In these cases, it is not desirable to
085     * invoke the same endpoint twice.
086     * @param serviceName the name of the service for which to locate an available endpoint
087     * @param applicationId the id of the application for which to locate an available endpoint for
088     *        the given service name
089     * @return a list of the remote endpoints that are available for the given service name, this
090     *         list will never be null but may be empty if there are no remote endpoints for the
091     *         given service name
092     * @throws IllegalArgumentException if serviceName is null
093     * @since 2.1.1
094     */
095    List<Endpoint> getEndpoints(QName serviceName, String applicationId);
096
097    /**
098     * Returns an unmodifiable list of remotely accessible endpoints that are available in the
099     * service registry with the given service name. This method will only return endpoints that the
100     * service bus believes are online, endpoints which are offline will not be included.
101     * 
102     * <p>
103     * If the service bus client has also deployed a service with this name, a remoted endpoint to
104     * this service will likely also be included in this list assuming that endpoint has already
105     * been synchronized with the registry.
106     * 
107     * <p>
108     * In most cases, it is preferable to use {@link #getEndpoints(QName)} instead of this method.
109     * Because it will preferably return a local endpoint reference for a given service endpoint if
110     * one is available.
111     * 
112     * @return a list of all endpoints that are available for the given service name, this list will
113     *         never be null but may be empty if there are no endpoints for the given service name
114     * @throws IllegalArgumentException if serviceName is null
115     */
116    List<Endpoint> getRemoteEndpoints(QName serviceName);
117
118    /**
119     * Returns the endpoint for the service with the given name that was published by this service
120     * bus client. If this client has not published any such service, then this method will return
121     * null.
122     * 
123     * @param serviceName the name of the service represented by the local endpoint
124     * @return the local endpoint for the given service name which was deployed by this client, or
125     *         null if no such service has been published
126     * @throws IllegalArgumentException if serviceName is null
127     */
128    Endpoint getLocalEndpoint(QName serviceName);
129
130    /**
131     * Returns an unmodifiable list of all services that have been published by this service bus
132     * client.
133     * 
134     * @return a map with the local service name as the key and the local endpoint as the value
135     *         which contains all local services published by this service bus client. This map may
136     *         be empty if this client has published no services, but it should never be null.
137     */
138    Map<QName, Endpoint> getLocalEndpoints();
139
140    /**
141     * Returns an unmodifiable list of all available and online endpoints of which the service bus
142     * is aware, including both local and remote endpoints.
143     * 
144     * @return all available endpoints, this list may be empty if no endpoints exist but will never
145     *         be null
146     */
147    List<Endpoint> getAllEndpoints();
148
149    /**
150     * Returns an available endpoint for the service with the given name. If the service with the
151     * given name is published locally, preference will be given to the locally deployed version of
152     * the service.
153     * 
154     * <p>
155     * Based on the nature of this method, if there is more than one endpoint available for the
156     * given name, multiple invocations of this method with the same service name may return
157     * different {@link Endpoint} instances each time.
158     * 
159     * @param serviceName the name of the service for which to locate an available endpoint
160     * @return an available endpoint for the service with the given name, or null if none is
161     *         available
162     * @throws IllegalArgumentException if serviceName is null
163     */
164    Endpoint getEndpoint(QName serviceName);
165
166    /**
167     * Returns an available endpoint for the service with the given name which is hosted by the
168     * application with the given application id. This operation functions the same as
169     * {@link #getEndpoint(QName)} with the exception that it will only consider endpoints with the
170     * given application id.
171     * 
172     * <p>
173     * Invoking this method with a null or blank value for {@code applicationId} is equivalent to
174     * invoking {@link #getEndpoint(QName)}.
175     * 
176     * @param serviceName the name of the service for which to locate an available endpoint
177     * @param applicationId the id of the application for which to locate an available endpoint for
178     *        the given service name
179     * @return an available endpoint for the service with the given name and application id, or null
180     *         if none is available
181     * @throws IllegalArgumentException if serviceName is null
182     */
183    Endpoint getEndpoint(QName serviceName, String applicationId);
184
185    /**
186     * Returns the endpoint matching the given service configuration, if one exists. In the case of
187     * services published by this service bus client, this method will preferably return the local
188     * endpoints in place of a remote endpoint to the same service.
189     * 
190     * @param serviceConfiguration the service configuration by which to lookup up the endpoint
191     * @return the endpoint who's service configuration matches the given configuration, or null if
192     *         no such match could be determined
193     * @throws IllegalArgumentException if the given serviceConfiguration is null
194     */
195    Endpoint getConfiguredEndpoint(ServiceConfiguration serviceConfiguration);
196
197    /**
198     * Returns a proxy to the service with the given name. This proxy should have built-in support
199     * for fail-over and load balancing capabilities. This means it is safe for client applications
200     * to cache a reference to this service proxy.
201     * 
202     * <p>
203     * This proxy should additionally be thread-safe.
204     * 
205     * <p>
206     * This method is equivalent to invoking {@link #getEndpoint(QName).getService()}.
207     * 
208     * @param serviceName the name of the service for which to locate an available proxy
209     * @return an available proxy for the service with the given name, or null if none is available
210     * @throws IllegalArgumentException if serviceName is null
211     */
212    Object getService(QName serviceName);
213
214    /**
215     * Returns a proxy to the service with the given name which is hosted by the application with
216     * the given application id. This operation functions the same as {@link #getService(QName)}
217     * with the exception that it will only consider endpoints with the given application id.
218     * 
219     * <p>
220     * Invoking this method with a null or blank value for {@code applicationId} is equivalent to
221     * invoking {@link #getService(QName)}. This method is also equivalent to invoking
222     * {@link #getEndpoint(QName, String).getService()}.
223     * 
224     * @param serviceName the name of the service for which to locate an available proxy
225     * @param applicationId the id of the application for which to locate an available proxy for the
226     *        given service name
227     * @return an available proxy for the service with the given name, or null if none is available
228     * @throws IllegalArgumentException if serviceName is null
229     */
230    Object getService(QName serviceName, String applicationId);
231
232    /**
233     * Publish a service with the given ServiceDefinition to the service bus. This effectively
234     * updates the service registry and provides an endpoint for other applications to invoke. If
235     * this application has already published a service under this name, it will be updated instead
236     * to reflect the new ServiceDefinition.
237     * 
238     * <p>
239     * The method also provides the ability for the service bus to immediately synchronize with the
240     * service registry after registering the service if {@code synchronize} is set to {@code true}.
241     * 
242     * @see #synchronize()
243     * 
244     * @param serviceDefinition the definition of the service to publish, must not be null
245     * @param synchronize indicates whether or not this service bus client should immediately
246     *        synchronize it's changes with the registry after registering the service.
247     * @return the service configuration for the published service
248     * @throws IllegalArgumentException if serviceDefinition is null
249     */
250    ServiceConfiguration publishService(ServiceDefinition serviceDefinition, boolean synchronize);
251
252    /**
253     * Functions as per {@link #publishService(ServiceDefinition, boolean)} but allows for multiple
254     * services to be published to the bus in a single operation. If the given list of service
255     * definitions is empty then this method will do nothing (including skipping synchronization
256     * with the registry if that was requested).
257     * 
258     * @see #publishService(ServiceDefinition, boolean)
259     * @see #synchronize()
260     * 
261     * @param serviceDefinitions the list of definition for the services to publish, must not be
262     *        null
263     * @param synchronize indicates whether or not this service bus client should immediately
264     *        synchronize it's changes with the registry after registering the services.
265     * @return the list of service configurations for the published services in the same order as
266     *         the list of service definitions
267     * @throws IllegalArgumentException if serviceDefinitions is null
268     */
269    List<ServiceConfiguration> publishServices(List<ServiceDefinition> serviceDefinitions, boolean synchronize);
270
271    /**
272     * Removes the service from the service bus and the service registry with the given service
273     * name. Client applications should only be able to remove services that they themselves have
274     * published.
275     * 
276     * <p>
277     * This method also provides the ability for the service bus to immediately synchronize with the
278     * service registry after removing the service if {@code synchronize} is set to {@code true}. If
279     * the service is not located and successfully removed, however, the sychronization will not
280     * run.
281     * 
282     * @see #synchronize()
283     * 
284     * @param serviceName the name of the service to remove
285     * @param synchronize indicates whether or not this service bus client should immediately
286     *        synchronize after removing the service
287     * @return true if the service was removed, false otherwise
288     * @throws IllegalArgumentException if the given serviceName is null
289     */
290    boolean removeService(QName serviceName, boolean synchronize);
291
292    /**
293     * Functions as per {@link #removeService(QName, boolean)} but allows for multiple services to
294     * be removed from the bus in a single operation. If the given list of service names is empty
295     * then this method will do nothing (including skipping synchronization with the registry if
296     * that was requested).
297     * 
298     * <p>
299     * If the list returned from the method contains only false responses (meaning that no services
300     * were removed) this method will skip synchronization even if it is requested.
301     * 
302     * @see #removeService(QName, boolean)
303     * @see #synchronize()
304     * 
305     * @param serviceNames the list of names for the services to remove, must not be null
306     * @param synchronize indicates whether or not this service bus client should immediately
307     *        synchronize it's changes with the registry after removing the services.
308     * @return a list of Booleans indicating which of the service removals were successful. This
309     *         list will be in the same order as the list of service configurations that were passed
310     *         in.
311     * @throws IllegalArgumentException if serviceNames is null
312     */
313    List<Boolean> removeServices(List<QName> serviceNames, boolean synchronize);
314
315    /**
316     * Synchronizes the current client's service bus with the central service registry. This may be
317     * done automatically on a periodic basic depending on the implementation of this service, but
318     * can be invoked manually through this method. This method should both register any outstanding
319     * service publications to the registry, as well as detect any changes in remote services that
320     * have been published/removed by other applications in the registry and update local service
321     * bus state accordingly.
322     *
323     * <p>Invoking this method is equivalent to invoking {@link #synchronizeLocalServices()} and
324     * {@link #synchronizeRemoteServices()} in either order.  However, the semantics vary slightly
325     * as this method should attempt to invoke them as an atomic operation.</p>
326     */
327    void synchronize();
328
329    /**
330     * Fetches information about the current state of the remote services available in the registry
331     * and the synchronizes the current client's service bus state.
332     */
333    void synchronizeRemoteServices();
334
335    /**
336     * Synchronizes information about the services this client is publishing with the central
337     * service registry.
338     */
339    void synchronizeLocalServices();
340
341}