/*******************************************************************************
* Copyright (c) 2011 GigaSpaces Technologies Ltd. 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 org.cloudifysource.utilitydomain.context;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.cloudifysource.domain.Service;
import org.cloudifysource.domain.context.ServiceContext;
import org.cloudifysource.domain.context.blockstorage.StorageFacade;
import org.cloudifysource.domain.context.kvstorage.AttributesFacade;
import org.cloudifysource.domain.context.network.NetworkFacade;
import org.cloudifysource.dsl.internal.CloudifyConstants;
import org.cloudifysource.dsl.internal.context.RemoteNetworkProvisioningDriver;
import org.cloudifysource.dsl.internal.context.RemoteStorageProvisioningDriver;
import org.cloudifysource.dsl.utils.ServiceUtils;
import org.cloudifysource.dsl.utils.ServiceUtils.FullServiceName;
import org.cloudifysource.utilitydomain.admin.TimedAdmin;
import org.cloudifysource.utilitydomain.context.blockstorage.StorageFacadeImpl;
import org.cloudifysource.utilitydomain.context.kvstore.AttributesFacadeImpl;
import org.cloudifysource.utilitydomain.context.network.NetworkFacadeImpl;
import org.openspaces.admin.Admin;
import org.openspaces.admin.AdminException;
import org.openspaces.admin.AdminFactory;
import org.openspaces.admin.esm.ElasticServiceManager;
import org.openspaces.admin.internal.esm.InternalElasticServiceManager;
import org.openspaces.admin.pu.ProcessingUnit;
import org.openspaces.core.cluster.ClusterInfo;
/**
*
*
* @author barakme
* @since 1.0
*/
public class ServiceContextImpl implements ServiceContext {
private static final String LOCALCLOUD = "localcloud";
private org.cloudifysource.domain.Service service;
private TimedAdmin timedAdmin;
private Admin openAdmin;
private final String serviceDirectory;
private ClusterInfo clusterInfo;
private boolean initialized = false;
private String serviceName;
private String applicationName;
private StorageFacade storageFacade;
private NetworkFacade networkDriver;
private AttributesFacade attributesFacade;
// TODO - this property should not be settable - there should be a separate
// interface for that.
// this pid may be modified due to process crashed, so volatile is required.
private volatile long externalProcessId;
/*************
* Constructor.
*
* @param clusterInfo
* the cluster info.
* @param serviceDirectory
* the service directory.
*
*/
public ServiceContextImpl(final ClusterInfo clusterInfo,
final String serviceDirectory) {
if (clusterInfo == null) {
throw new NullPointerException(
"Cluster Info provided to service context cannot be null!");
}
this.clusterInfo = clusterInfo;
this.serviceDirectory = serviceDirectory;
if (clusterInfo.getName() != null) {
FullServiceName fullName = ServiceUtils
.getFullServiceName(clusterInfo.getName());
this.applicationName = fullName.getApplicationName();
this.serviceName = fullName.getServiceName();
}
}
/**********
* Late object initialization.
*
* @param service
* .
* @param admin
* .
* @param clusterInfo
* .
*/
public void init(final Service service, final TimedAdmin timedAdmin, final ClusterInfo clusterInfo) {
this.service = service;
this.timedAdmin = timedAdmin;
// TODO - is the null path even possible?
if (clusterInfo == null) {
this.applicationName = CloudifyConstants.DEFAULT_APPLICATION_NAME;
this.serviceName = service.getName();
} else {
logger.fine("Parsing full service name from PU name: "
+ clusterInfo.getName());
final FullServiceName fullServiceName = ServiceUtils
.getFullServiceName(clusterInfo.getName());
logger.fine("Got full service name: " + fullServiceName);
this.serviceName = fullServiceName.getServiceName();
this.applicationName = fullServiceName.getApplicationName();
}
if (timedAdmin != null) {
final boolean found = this.timedAdmin.waitForLookupServices(1, 30, TimeUnit.SECONDS);
if (!found) {
throw new AdminException(
"A service context could not be created as the Admin API could not find a lookup service "
+ "in the network, using groups: " + Arrays.toString(timedAdmin.getAdminGroups())
+ " and locators: " + Arrays.toString(timedAdmin.getAdminLocators()));
}
}
this.attributesFacade = new AttributesFacadeImpl(this, timedAdmin);
initialized = true;
}
private Object getRemoteApi(final String apiName) {
ElasticServiceManager elasticServiceManager;
if (timedAdmin != null) {
elasticServiceManager = timedAdmin.waitForElasticServiceManager();
String puName = ServiceUtils.getAbsolutePUName(applicationName, serviceName);
Object remoteApi = null;
remoteApi = ((InternalElasticServiceManager) elasticServiceManager)
.getRemoteApi(puName, apiName);
if (logger.isLoggable(Level.FINE)) {
if (remoteApi == null) {
logger.fine(apiName + " was not found for pu name: " + puName);
} else {
logger.fine(apiName + " successfully located for pu name: " + puName);
}
}
if (CloudifyConstants.STORAGE_REMOTE_API_KEY.equals(apiName)) {
return new StorageFacadeImpl(this, (RemoteStorageProvisioningDriver) remoteApi);
} else if (CloudifyConstants.NETWORK_REMOTE_API_KEY.equals(apiName)) {
return new NetworkFacadeImpl((RemoteNetworkProvisioningDriver) remoteApi);
}
}
return null;
}
/************
* Late initializer, used in the integrated container (i.e. test-recipe)
*
* @param service
* .
*/
public void initInIntegratedContainer(final Service service) {
this.service = service;
this.clusterInfo = new ClusterInfo(null, 1, 0, 1, 0);
if (service != null) {
this.clusterInfo.setName(service.getName());
this.serviceName = service.getName();
}
this.applicationName = CloudifyConstants.DEFAULT_APPLICATION_NAME;
this.attributesFacade = new AttributesFacadeImpl(this, timedAdmin);
initialized = true;
}
private void checkInitialized() {
if (!this.initialized) {
throw new IllegalStateException(
"The Service Context has not been initialized yet. "
+ "It can only be used after the Service file has been fully evaluated");
}
}
/*
* (non-Javadoc)
*
* @see org.cloudifysource.dsl.context.IServiceContext#getInstanceId()
*/
@Override
public int getInstanceId() {
// checkInitialized();
return clusterInfo.getInstanceId();
}
/*
* (non-Javadoc)
*
* @see org.cloudifysource.dsl.context.IServiceContext#waitForService(java.lang .String, int,
* java.util.concurrent.TimeUnit)
*/
@Override
public org.cloudifysource.domain.context.Service waitForService(
final String name, final int timeout, final TimeUnit unit) {
checkInitialized();
if (this.timedAdmin != null) {
final String puName = ServiceUtils.getAbsolutePUName(
this.applicationName, name);
final ProcessingUnit pu = waitForProcessingUnitFromAdmin(puName,
timeout, unit);
if (pu == null) {
return null;
} else {
return new ServiceImpl(
pu);
}
}
// running in integrated container
if (name.equals(this.service.getName())) {
return new ServiceImpl(
name, service.getNumInstances());
}
throw new IllegalArgumentException(
"When running in the integrated container, Service Context only includes the running service");
}
private static final java.util.logging.Logger logger = java.util.logging.Logger
.getLogger(ServiceContextImpl.class.getName());
private ProcessingUnit waitForProcessingUnitFromAdmin(final String name,
final long timeout, final TimeUnit unit) {
final ProcessingUnit pu = timedAdmin.waitForPU(name, timeout, unit);
if (pu == null) {
logger.warning("Processing unit with name: "
+ name
+ " was not found in the cluster. Are you running in an IntegratedProcessingUnitContainer? "
+ "If not, consider extending the timeout.");
}
return pu;
}
/*
* (non-Javadoc)
*
* @see org.cloudifysource.dsl.context.IServiceContext#getServiceDirectory()
*/
@Override
public String getServiceDirectory() {
return serviceDirectory;
}
/**
* Returns the Admin Object the underlies the Service Context. Note: this is intended as a debugging aid, and should
* not be used by most application. Only power users, familiar with the details of the Admin API, should use it.
*
* @return the admin.
*/
public Admin getAdmin() {
logger.warning("Using an admin object directly is not recommended. This action bypasses the admin"
+ " timing mechanism and might hinder performace");
return getOpenAdmin();
}
private synchronized Admin getOpenAdmin() {
if (openAdmin != null) {
logger.info("using a cached un-timed Admin");
return openAdmin;
}
logger.fine("creating a new un-timed Admin object");
final AdminFactory factory = new AdminFactory();
factory.useDaemonThreads(true);
factory.discoverUnmanagedSpaces();
openAdmin = factory.createAdmin();
openAdmin.setStatisticsHistorySize(0);
logger.info("Created a new un-timed Admin object with groups: " + Arrays.toString(timedAdmin.getAdminGroups())
+ " and Locators: " + Arrays.toString(timedAdmin.getAdminLocators()));
return openAdmin;
}
/**
*
* @param service
*/
void setService(final Service service) {
this.service = service;
}
public ClusterInfo getClusterInfo() {
return clusterInfo;
}
/*
* (non-Javadoc)
*
* @see org.cloudifysource.dsl.context.IServiceContext#getServiceName()
*/
@Override
public String getServiceName() {
return serviceName;
}
/*
* (non-Javadoc)
*
* @see org.cloudifysource.dsl.context.IServiceContext#getApplicationName()
*/
@Override
public String getApplicationName() {
return applicationName;
}
/*
* (non-Javadoc)
*
* @see org.cloudifysource.dsl.context.IServiceContext#getAttributes()
*/
@Override
public AttributesFacade getAttributes() {
return attributesFacade;
}
@Override
public String toString() {
if (this.initialized) {
return "ServiceContext [dir=" + serviceDirectory + ", clusterInfo="
+ clusterInfo + "]";
} else {
return "ServiceContext [NOT INITIALIZED]";
}
}
@Override
public long getExternalProcessId() {
return externalProcessId;
}
public void setExternalProcessId(final long externalProcessId) {
this.externalProcessId = externalProcessId;
}
@Override
public boolean isLocalCloud() {
String isLocalCloudStr = System.getenv(CloudifyConstants.GIGASPACES_CLOUD_MACHINE_ID);
return LOCALCLOUD.equalsIgnoreCase(isLocalCloudStr);
}
@Override
public String getPublicAddress() {
final String envVar = System
.getenv(CloudifyConstants.CLOUDIFY_AGENT_ENV_PUBLIC_IP);
if (envVar != null) {
return envVar;
}
return ServiceUtils.getPrimaryInetAddress();
}
@Override
public String getPrivateAddress() {
final String envVar = System
.getenv(CloudifyConstants.CLOUDIFY_AGENT_ENV_PRIVATE_IP);
if (envVar != null) {
return envVar;
}
return ServiceUtils.getPrimaryInetAddress();
}
@Override
public String getImageID() {
return System.getenv(CloudifyConstants.CLOUDIFY_CLOUD_IMAGE_ID);
}
@Override
public String getHardwareID() {
return System.getenv(CloudifyConstants.CLOUDIFY_CLOUD_HARDWARE_ID);
}
@Override
public String getCloudTemplateName() {
return System.getenv(CloudifyConstants.GIGASPACES_CLOUD_TEMPLATE_NAME);
}
@Override
public String getMachineID() {
return System.getenv(CloudifyConstants.GIGASPACES_CLOUD_MACHINE_ID);
}
@Override
public String getLocationId() {
return System.getenv(CloudifyConstants.CLOUDIFY_CLOUD_LOCATION_ID);
}
@Override
public StorageFacade getStorage() {
if (storageFacade == null) {
this.storageFacade = (StorageFacade) getRemoteApi(CloudifyConstants.STORAGE_REMOTE_API_KEY);
}
return storageFacade;
}
@Override
public boolean isPrivileged() {
final String envVar = System.getenv(CloudifyConstants.GIGASPACES_AGENT_ENV_PRIVILEGED);
return Boolean.valueOf(envVar);
}
@Override
public String getBindAddress() {
return System.getenv(CloudifyConstants.CLOUDIFY_CLOUD_MACHINE_IP_ADDRESS_ENV);
}
@Override
public String getAttributesStoreDiscoveryTimeout() {
return System.getenv(CloudifyConstants.USM_ATTRIBUTES_STORE_DISCOVERY_TIMEOUT_ENV_VAR);
}
@Override
public void stopMaintenanceMode() {
InternalElasticServiceManager esm = (InternalElasticServiceManager) timedAdmin.waitForElasticServiceManager();
String absolutePUName = ServiceUtils.getAbsolutePUName(getApplicationName(), getServiceName());
esm.enableAgentFailureDetection(absolutePUName);
}
@Override
public void startMaintenanceMode(final long timeout,
final TimeUnit unit) {
InternalElasticServiceManager esm = (InternalElasticServiceManager) timedAdmin.waitForElasticServiceManager();
String absolutePUName = ServiceUtils.getAbsolutePUName(getApplicationName(), getServiceName());
esm.disableAgentFailureDetection(absolutePUName, timeout, unit);
}
@Override
public NetworkFacade getNetwork() {
if (this.networkDriver == null) {
this.networkDriver = (NetworkFacade) getRemoteApi(CloudifyConstants.NETWORK_REMOTE_API_KEY);
}
return this.networkDriver;
}
}