com.eucalyptus.context.ServiceContextManager.java Source code

Java tutorial

Introduction

Here is the source code for com.eucalyptus.context.ServiceContextManager.java

Source

/*************************************************************************
 * Copyright 2009-2013 Eucalyptus Systems, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/.
 *
 * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
 * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
 * additional information or have any questions.
 *
 * This file may incorporate work covered under the following copyright
 * and permission notice:
 *
 *   Software License Agreement (BSD License)
 *
 *   Copyright (c) 2008, Regents of the University of California
 *   All rights reserved.
 *
 *   Redistribution and use of this software in source and binary forms,
 *   with or without modification, are permitted provided that the
 *   following conditions are met:
 *
 *     Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *     Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer
 *     in the documentation and/or other materials provided with the
 *     distribution.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *   COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *   BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *   CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *   POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE
 *   THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL,
 *   COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE,
 *   AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
 *   IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA,
 *   SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY,
 *   WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION,
 *   REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO
 *   IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT
 *   NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS.
 ************************************************************************/

package com.eucalyptus.context;

import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.log4j.Logger;
import org.mule.MessageExchangePattern;
import org.mule.api.MuleContext;
import org.mule.api.MuleException;
import org.mule.api.context.MuleContextFactory;
import org.mule.api.endpoint.EndpointBuilder;
import org.mule.api.endpoint.InboundEndpoint;
import org.mule.api.service.Service;
import org.mule.api.transformer.Transformer;
import org.mule.config.ConfigResource;
import org.mule.config.spring.SpringXmlConfigurationBuilder;
import org.mule.context.DefaultMuleContextFactory;
import org.mule.endpoint.EndpointURIEndpointBuilder;
import org.mule.module.client.MuleClient;
import org.mule.service.ServiceCompositeMessageSource;
import org.mule.transformer.TransformerUtils;
import com.eucalyptus.bootstrap.Bootstrap;
import com.eucalyptus.bootstrap.Bootstrapper;
import com.eucalyptus.bootstrap.OrderedShutdown;
import com.eucalyptus.bootstrap.Provides;
import com.eucalyptus.bootstrap.RunDuring;
import com.eucalyptus.component.Component;
import com.eucalyptus.component.ComponentId;
import com.eucalyptus.component.ComponentIds;
import com.eucalyptus.component.ComponentMessages;
import com.eucalyptus.component.Components;
import com.eucalyptus.component.ServiceConfiguration;
import com.eucalyptus.empyrean.Empyrean;
import com.eucalyptus.records.Logs;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.util.Templates;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.Resources;
import static com.eucalyptus.util.Parameters.checkParam;
import static org.hamcrest.Matchers.notNullValue;

public class ServiceContextManager {
    @Provides(Empyrean.class)
    @RunDuring(Bootstrap.Stage.RemoteServicesInit)
    public static class ServiceContextBootstrapper extends Bootstrapper.Simple {

        public ServiceContextBootstrapper() {
        }

        @Override
        public boolean start() throws Exception {
            new Thread() {

                @Override
                public void run() {
                    try {
                        singleton.update();
                        singleton.getClient();
                    } catch (final Exception ex) {
                        LOG.error(ex, ex);
                    }
                }

            }.start();
            return true;
        }
    }

    private static Logger CONFIG_LOG = Logger.getLogger("Configs");
    private static Logger LOG = Logger.getLogger(ServiceContextManager.class);
    private static ServiceContextManager singleton = new ServiceContextManager();

    private static final MuleContextFactory contextFactory = new DefaultMuleContextFactory();
    private final ConcurrentNavigableMap<String, String> endpointToService = new ConcurrentSkipListMap<String, String>();
    private final ConcurrentNavigableMap<String, String> serviceToEndpoint = new ConcurrentSkipListMap<String, String>();
    private final List<ComponentId> enabledCompIds = Lists.newArrayList();
    private final AtomicBoolean running = new AtomicBoolean(true);
    private final ReentrantReadWriteLock canHas = new ReentrantReadWriteLock();
    private final Lock canHasWrite;
    private final Lock canHasRead;
    private final BlockingQueue<ServiceConfiguration> queue = new LinkedBlockingQueue<ServiceConfiguration>();
    private MuleContext context;
    private MuleClient client;

