com.hazelcast.osgi.impl.HazelcastOSGiServiceImpl Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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.
*/
package com.hazelcast.osgi.impl;
import com.hazelcast.config.Config;
import com.hazelcast.config.GroupConfig;
import com.hazelcast.config.XmlConfigBuilder;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.Logger;
import com.hazelcast.osgi.HazelcastOSGiInstance;
import com.hazelcast.osgi.HazelcastOSGiService;
import com.hazelcast.util.ExceptionUtil;
import com.hazelcast.util.StringUtil;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Implementation of {@link HazelcastInternalOSGiService}.
*
* @see HazelcastInternalOSGiService
* @see com.hazelcast.osgi.HazelcastOSGiService
*/
class HazelcastOSGiServiceImpl
implements HazelcastInternalOSGiService {
private static final ILogger LOGGER = Logger.getLogger(HazelcastOSGiService.class);
private final Object serviceMutex = new Object();
private final Bundle ownerBundle;
private final BundleContext ownerBundleContext;
private final String id;
private final ConcurrentMap instanceServiceRegistrationMap
= new ConcurrentHashMap();
private final ConcurrentMap instanceMap
= new ConcurrentHashMap();
// No need to "volatile" since this field is guarded and happens-before is handled by
// `synchronized` blocks of `serviceMutex` instance.
private ServiceRegistration serviceRegistration;
// Defined as `volatile` because even though this field is written inside `synchronized` blocks,
// it can be read from any thread without `synchronized` blocks and without `volatile` they may seen invalid value.
private volatile HazelcastOSGiInstance hazelcastInstance;
public HazelcastOSGiServiceImpl(Bundle ownerBundle) {
this(ownerBundle, DEFAULT_ID);
}
public HazelcastOSGiServiceImpl(Bundle ownerBundle, String id) {
this.ownerBundle = ownerBundle;
this.ownerBundleContext = ownerBundle.getBundleContext();
this.id = id;
}
private void checkActive() {
if (!isActive()) {
throw new IllegalStateException("Hazelcast OSGI Service is not active!");
}
}
private boolean shouldSetGroupName(GroupConfig groupConfig) {
if (groupConfig == null
|| StringUtil.isNullOrEmpty(groupConfig.getName())
|| GroupConfig.DEFAULT_GROUP_NAME.equals(groupConfig.getName())) {
if (!Boolean.getBoolean(HAZELCAST_OSGI_GROUPING_DISABLED)) {
return true;
}
}
return false;
}
private Config getConfig(Config config) {
if (config == null) {
config = new XmlConfigBuilder().build();
}
GroupConfig groupConfig = config.getGroupConfig();
if (shouldSetGroupName(groupConfig)) {
String groupName = id;
if (groupConfig == null) {
config.setGroupConfig(new GroupConfig(groupName));
} else {
groupConfig.setName(groupName);
}
}
return config;
}
private HazelcastInstance createHazelcastInstance(Config config) {
return Hazelcast.newHazelcastInstance(getConfig(config));
}
private HazelcastOSGiInstance registerInstance(HazelcastInstance instance) {
HazelcastOSGiInstance hazelcastOSGiInstance;
if (instance instanceof HazelcastOSGiInstance) {
hazelcastOSGiInstance = (HazelcastOSGiInstance) instance;
} else {
hazelcastOSGiInstance = new HazelcastOSGiInstanceImpl(instance, this);
}
if (!Boolean.getBoolean(HAZELCAST_OSGI_REGISTER_DISABLED)) {
ServiceRegistration serviceRegistration =
ownerBundleContext.registerService(HazelcastInstance.class.getName(), hazelcastOSGiInstance, null);
instanceServiceRegistrationMap.put(hazelcastOSGiInstance, serviceRegistration);
}
instanceMap.put(instance.getName(), hazelcastOSGiInstance);
return hazelcastOSGiInstance;
}
private void deregisterInstance(HazelcastOSGiInstance hazelcastOSGiInstance) {
instanceMap.remove(hazelcastOSGiInstance.getName());
ServiceRegistration serviceRegistration =
instanceServiceRegistrationMap.remove(hazelcastOSGiInstance);
if (serviceRegistration != null) {
ownerBundleContext.ungetService(serviceRegistration.getReference());
serviceRegistration.unregister();
}
}
private void shutdownDefaultHazelcastInstanceIfActive() {
if (hazelcastInstance != null) {
shutdownHazelcastInstanceInternalSafely(hazelcastInstance);
hazelcastInstance = null;
}
}
private void shutdownAllInternal() {
for (HazelcastOSGiInstance instance : instanceMap.values()) {
shutdownHazelcastInstanceInternalSafely(instance);
}
// Default instance may not be registered due to set `HAZELCAST_OSGI_REGISTER_DISABLED` flag,
// So be sure that it is shutdown.
shutdownDefaultHazelcastInstanceIfActive();
}
@Override
public String getId() {
return id;
}
@Override
public Bundle getOwnerBundle() {
return ownerBundle;
}
@Override
public boolean isActive() {
return ownerBundle.getState() == Bundle.ACTIVE;
}
@Override
public void activate() {
// No need to complex lock-free approaches since this is not called frequently. Simple is good.
synchronized (serviceMutex) {
if (ownerBundle.getState() == Bundle.STARTING) {
try {
if (hazelcastInstance != null) {
LOGGER.warning("Default Hazelcast instance should be null while activating service !");
shutdownDefaultHazelcastInstanceIfActive();
}
if (Boolean.getBoolean(HAZELCAST_OSGI_START)) {
hazelcastInstance =
new HazelcastOSGiInstanceImpl(createHazelcastInstance(null), this);
LOGGER.info("Default Hazelcast instance has been created");
}
if (hazelcastInstance != null && !Boolean.getBoolean(HAZELCAST_OSGI_REGISTER_DISABLED)) {
registerInstance(hazelcastInstance);
LOGGER.info("Default Hazelcast instance has been registered as OSGI service");
}
serviceRegistration =
ownerBundleContext.registerService(HazelcastOSGiService.class.getName(), this, null);
LOGGER.info(this + " has been registered as OSGI service and activated now");
} catch (Throwable t) {
// If somehow default instance is activated, revert and deactivate it.
shutdownDefaultHazelcastInstanceIfActive();
ExceptionUtil.rethrow(t);
}
}
}
}
@Override
public void deactivate() {
// No need to complex lock-free approaches since this is not called frequently. Simple is good.
synchronized (serviceMutex) {
if (ownerBundle.getState() == Bundle.STOPPING) {
try {
shutdownAllInternal();
try {
ownerBundleContext.ungetService(serviceRegistration.getReference());
serviceRegistration.unregister();
} catch (Throwable t) {
LOGGER.finest("Error occurred while deregistering " + this, t);
}
LOGGER.info(this + " has been deregistered as OSGI service and deactivated");
} finally {
serviceRegistration = null;
}
}
}
}
@Override
public HazelcastOSGiInstance getDefaultHazelcastInstance() {
checkActive();
// No need to synchronization since this is not a mutating operation on instances.
// If at this time service is deactivated, this method just returns terminated instance.
return hazelcastInstance;
}
@Override
public HazelcastOSGiInstance newHazelcastInstance(Config config) {
// No need to complex lock-free approaches since this is not called frequently. Simple is good.
synchronized (serviceMutex) {
checkActive();
return registerInstance(createHazelcastInstance(config));
}
}
@Override
public HazelcastOSGiInstance newHazelcastInstance() {
// No need to complex lock-free approaches since this is not called frequently. Simple is good.
synchronized (serviceMutex) {
checkActive();
return registerInstance(createHazelcastInstance(null));
}
}
@Override
public HazelcastOSGiInstance getHazelcastInstanceByName(String instanceName) {
checkActive();
// No need to synchronization since this is not a mutating operation on instances.
// If at this time service is deactivated, this method just returns terminated instance.
return instanceMap.get(instanceName);
}
@Override
public Set getAllHazelcastInstances() {
checkActive();
// No need to synchronization since this is not a mutating operation on instances.
// If at this time service is deactivated, this method just returns terminated instances.
return new HashSet(instanceMap.values());
}
@Override
public void shutdownHazelcastInstance(HazelcastOSGiInstance instance) {
// No need to complex lock-free approaches since this is not called frequently. Simple is good.
synchronized (serviceMutex) {
checkActive();
shutdownHazelcastInstanceInternal(instance);
}
}
private void shutdownHazelcastInstanceInternal(HazelcastOSGiInstance instance) {
try {
deregisterInstance(instance);
} catch (Throwable t) {
LOGGER.finest("Error occurred while deregistering " + instance, t);
}
instance.shutdown();
}
private void shutdownHazelcastInstanceInternalSafely(HazelcastOSGiInstance instance) {
try {
shutdownHazelcastInstanceInternal(instance);
} catch (Throwable t) {
LOGGER.finest("Error occurred while shutting down " + instance, t);
}
}
@Override
public void shutdownAll() {
// No need to complex lock-free approaches since this is not called frequently. Simple is good.
synchronized (serviceMutex) {
checkActive();
shutdownAllInternal();
}
}
@Override
public String toString() {
return "HazelcastOSGiServiceImpl{"
+ "ownerBundle=" + ownerBundle
+ ", hazelcastInstance=" + hazelcastInstance
+ ", active=" + isActive()
+ ", id=" + id
+ '}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy