blob: 6b924272d7577b8c805e36958159842e041b61d9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.osgi.internal.serviceregistry;
import org.eclipse.osgi.internal.framework.BundleContextImpl;
import org.eclipse.osgi.internal.messages.Msg;
import org.osgi.framework.*;
/**
* ServiceObjects implementation.
*/
public class ServiceObjectsImpl<S> implements ServiceObjects<S> {
/** Service registration */
private final ServiceRegistrationImpl<S> registration;
/** Reference to service */
private final ServiceReference<S> reference;
/** BundleContext associated with this service use */
private final BundleContextImpl user;
/**
* Constructs a service objects encapsulating the service object.
*
* @param user bundle getting the service
* @param registration ServiceRegistration of the service
*/
ServiceObjectsImpl(BundleContextImpl user, ServiceRegistrationImpl<S> registration) {
this.registration = registration;
this.reference = registration.getReference();
this.user = user;
}
/**
* Returns a service object for the {@link #getServiceReference()
* referenced} service.
*
* <p>
* This {@code ServiceObjects} object can be used to obtain multiple service
* objects for the referenced service if the service has
* {@link Constants#SCOPE_PROTOTYPE prototype} scope. If the referenced
* service has {@link Constants#SCOPE_SINGLETON singleton} or
* {@link Constants#SCOPE_BUNDLE bundle} scope, this method behaves the same
* as calling the {@link BundleContext#getService(ServiceReference)} method
* for the referenced service. That is, only one, use-counted service object
* is available from this {@link ServiceObjects} object.
*
* <p>
* This method will always return {@code null} when the referenced service
* has been unregistered.
*
* <p>
* For a prototype scope service, the following steps are required to get
* the service object:
* <ol>
* <li>If the referenced service has been unregistered, {@code null} is
* returned.</li>
* <li>The
* {@link PrototypeServiceFactory#getService(Bundle, ServiceRegistration)}
* method is called to create a service object for the caller.</li>
* <li>If the service object returned by the {@code PrototypeServiceFactory}
* object is {@code null}, not an {@code instanceof} all the classes named
* when the service was registered or the {@code PrototypeServiceFactory}
* object throws an exception, {@code null} is returned and a Framework
* event of type {@link FrameworkEvent#ERROR} containing a
* {@link ServiceException} describing the error is fired.</li>
* <li>The service object is returned.</li>
* </ol>
*
* @return A service object for the referenced service or {@code null} if
* the service is not registered, the service object returned by a
* {@code ServiceFactory} does not implement the classes under which
* it was registered or the {@code ServiceFactory} threw an
* exception.
* @throws IllegalStateException If the BundleContext used to create this
* {@code ServiceObjects} object is no longer valid.
* @see #ungetService(Object)
*/
@Override
public S getService() {
user.checkValid();
return registration.getService(user, ServiceConsumer.prototypeConsumer);
}
/**
* Releases a service object for the {@link #getServiceReference()
* referenced} service.
*
* <p>
* This {@code ServiceObjects} object can be used to obtain multiple service
* objects for the referenced service if the service has
* {@link Constants#SCOPE_PROTOTYPE prototype} scope. If the referenced
* service has {@link Constants#SCOPE_SINGLETON singleton} or
* {@link Constants#SCOPE_BUNDLE bundle} scope, this method behaves the same
* as calling the {@link BundleContext#ungetService(ServiceReference)}
* method for the referenced service. That is, only one, use-counted service
* object is available from this {@link ServiceObjects} object.
*
* <p>
* For a prototype scope service, the following steps are required to
* release the service object:
* <ol>
* <li>If the referenced service has been unregistered, this method returns
* without doing anything.</li>
* <li>The
* {@link PrototypeServiceFactory#ungetService(Bundle, ServiceRegistration, Object)}
* method is called to release the specified service object.</li>
* </ol>
*
* <p>
* The specified service object must no longer be used and all references to
* it should be destroyed after calling this method.
*
* @param service A service object previously provided by this
* {@code ServiceObjects} object.
* @throws IllegalStateException If the BundleContext used to create this
* {@code ServiceObjects} object is no longer valid.
* @throws IllegalArgumentException If the specified service was not
* provided by this {@code ServiceObjects} object.
* @see #getService()
*/
@Override
public void ungetService(S service) {
user.checkValid();
boolean removed = registration.ungetService(user, ServiceConsumer.prototypeConsumer, service);
if (!removed) {
if (registration.isUnregistered()) {
return;
}
throw new IllegalArgumentException(Msg.SERVICE_OBJECTS_UNGET_ARGUMENT_EXCEPTION);
}
}
/**
* Returns the {@link ServiceReference} for the service associated with this
* {@code ServiceObjects} object.
*
* @return The {@link ServiceReference} for the service associated with this
* {@code ServiceObjects} object.
*/
@Override
public ServiceReference<S> getServiceReference() {
return reference;
}
}