    private ServiceContextManager() {
        this.canHasRead = this.canHas.readLock();
        this.canHasWrite = this.canHas.writeLock();
        OrderedShutdown.registerPreShutdownHook(new Runnable() {

            @Override
            public void run() {
                ServiceContextManager.shutdown();
            }

        });
    }

    public static final void restartSync() {
        if (singleton.canHasWrite.tryLock()) {
            try {
                singleton.update();
            } catch (final Exception ex) {
                LOG.error(Exceptions.causeString(ex));
                LOG.error(ex, ex);
            } finally {
                singleton.canHasWrite.unlock();
            }
        }
    }

    private void update() {
        if (this.context != null) {
            return;
        } else {
            this.canHasWrite.lock();
            try {
                this.context = this.createContext();
                checkParam(this.context, notNullValue());
                try {
                    this.context.start();
                    // Extend MuleClient to override method with fix as per pull request: 
                    // - https://github.com/mulesoft/mule/pull/124
                    this.client = new MuleClient(this.context) {
                        @Override
                        protected InboundEndpoint getDefaultClientEndpoint(final Service service,
                                final Object payload, final boolean sync) throws MuleException {
                            if (!(service.getMessageSource() instanceof ServiceCompositeMessageSource)) {
                                throw new IllegalStateException(
                                        "Only 'CompositeMessageSource' is supported with MuleClient.sendDirect() and MuleClient.dispatchDirect()");
                            }

                            // as we are bypassing the message transport layer we need to check that
                            InboundEndpoint endpoint = ((ServiceCompositeMessageSource) service.getMessageSource())
                                    .getEndpoints().get(0);
                            if (endpoint != null) {
                                List<Transformer> transformers = endpoint.getTransformers();
                                if (transformers != null && !transformers.isEmpty()) {
                                    // the original code here really did just check the first exception
                                    // as far as i can tell
                                    if (TransformerUtils.isSourceTypeSupportedByFirst(transformers,
                                            payload.getClass())) {
                                        return endpoint;
                                    } else {
                                        EndpointBuilder builder = new EndpointURIEndpointBuilder(endpoint);
                                        builder.setTransformers(new LinkedList());
                                        builder.setExchangePattern(MessageExchangePattern.REQUEST_RESPONSE);
                                        return getMuleContext().getEndpointFactory().getInboundEndpoint(builder);
                                    }
                                } else {
                                    return endpoint;
                                }
                            } else {
                                EndpointBuilder builder = new EndpointURIEndpointBuilder("vm://mule.client",
                                        getMuleContext());
                                builder.setName("muleClientProvider");
                                endpoint = getMuleContext().getEndpointFactory().getInboundEndpoint(builder);
                            }
                            return endpoint;
                        }
                    };
                    this.endpointToService.clear();
                    this.serviceToEndpoint.clear();
                    for (final Service service : this.context.getRegistry().lookupObjects(Service.class)) {
                        final ServiceCompositeMessageSource source = (ServiceCompositeMessageSource) service
                                .getMessageSource();
                        for (final InboundEndpoint in : source.getEndpoints()) {
                            this.endpointToService.put(in.getEndpointURI().toString(), service.getName());
                            this.serviceToEndpoint.put(service.getName(), in.getEndpointURI().toString());
                        }
                    }
                } catch (final Exception e) {
                    LOG.error(e, e);
                    throw Exceptions.toUndeclared(
                            new ServiceInitializationException("Failed to start service this.context.", e));
                }
            } finally {
                this.canHasWrite.unlock();
            }
        }
    }

    private static final String EMPTY_MODEL = "<mule xmlns=\"http://www.mulesoft.org/schema/mule/core\"\n"
            + "      xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + "      xsi:schemaLocation=\"\n"
            + "       http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.4/mule.xsd\">\n"
            + "</mule>\n";

