All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.microsoft.windowsazure.serviceruntime.RoleEnvironment Maven / Gradle / Ivy

/**
 * Copyright Microsoft Corporation
 * 
 * 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.microsoft.windowsazure.serviceruntime;

import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

/**
 * Represents the Windows Azure environment in which an instance of a role is
 * running.
 */
public final class RoleEnvironment {
    private static final String VersionEndpointEnvironmentName = "WaRuntimeEndpoint";
    private static final String VersionEndpointFixedPath = "\\\\.\\pipe\\WindowsAzureRuntime";
    private static final String clientId;

    private static RuntimeClient runtimeClient;
    private static AtomicReference currentGoalState;
    private static AtomicReference currentEnvironmentData;
    private static List changingListeners;
    private static List changedListeners;
    private static List stoppingListeners;
    private static AtomicReference lastState;
    private static final Calendar maxDateTime;

    static {
        try {
            JAXBContext.newInstance(RoleEnvironment.class.getPackage().getName());
        }
        catch (JAXBException e) {
            e.printStackTrace();
        }
        clientId = UUID.randomUUID().toString();
        maxDateTime = javax.xml.bind.DatatypeConverter.parseDateTime("9999-12-31T23:59:59.9999999");
    }

    private RoleEnvironment() {
    };

    private static synchronized void initialize() {
        if (runtimeClient == null) {
            String endpoint = System.getenv(VersionEndpointEnvironmentName);

            if (endpoint == null) {
                endpoint = VersionEndpointFixedPath;
            }

            RuntimeKernel kernel = RuntimeKernel.getKernel();

            try {
                runtimeClient = kernel.getRuntimeVersionManager().getRuntimeClient(endpoint);
            }
            catch (Throwable t) {
                throw new RoleEnvironmentNotAvailableException(t);
            }

            changingListeners = new LinkedList();
            changedListeners = new LinkedList();
            stoppingListeners = new LinkedList();

            try {
                currentGoalState = new AtomicReference(runtimeClient.getCurrentGoalState());
                currentEnvironmentData = new AtomicReference(
                        runtimeClient.getRoleEnvironmentData());
            }
            catch (InterruptedException e) {
                throw new RoleEnvironmentNotAvailableException(e);
            }

            lastState = new AtomicReference();

            runtimeClient.addGoalStateChangedListener(new GoalStateChangedListener() {
                @Override
                public void goalStateChanged(GoalState newGoalState) {
                    switch (newGoalState.getExpectedState()) {
                        case STARTED:
                            if (newGoalState.getIncarnation().compareTo(currentGoalState.get().getIncarnation()) > 0) {
                                processGoalStateChange(newGoalState);
                            }
                            break;
                        case STOPPED:
                            raiseStoppingEvent();

                            CurrentState stoppedState = new AcquireCurrentState(clientId,
                                    newGoalState.getIncarnation(), CurrentStatus.STOPPED, maxDateTime);

                            runtimeClient.setCurrentState(stoppedState);
                            break;
                    }
                }
            });
        }
        else {
            try {
                currentGoalState.set(runtimeClient.getCurrentGoalState());
                currentEnvironmentData.set(runtimeClient.getRoleEnvironmentData());
            }
            catch (InterruptedException e) {
                throw new RoleEnvironmentNotAvailableException(e);
            }
        }
    }

