Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2016-03-07 16:53:05 +0000
committerChristian W. Damus2016-03-07 22:54:00 +0000
commitb3abad7ab47a4414939e41665d5d0d4c6bd8bcc7 (patch)
tree727f52ab4beee7a1ed974ba5d9645670e337d646 /plugins
parent85ac78aed7e2a0b17920adf21f4d905b53159081 (diff)
downloadorg.eclipse.papyrus-b3abad7ab47a4414939e41665d5d0d4c6bd8bcc7.tar.gz
org.eclipse.papyrus-b3abad7ab47a4414939e41665d5d0d4c6bd8bcc7.tar.xz
org.eclipse.papyrus-b3abad7ab47a4414939e41665d5d0d4c6bd8bcc7.zip
Bug 488558: [Releng] Projects not included in the Main release
https://bugs.eclipse.org/bugs/show_bug.cgi?id=488558 Implement a factory for shared service instances in the Service Registry. Use this new facility for the stateless object localizer service. Change-Id: I467c2d9c59243658b467697b099afa46af480fb2
Diffstat (limited to 'plugins')
-rw-r--r--plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/SharedServiceFactory.java283
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.classpath2
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.settings/org.eclipse.jdt.core.prefs6
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/META-INF/MANIFEST.MF2
-rw-r--r--plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/src/org/eclipse/papyrus/infra/services/localizer/util/DefaultObjectLocalizerFactory.java32
5 files changed, 294 insertions, 31 deletions
diff --git a/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/SharedServiceFactory.java b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/SharedServiceFactory.java
new file mode 100644
index 00000000000..7066747473d
--- /dev/null
+++ b/plugins/infra/core/org.eclipse.papyrus.infra.core/src/org/eclipse/papyrus/infra/core/services/SharedServiceFactory.java
@@ -0,0 +1,283 @@
+/*****************************************************************************
+ * Copyright (c) 2016 Christian W. Damus and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.infra.core.services;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import org.eclipse.emf.common.util.WrappedException;
+import org.eclipse.papyrus.infra.core.Activator;
+import org.eclipse.papyrus.infra.tools.util.ReferenceCounted;
+
+/**
+ * A service factory that creates a reference-counted service that is shared
+ * amongst all {@linkplain ServicesRegistry service registries}. If the
+ * service interface {@code S} does not conform to the {@link IService} protocol
+ * then it is recommended to override the following operations:
+ * <ul>
+ * <li>{@link #start(Object)}</li>
+ * <li>{@link #dispose(Object)}</li>
+ * </ul>
+ * In any case, if the service is an {@link IService}, it will never be
+ * {@linkplain IService#init(ServicesRegistry) initialized} with a service
+ * registry because it is shared by all service registries.
+ *
+ * @param <S>
+ * the shared service interface
+ *
+ * @since 2.0
+ */
+public class SharedServiceFactory<S> implements IServiceFactory {
+
+ private final Class<? extends S> serviceInterface;
+
+ private final Supplier<? extends S> serviceCreator;
+
+ private final Function<? super ServicesRegistry, Scope> scopeProvider;
+
+ private Scope scope;
+
+ private S serviceInstance;
+
+ /**
+ * Creates a new shared service factory for services of the given type. Subclasses that
+ * use this constructor must override the {@link #createSharedInstance()} method to
+ * create the shared service instance. The {@link Scope} of the shared service instance
+ * is the {@linkplain Scope#GLOBAL_SCOPE global scope}.
+ *
+ * @param serviceInterface
+ * the service type that I create
+ */
+ protected SharedServiceFactory(Class<? extends S> serviceInterface) {
+ this(serviceInterface, null, null);
+ }
+
+ /**
+ * Creates a new shared service factory for services of the given type with a supplier
+ * that provides the shared service instance on demand. Subclasses that
+ * use this constructor need not override the {@link #createSharedInstance()} method to
+ * create the shared service instance, unless the {@code serviceCreator} is {@code null}.
+ * The {@link Scope} of the shared service instance is the
+ * {@linkplain Scope#GLOBAL_SCOPE global scope}.
+ *
+ * @param serviceInterface
+ * the service type that I create
+ * @param serviceCreator
+ * a supplier that creates a new service instance on demand. This commonly
+ * would be a zero-argument constructor of the service implementation class
+ */
+ protected SharedServiceFactory(Class<? extends S> serviceInterface, Supplier<? extends S> serviceCreator) {
+ this(serviceInterface, serviceCreator, null);
+ }
+
+ /**
+ * Creates a new shared service factory for services of the given type in a defined
+ * scope, with a supplier that provides the shared service instance on demand.
+ * Subclasses that use this constructor need not override the {@link #createSharedInstance()}
+ * method to create the shared service instance, unless the {@code serviceCreator} is
+ * {@code null}.
+ *
+ * @param serviceInterface
+ * the service type that I create
+ * @param serviceCreator
+ * a supplier that creates a new service instance on demand. This commonly
+ * would be a zero-argument constructor of the service implementation class
+ * @param scopeProvider
+ * a function that computes the appropriate {@link Scope} in which
+ * a registry should find the shared instance of my service. A {@code null} scope
+ * is equivalent to the {@linkplain Scope#GLOBAL_SCOPE global scope}
+ */
+ protected SharedServiceFactory(Class<? extends S> serviceInterface, Supplier<? extends S> serviceCreator, Function<? super ServicesRegistry, Scope> scopeProvider) {
+ super();
+
+ this.serviceInterface = serviceInterface;
+ this.serviceCreator = (serviceCreator != null) ? serviceCreator : this::createSharedInstance;
+ this.scopeProvider = (scopeProvider != null) ? scopeProvider : __ -> Scope.GLOBAL_SCOPE;
+ }
+
+ @Override
+ public final void init(ServicesRegistry servicesRegistry) throws ServiceException {
+ // A shared service doesn't need to know any particular registry, but I
+ // need to create my scope
+ scope = scopeProvider.apply(servicesRegistry);
+ }
+
+ @Override
+ public final void startService() throws ServiceException {
+ // It was already started on creation
+ }
+
+ /**
+ * Releases my service instance, thereby reducing its reference count and potentially
+ * actually disposing of it (if there are no other service registries using it).
+ */
+ @Override
+ public final void disposeService() {
+ if (serviceInstance != null) {
+ serviceInstance = null;
+ scope.maybeGetService(serviceInterface).ifPresent(ReferenceCounted::release);
+ scope = null;
+ }
+ }
+
+ @Override
+ public final Object createServiceInstance() throws ServiceException {
+ if (serviceInstance == null) {
+ try {
+ serviceInstance = serviceInterface.cast(getCountedService().retain());
+ } catch (ClassCastException e) {
+ getCountedService().release(); // It's of no use to us
+ throw new ServiceException("Incompatible service type", e); //$NON-NLS-1$
+ }
+ }
+
+ return serviceInstance;
+ }
+
+ private ReferenceCounted<?> getCountedService() throws ServiceException {
+ return scope.getService(serviceInterface, this);
+ }
+
+ /**
+ * If the factory is not {@linkplain #SharedServiceFactory(Class, Supplier) initialized}
+ * with a service creator, then this method must be overridden to create the shared
+ * service instance. The default implementation throws {@link UnsupportedOperationException}..
+ *
+ * @return a new instance of my service, to be shared by all registries
+ */
+ protected S createSharedInstance() {
+ throw new UnsupportedOperationException("createSharedInstance"); //$NON-NLS-1$
+ }
+
+ /**
+ * Starts the shared instance of my service. This is only called once in the lifetime
+ * of the instance. The default implementation forwards to the {@link IService} protocol
+ * if the {@code sharedInstance} conforms to it. Otherwise, subclasses should override
+ * to start the service instance if necessary.
+ *
+ * @param sharedInstance
+ * the shared instance of my service
+ *
+ * @throws ServiceException
+ * on failure to start the instance
+ *
+ * @see IService#startService()
+ */
+ protected void start(S sharedInstance) throws ServiceException {
+ if (sharedInstance instanceof IService) {
+ ((IService) sharedInstance).startService();
+ }
+ }
+
+ /**
+ * Disposes of the shared instance of my service. This is only called once in the lifetime
+ * of the instance. The default implementation forwards to the {@link IService} protocol
+ * if the {@code sharedInstance} conforms to it. Otherwise, subclasses should override
+ * to dispose of the service instance if necessary.
+ *
+ * @param sharedInstance
+ * the shared instance of my service
+ *
+ * @throws ServiceException
+ * on failure to dispose of the instance
+ *
+ * @see IService#disposeService()
+ */
+ protected void dispose(S sharedInstance) throws ServiceException {
+ if (sharedInstance instanceof IService) {
+ ((IService) sharedInstance).disposeService();
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * A scope in which a single instance of my service is to be shared. Any number of
+ * service registries can share the same service within a scope if they have factories
+ * that provide that scope. It is up to each factory to determine the scope appropriate
+ * for its registry. The default scope is the {@link #GLOBAL_SCOPE}. Clients may
+ * create any scopes that they may need, in addition to using the
+ * {@linkplain #GLOBAL_SCOPE global scope}.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ */
+ public static class Scope {
+ /**
+ * The default scope in which registries share service instances, being a global scope
+ * available to all registries.
+ */
+ public static final Scope GLOBAL_SCOPE = new Scope();
+
+ /**
+ * Initialize me.
+ */
+ public Scope() {
+ super();
+ }
+
+ private final Map<Class<?>, ReferenceCounted<?>> serviceInstances = new ConcurrentHashMap<>();
+
+ /**
+ * Obtains the shared instance of the specified service interface if it currently
+ * exists in the scope.
+ *
+ * @param serviceInterface
+ * a service interface
+ *
+ * @return the current shared instance, or {@code null} if it does not exist
+ */
+ public <S> S getService(Class<S> serviceInterface) {
+ return maybeGetService(serviceInterface)
+ .map(serviceInterface::cast)
+ .orElse(null);
+ }
+
+ Optional<ReferenceCounted<?>> maybeGetService(Class<?> serviceInterface) {
+ return Optional.ofNullable(serviceInstances.get(serviceInterface));
+ }
+
+ <S> ReferenceCounted<?> getService(Class<? extends S> serviceInterface, SharedServiceFactory<S> factory) throws ServiceException {
+ try {
+ return serviceInstances.computeIfAbsent(serviceInterface, type -> {
+ S sharedInstance = factory.serviceCreator.get();
+
+ try {
+ factory.start(sharedInstance);
+ } catch (ServiceException e) {
+ throw new WrappedException(e);
+ }
+
+ return new ReferenceCounted<>(sharedInstance, () -> {
+ // Remove the mapping for this shared instance
+ serviceInstances.remove(type);
+
+ // And dispose of it
+ try {
+ factory.dispose(sharedInstance);
+ } catch (Exception e) {
+ Activator.log.error("Shared service instance not successfully disposed", e); //$NON-NLS-1$
+ }
+ });
+ });
+ } catch (WrappedException e) {
+ throw (ServiceException) e.exception();
+ }
+ }
+ }
+}
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.classpath b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.classpath
index ad32c83a788..eca7bdba8f0 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.classpath
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.classpath
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.settings/org.eclipse.jdt.core.prefs b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.settings/org.eclipse.jdt.core.prefs
index 94d61f00da6..b3aa6d60f94 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.settings/org.eclipse.jdt.core.prefs
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/.settings/org.eclipse.jdt.core.prefs
@@ -1,10 +1,10 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/META-INF/MANIFEST.MF b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/META-INF/MANIFEST.MF
index e13640ff285..db1a0451351 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/META-INF/MANIFEST.MF
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/META-INF/MANIFEST.MF
@@ -12,4 +12,4 @@ Bundle-Localization: plugin
Bundle-ManifestVersion: 2
Bundle-Activator: org.eclipse.papyrus.infra.services.localizer.internal.Activator
Bundle-SymbolicName: org.eclipse.papyrus.infra.services.localizer;singleton:=true
-Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/src/org/eclipse/papyrus/infra/services/localizer/util/DefaultObjectLocalizerFactory.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/src/org/eclipse/papyrus/infra/services/localizer/util/DefaultObjectLocalizerFactory.java
index 79ffad08e9f..35ca3a6ecf6 100644
--- a/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/src/org/eclipse/papyrus/infra/services/localizer/util/DefaultObjectLocalizerFactory.java
+++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.localizer/src/org/eclipse/papyrus/infra/services/localizer/util/DefaultObjectLocalizerFactory.java
@@ -1,5 +1,5 @@
/*****************************************************************************
- * Copyright (c) 2013 CEA LIST and others.
+ * Copyright (c) 2013, 2016 CEA LIST, Christian W. Damus, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -8,42 +8,22 @@
*
* Contributors:
* CEA LIST - Initial API and implementation
+ * Christian W. Damus - bug 488558
*****************************************************************************/
package org.eclipse.papyrus.infra.services.localizer.util;
-import org.eclipse.papyrus.infra.core.services.IServiceFactory;
-import org.eclipse.papyrus.infra.core.services.ServiceException;
-import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
+import org.eclipse.papyrus.infra.core.services.SharedServiceFactory;
import org.eclipse.papyrus.infra.services.localizer.DefaultObjectLocalizer;
+import org.eclipse.papyrus.infra.services.localizer.IObjectLocalizer;
/**
* Service factory for the default object localizer.
*/
-public class DefaultObjectLocalizerFactory implements IServiceFactory {
+public class DefaultObjectLocalizerFactory extends SharedServiceFactory<IObjectLocalizer> {
public DefaultObjectLocalizerFactory() {
- super();
- }
-
- @Override
- public void init(ServicesRegistry servicesRegistry) throws ServiceException {
- // pass. The localizer is stateless and requires no initialization
- }
-
- @Override
- public void startService() throws ServiceException {
- // pass. The localizer is stateless and requires no starting
- }
-
- @Override
- public void disposeService() throws ServiceException {
- // pass. The localizer is stateless and requires no disposal
- }
-
- @Override
- public Object createServiceInstance() throws ServiceException {
- return DefaultObjectLocalizer.INSTANCE;
+ super(IObjectLocalizer.class, DefaultObjectLocalizer::new);
}
}

Back to the top