    private MuleContext createContext() {
        List<ComponentId> currentComponentIds = ComponentIds.list();
        LOG.error("Restarting service context with these enabled services: " + currentComponentIds);
        final Set<ConfigResource> configs = Sets.newHashSet();
        MuleContext muleCtx = null;
        for (final ComponentId componentId : currentComponentIds) {
            final Component component = Components.lookup(componentId);
            final String errMsg = "Failed to render model for: " + componentId + " because of: ";
            LOG.info("-> Rendering configuration for " + componentId.name());
            try {
                final String serviceModel = this.loadModel(componentId);
                final String outString = Templates.prepare(componentId.getServiceModelFileName())
                        .withProperty("components", currentComponentIds)
                        .withProperty("ComponentMessages", ComponentMessages.class)
                        .withProperty("thisComponent", componentId).evaluate(serviceModel);
                final ConfigResource configRsc = createConfigResource(componentId, outString);
                configs.add(configRsc);
            } catch (final Exception ex) {
                LOG.error(errMsg + ex.getMessage(), ex);
            }
        }
        try {
            final SpringXmlConfigurationBuilder builder = new SpringXmlConfigurationBuilder(
                    configs.toArray(new ConfigResource[] {}));
            muleCtx = contextFactory.createMuleContext(builder);
            this.enabledCompIds.clear();
            this.enabledCompIds.addAll(currentComponentIds);
        } catch (final Exception ex) {
            LOG.error(ex, ex);
        }
        return muleCtx;
    }

    private String loadModel(final ComponentId componentId) {
        try {
            return Resources.toString(Resources.getResource(componentId.getServiceModelFileName()),
                    Charset.defaultCharset());
        } catch (final Exception ex) {
            return EMPTY_MODEL;
        }
    }

    private static ConfigResource createConfigResource(final ComponentId componentId, final String outString) {
        final ByteArrayInputStream bis = new ByteArrayInputStream(outString.getBytes());
        Logs.extreme().trace("===================================");
        Logs.extreme().trace(outString);
        Logs.extreme().trace("===================================");
        final ConfigResource configRsc = new ConfigResource(componentId.getServiceModelFileName(), bis);
        return configRsc;
    }

    private static String FAIL_MSG = "ESB client not ready because the service bus has not been started.";

    static MuleClient getClient() throws MuleException {
        singleton.update();
        return singleton.client;
    }

    static MuleContext getContext() throws MuleException {
        singleton.update();
        return singleton.context;
    }

    private void stop() {
        this.canHasWrite.lock();
        try {
            if (this.context != null) {
                try {
                    this.context.stop();
                    this.context.dispose();
                } catch (final MuleException ex) {
                    LOG.error(ex, ex);
                }
            }
        } finally {
            this.canHasWrite.unlock();
        }
    }

    public static void shutdown() {
        singleton.stop();
    }

    public static String mapServiceToEndpoint(final String service) throws Exception {
        checkParam(service, notNullValue());
        if (singleton.canHasRead.tryLock(120, TimeUnit.SECONDS)) {
            try {
                String dest = service;
                if ((!service.startsWith("vm://") && !singleton.serviceToEndpoint.containsKey(service))) {
                    dest = "vm://RequestQueue";
                } else if (!service.startsWith("vm://")) {
                    dest = singleton.serviceToEndpoint.get(dest);
                }
                return dest;
            } finally {
                singleton.canHasRead.unlock();
            }
        }
        throw Exceptions.notFound("Failed to dispatch: " + service);
    }

    public static String mapEndpointToService(final String endpoint) throws Exception {
        checkParam(endpoint, notNullValue());
        if (singleton.canHasRead.tryLock(120, TimeUnit.SECONDS)) {
            try {
                String dest = endpoint;
                if ((endpoint.startsWith("vm://") && !singleton.endpointToService.containsKey(endpoint))) {
                    throw new ServiceDispatchException("No such endpoint: " + endpoint + " in endpoints="
                            + singleton.endpointToService.entrySet());

                }
                if (endpoint.startsWith("vm://")) {
                    dest = singleton.endpointToService.get(endpoint);
                }
                return dest;
            } finally {
                singleton.canHasRead.unlock();
            }
        }
        throw Exceptions.notFound("Failed to dispatch: " + endpoint);
    }

}