    private static void processGoalStateChange(GoalState newGoalState) {
        List changes = new LinkedList();
        RoleEnvironmentChangingEvent changingEvent = new RoleEnvironmentChangingEvent(changes);
        CurrentState last = lastState.get();

        calculateChanges(changes);

        if (changes.isEmpty()) {
            acceptLatestIncarnation(newGoalState, last);
        }
        else {
            for (RoleEnvironmentChangingListener listener : changingListeners) {
                try {
                    listener.roleEnvironmentChanging(changingEvent);
                }
                catch (Throwable t) {
                    t.printStackTrace();
                }
            }

            if (changingEvent.isCancelled()) {
                CurrentState recycleState = new AcquireCurrentState(clientId, newGoalState.getIncarnation(),
                        CurrentStatus.RECYCLE, maxDateTime);

                runtimeClient.setCurrentState(recycleState);

                return;
            }

            acceptLatestIncarnation(newGoalState, last);

            try {
                currentEnvironmentData.set(runtimeClient.getRoleEnvironmentData());
            }
            catch (InterruptedException e) {
                throw new RoleEnvironmentNotAvailableException(e);
            }

            for (RoleEnvironmentChangedListener listener : changedListeners) {
                try {
                    listener.roleEnvironmentChanged(new RoleEnvironmentChangedEvent(changes));
                }
                catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        }
    }

    private static void acceptLatestIncarnation(GoalState newGoalState, CurrentState last) {
        if (last != null && last instanceof AcquireCurrentState) {
            AcquireCurrentState acquireState = (AcquireCurrentState) last;

            CurrentState acceptState = new AcquireCurrentState(clientId, newGoalState.getIncarnation(),
                    acquireState.getStatus(), acquireState.getExpiration());

            runtimeClient.setCurrentState(acceptState);
        }

        currentGoalState.set(newGoalState);
    }

    private static void calculateChanges(List changes) {
        RoleEnvironmentData current = currentEnvironmentData.get();
        RoleEnvironmentData newData;

        try {
            newData = runtimeClient.getRoleEnvironmentData();
        }
        catch (InterruptedException e) {
            throw new RoleEnvironmentNotAvailableException(e);
        }

        Map currentConfig = current.getConfigurationSettings();
        Map newConfig = newData.getConfigurationSettings();
        Map currentRoles = current.getRoles();
        Map newRoles = newData.getRoles();

        for (String setting : currentConfig.keySet()) {
            if (newConfig.containsKey(setting)) {
                if (!newConfig.get(setting).equals(currentConfig.get(setting))) {
                    changes.add(new RoleEnvironmentConfigurationSettingChange(setting));
                }
            }
            else {
                changes.add(new RoleEnvironmentConfigurationSettingChange(setting));
            }
        }

        for (String setting : newConfig.keySet()) {
            if (!currentConfig.containsKey(setting)) {
                changes.add(new RoleEnvironmentConfigurationSettingChange(setting));
            }
        }

        Set changedRoleSet = new HashSet();

        for (String role : currentRoles.keySet()) {
            if (newRoles.containsKey(role)) {
                Role currentRole = currentRoles.get(role);
                Role newRole = newRoles.get(role);

                for (String instance : currentRole.getInstances().keySet()) {
                    if (newRole.getInstances().containsKey(instance)) {
                        RoleInstance currentInstance = currentRole.getInstances().get(instance);
                        RoleInstance newInstance = newRole.getInstances().get(instance);

                        if (currentInstance.getUpdateDomain() == newInstance.getUpdateDomain()
                                && currentInstance.getFaultDomain() == newInstance.getFaultDomain()) {
                            for (String endpoint : currentInstance.getInstanceEndpoints().keySet()) {
                                if (newInstance.getInstanceEndpoints().containsKey(endpoint)) {
                                    RoleInstanceEndpoint currentEndpoint = currentInstance.getInstanceEndpoints().get(
                                            endpoint);
                                    RoleInstanceEndpoint newEndpoint = newInstance.getInstanceEndpoints().get(endpoint);

                                    if (!currentEndpoint.getProtocol().equals(newEndpoint.getProtocol())
                                            || !currentEndpoint.getIpEndPoint().equals(newEndpoint.getIpEndPoint())) {
                                        changedRoleSet.add(role);
                                    }
                                }
                                else {
                                    changedRoleSet.add(role);
                                }
                            }
                        }
                        else {
                            changedRoleSet.add(role);
                        }
                    }
                    else {
                        changedRoleSet.add(role);
                    }
                }
            }
            else {
                changedRoleSet.add(role);
            }
        }

        for (String role : newRoles.keySet()) {
            if (currentRoles.containsKey(role)) {
                Role currentRole = currentRoles.get(role);
                Role newRole = newRoles.get(role);

                for (String instance : newRole.getInstances().keySet()) {
                    if (currentRole.getInstances().containsKey(instance)) {
                        RoleInstance currentInstance = currentRole.getInstances().get(instance);
                        RoleInstance newInstance = newRole.getInstances().get(instance);

                        if (currentInstance.getUpdateDomain() == newInstance.getUpdateDomain()
                                && currentInstance.getFaultDomain() == newInstance.getFaultDomain()) {
                            for (String endpoint : newInstance.getInstanceEndpoints().keySet()) {
                                if (currentInstance.getInstanceEndpoints().containsKey(endpoint)) {
                                    RoleInstanceEndpoint currentEndpoint = currentInstance.getInstanceEndpoints().get(
                                            endpoint);
                                    RoleInstanceEndpoint newEndpoint = newInstance.getInstanceEndpoints().get(endpoint);

                                    if (!currentEndpoint.getProtocol().equals(newEndpoint.getProtocol())
                                            || !currentEndpoint.getIpEndPoint().equals(newEndpoint.getIpEndPoint())) {
                                        changedRoleSet.add(role);
                                    }
                                }
                                else {
                                    changedRoleSet.add(role);
                                }
                            }
                        }
                        else {
                            changedRoleSet.add(role);
                        }
                    }
                    else {
                        changedRoleSet.add(role);
                    }
                }
            }
            else {
                changedRoleSet.add(role);
            }
        }

        for (String role : changedRoleSet) {
            changes.add(new RoleEnvironmentTopologyChange(role));
        }
    }

    private static synchronized void raiseStoppingEvent() {
        for (RoleEnvironmentStoppingListener listener : stoppingListeners) {
            try {
                listener.roleEnvironmentStopping();
            }
            catch (Throwable t) {
                t.printStackTrace();
            }
        }
    }

    /**
     * Returns a {@link RoleInstance} object that represents the role instance
     * in which this code is currently executing.
     * 
     * @return A RoleInstance object that represents the role
     *         instance in which this code is currently executing.
     */
    public static RoleInstance getCurrentRoleInstance() {
        initialize();

        return currentEnvironmentData.get().getCurrentInstance();
    }

    /**
     * Returns the deployment ID that uniquely identifies the deployment in
     * which this role instance is running.
     * 
     * @return A String object that represents the deployment ID.
     */
    public static String getDeploymentId() {
        initialize();

        return currentEnvironmentData.get().getDeploymentId();
    }

    /**
     * Indicates whether the role instance is running in the Windows Azure
     * environment.
     * 
     * @return true if this instance is running in the development
     *         fabric or in the Windows Azure environment in the cloud;
     *         otherwise, false.
     */
    public static boolean isAvailable() {
        try {
            initialize();
        }
        catch (RoleEnvironmentNotAvailableException ex) {
        }

        return runtimeClient != null;
    }

    /**
     * Indicates whether the role instance is running in the development fabric.
     * 
     * @return true if this instance is running in the development
     *         fabric; otherwise, false.
     */
    public static boolean isEmulated() {
        initialize();

        return currentEnvironmentData.get().isEmulated();
    }

    /**
     * Returns the set of {@link Role} objects defined for your service.
     * 

* Roles are defined in the service definition file. * * @return A java.util.Map object containing the set of {@link Role} objects that represent the roles * defined for your * service. */ public static Map getRoles() { initialize(); return currentEnvironmentData.get().getRoles(); } /** * Retrieves the settings in the service configuration file. *

* A role's configuration settings are defined in the service definition file. Values for configuration settings are * set in the service configuration file. * * @return A java.util.Map object containing the String objects that represent the * configuration * settings. */ public static Map getConfigurationSettings() { initialize(); return currentEnvironmentData.get().getConfigurationSettings(); } /** * Retrieves the set of named local storage resources. * * @return A java.util.Map object containing the String objects that represent the local * storage * resources. */ public static Map getLocalResources() { initialize(); return currentEnvironmentData.get().getLocalResources(); } /** * Requests that the current role instance be stopped and restarted. *

* Before the role instance is recycled, the Windows Azure load balancer takes the role instance out of rotation. * This ensures that no new requests are routed to the instance while it is restarting. * * A call to RequestRecycle initiates the normal shutdown cycle. Windows Azure raises the * Stopping event and calls the OnStop method so that you can run the necessary code to * prepare the instance to be recycled. */ public static void requestRecycle() { initialize(); CurrentState recycleState = new AcquireCurrentState(clientId, currentGoalState.get().getIncarnation(), CurrentStatus.RECYCLE, maxDateTime); runtimeClient.setCurrentState(recycleState); } /** * Sets the status of the role instance. *

* An instance may indicate that it is in one of two states: Ready or Busy. If an instance's state is Ready, it is * prepared to receive requests from the load balancer. If the instance's state is Busy, it will not receive * requests from the load balancer. * * @param status * A {@link RoleInstanceStatus} value that indicates whether the * instance is ready or busy. * @param expiration_utc * A java.util.Date value that specifies the * expiration date and time of the status. * */ public static void setStatus(RoleInstanceStatus status, Date expiration_utc) { initialize(); CurrentStatus currentStatus = CurrentStatus.STARTED; switch (status) { case Busy: currentStatus = CurrentStatus.BUSY; break; case Ready: currentStatus = CurrentStatus.STARTED; } Calendar expiration = Calendar.getInstance(); expiration.setTime(expiration_utc); CurrentState newState = new AcquireCurrentState(clientId, currentGoalState.get().getIncarnation(), currentStatus, expiration); lastState.set(newState); runtimeClient.setCurrentState(newState); } /** * Clears the status of the role instance. *

* An instance may indicate that it has completed communicating status by calling this method. * */ public static void clearStatus() { initialize(); CurrentState newState = new ReleaseCurrentState(clientId); lastState.set(newState); runtimeClient.setCurrentState(newState); } /** * Adds an event listener for the Changed event, which occurs * after a configuration change has been applied to a role instance. *

* A Changed event is encapsulated in a {@link RoleEnvironmentChangedEvent} object. * * @param listener * A {@link RoleEnvironmentChangedListener} object that * represents the event listener to add. * * @see #removeRoleEnvironmentChangedListener */ public static synchronized void addRoleEnvironmentChangedListener(RoleEnvironmentChangedListener listener) { initialize(); changedListeners.add(listener); } /** * Removes an event listener for the Changed event. * * @param listener * A {@link RoleEnvironmentChangedListener} object that * represents the event listener to remove. * * @see #addRoleEnvironmentChangedListener */ public static synchronized void removeRoleEnvironmentChangedListener(RoleEnvironmentChangedListener listener) { initialize(); changedListeners.remove(listener); } /** * Adds an event listener for the Changing event, which occurs * before a change to the service configuration is applied to the running * instances of the role. *

* Service configuration changes are applied on-the-fly to running role instances. Configuration changes include * changes to the service configuration changes and changes to the number of instances in the service. *

* This event occurs after the new configuration file has been submitted to Windows Azure but before the changes * have been applied to each running role instance. This event can be cancelled for a given instance to prevent the * configuration change. *

* Note that cancelling this event causes the instance to be automatically recycled. When the instance is recycled, * the configuration change is applied when it restarts. *

* A Changing event is encapsulated in a {@link RoleEnvironmentChangingEvent} object. * * @param listener * A {@link RoleEnvironmentChangingListener} object that * represents the event listener to add. * * @see #removeRoleEnvironmentChangingListener */ public static synchronized void addRoleEnvironmentChangingListener(RoleEnvironmentChangingListener listener) { initialize(); changingListeners.add(listener); } /** * Removes an event listener for the Changing event. * * @param listener * A {@link RoleEnvironmentChangingListener} object that * represents the event listener to remove. * * @see #addRoleEnvironmentChangingListener */ public static void removeRoleEnvironmentChangingListener(RoleEnvironmentChangingListener listener) { initialize(); changingListeners.remove(listener); } /** * Adds an event listener for the Stopping event, which occurs * wheen the role is stopping. * * @param listener * A {@link RoleEnvironmentStoppingListener} object that * represents the event listener to add. * * @see #removeRoleEnvironmentStoppingListener */ public static synchronized void addRoleEnvironmentStoppingListener(RoleEnvironmentStoppingListener listener) { initialize(); stoppingListeners.add(listener); } /** * Removes an event listener for the Stopping event. * * @param listener * A {@link RoleEnvironmentStoppingListener} object that * represents the event listener to remove. * * @see #addRoleEnvironmentStoppingListener */ public static synchronized void removeRoleEnvironmentStoppingListener(RoleEnvironmentStoppingListener listener) { initialize(); stoppingListeners.remove(listener); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy