Package org.wso2.carbon.cloud.csg.agent.jms

Source Code of org.wso2.carbon.cloud.csg.agent.jms.JMSServicePublisher

/*
* Copyright 2009-2010 WSO2, Inc. (http://wso2.com)
*
* 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.wso2.carbon.cloud.csg.agent.jms;


import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNode;
import org.apache.axis2.AxisFault;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.cloud.csg.agent.CSGAgentUtils;
import org.wso2.carbon.cloud.csg.agent.CSGServicePublisher;
import org.wso2.carbon.cloud.csg.agent.client.CSGAdminClient;
import org.wso2.carbon.cloud.csg.common.CSGCommonUtils;
import org.wso2.carbon.cloud.csg.common.CSGConstant;
import org.wso2.carbon.cloud.csg.common.CSGException;
import org.wso2.carbon.cloud.csg.common.CSGServerBean;
import org.wso2.carbon.cloud.csg.stub.types.common.ServiceMetaData;
import org.wso2.carbon.core.AbstractAdmin;
import org.wso2.carbon.core.multitenancy.SuperTenantCarbonContext;
import org.wso2.carbon.core.transports.util.TransportParameter;
import org.wso2.carbon.core.transports.util.TransportSummary;
import org.wso2.carbon.core.util.CryptoException;
import org.wso2.carbon.core.util.CryptoUtil;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Resource;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.service.mgt.ServiceAdmin;
import org.wso2.carbon.transport.jms.JMSTransportAdmin;
import org.wso2.carbon.transport.mgt.TransportAdmin;
import org.wso2.carbon.utils.CarbonUtils;

import java.io.File;
import java.util.Iterator;
import java.util.Properties;

/**
* The class <code>JMSServicePublisher</code> provides the API for exposing a service in JMS transport.
* The JMS model work as follows. Upon user say publish on a private service, that service will be
* exposed on JMS, at the same time a JMS proxy will be created which will actually communicate
* with the out side. If the service is in/out MEP them service will be creating a second reply
* JMS queue and the JMS proxy will be a two way JMS proxy
*/
public class JMSServicePublisher extends AbstractAdmin implements CSGServicePublisher {

    private static final Log log = LogFactory.getLog(JMSServicePublisher.class);

    /**
     * The running axis2 configuration
     */
    private AxisConfiguration axis2Conf;

    /**
     * The registry instance
     */
    private org.wso2.carbon.registry.core.Registry registry;

    private JMSTransportAdmin jmsAdmin;

    private TransportAdmin transportAdmin;


    public JMSServicePublisher() {
        axis2Conf = getAxisConfig();
        registry = getConfigSystemRegistry();
        jmsAdmin = new JMSTransportAdmin();
        transportAdmin = new TransportAdmin();
    }

    /**
     * Expose the private service in public JMS. The method is synchronized to make sure that
     * no two threads will be trying to deploy the same service.
     *
     * @param serviceName name of the service to be exposed in JMS
     * @return does the service published successfully ?
     * @throws CSGException throws in case of an error
     */
    public synchronized boolean publish(String serviceName, String serverName)
            throws CSGException {
        if (serviceName == null) {
            log.error("The service name is null");
            return false;
        }
        try {
            CSGServerBean csgServer = getCSGServerBean(serverName);
            if (csgServer == null) {
                throw new CSGException("No persist information found for the server name : " +
                        serverName);
            }
            String userName = csgServer.getUserName();
            String passWord = csgServer.getPassWord();
      String domainName = csgServer.getDomainName();

            String sessionCookie = CSGAgentUtils.getSessionCookie(getAuthServiceURL(csgServer),
                    userName, passWord, domainName, csgServer.getHost());
            CSGAdminClient csgAdminClient;
            if (CSGAgentUtils.isClientAxis2XMLExists()) {
                ConfigurationContext configCtx = ConfigurationContextFactory.
                        createConfigurationContextFromFileSystem(null, CSGConstant.CLIENT_AXIS2_XML);
                csgAdminClient = new CSGAdminClient(sessionCookie, getProxyURL(csgServer), configCtx);
            } else {
                csgAdminClient = new CSGAdminClient(sessionCookie, getProxyURL(csgServer));
            }

            boolean isExposedOnJMS = isExposedOnJMS(serviceName);

            ServiceAdmin serverAdmin = new ServiceAdmin(axis2Conf);
            serverAdmin.addTransportBinding(serviceName, CSGConstant.JMS_PREFIX);

            AxisService service = axis2Conf.getService(serviceName);

            // enable JMS transport sender if required
            // Note: we need to enable JMS sender before JMS listener otherwise
            // AbstractTransportListener.java:96 ( where we initialize transportOut) will be initialized
            // to a null value which causes the response to be lost and JMSSender at client side is
            // end up with a warning for not receiving the response
            if(hasInOutOperations(service)){
                enableJMSTransportSender(serviceName);
            }

            // enable JMS listener for this service
            enableJMSTransportListner(serviceName, csgAdminClient, userName, passWord,
                    csgServer.getHost(), csgServer.getDomainName());
            // deploy the proxy on CSG server
            csgAdminClient.deployProxy(getServiceMetaData(service, domainName));
           
            // flag the service as published
            flagServicePublishing(serviceName, serverName, true, isExposedOnJMS);
        } catch (Exception e) {
            handleException("Cloud not publish service '" + serviceName + "'", e);
        }
        return true;
    }

    /**
     * Un publish the service from public
     * @param serviceName service to unpublished
     * @return does the service unpublished successfully?
     * @throws CSGException throws in case of an error
     */
    public synchronized boolean unPublish(String serviceName, String serverName)
            throws CSGException {
        if (serviceName == null) {
            log.error("The service name is null");
            return false;
        }

        AxisService service = axis2Conf.getServiceForActivation(serviceName);
        if (service == null) {
            handleException("No service found with the name '" + serviceName + "'");
        } else {
            try {
                boolean isJMSEnabled = true;
                String flagResourcePath =
                        CSGConstant.REGISTRY_FLAG_RESOURCE_PATH + "/" + serviceName + ".flag";
                // remove the transport binding only if we add them
                if (registry.resourceExists(flagResourcePath)) {
                    Resource resource = registry.get(flagResourcePath);
                    if ("false".equals(resource.getProperty(CSGConstant.CSG_IS_JMS_ENABLED))) {
                        transportAdmin.removeExposedTransports(serviceName, CSGConstant.JMS_PREFIX);
                        isJMSEnabled = false;
                    }
                }

                CSGServerBean csgServer = getCSGServerBean(serverName);
                if (csgServer == null) {
                    throw new CSGException("No CSG server information found with the name : " +
                            serverName);
                }
                String sessionCookie = CSGAgentUtils.getSessionCookie(
                        getAuthServiceURL(csgServer),
                        csgServer.getUserName(),
                        csgServer.getPassWord(),
                        csgServer.getDomainName(),
                        csgServer.getHost());
                CSGAdminClient csgAdminClient;
                if (CSGAgentUtils.isClientAxis2XMLExists()) {
                    ConfigurationContext configCtx = ConfigurationContextFactory.
                            createConfigurationContextFromFileSystem(null, CSGConstant.CLIENT_AXIS2_XML);
                    csgAdminClient = new CSGAdminClient(sessionCookie, getProxyURL(csgServer), configCtx);
                } else {
                    csgAdminClient = new CSGAdminClient(sessionCookie, getProxyURL(csgServer));
                }
                csgAdminClient.unDeployProxy(csgServer.getDomainName() + serviceName + "Proxy");

                // flag the service as unpublished
                flagServicePublishing(serviceName, serverName, false, isJMSEnabled);
            } catch (Exception e) {
                handleException("Cloud not remove the JMS transport from the service '" +
                        serviceName + "'",e);
            }
        }
        return true;
    }

    private ServiceMetaData getServiceMetaData(AxisService service, String domainName) throws CSGException {
        try {
            ServiceMetaData privateServiceMetaData = new ServiceMetaData();
            privateServiceMetaData.setServiceName(domainName + service.getName() + "Proxy");

            ServiceAdmin serviceAdmin = new ServiceAdmin(axis2Conf);
            org.wso2.carbon.service.mgt.ServiceMetaData serviceAdminMetaData =
                    serviceAdmin.getServiceData(service.getName());

            String eprs[] = serviceAdminMetaData.getEprs();
            boolean isJMSFound = false;
            if (eprs != null) {
                for (String epr : eprs) {
                    if (epr != null && epr.contains(CSGConstant.JMS_TRANSPORT_PREFIX)) {
                        privateServiceMetaData.setEndpoint(epr);
                        isJMSFound = true;
                        break;
                    }
                }
            } else {
                throw new CSGException("Error while configuring the transports!");
            }

            if (!isJMSFound) {
                throw new CSGException("Cloud not determine the JMS epr of the service '" +
                        service.getName() + "'. This is required for service publishing. " +
                        "Check if the Qpid broker is running!");
            }

            if (serviceAdminMetaData.isActive()) {
                String wsdlLocation = serviceAdminMetaData.getWsdlURLs()[0];
                OMNode wsdNode =
                        CSGAgentUtils.getOMElementFromURI(wsdlLocation);
                OMElement wsdlElement;
                if (wsdNode instanceof OMElement) {
                    wsdlElement = (OMElement) wsdNode;
                } else {
                    throw new CSGException("Invalid instance type detected when parsing the WSDL '"
                            + wsdlLocation + "'. Required OMElement type!");
                }
                privateServiceMetaData.setInLineWSDL(wsdlElement.toStringWithConsume());
            }

            if(hasInOutOperations(service)){
                privateServiceMetaData.setHasInOutMEP(true);
            }
            return privateServiceMetaData;
        } catch (Exception e) {
            handleException("Cloud not get the meta Data", e);
        }
        return null;
    }

    /**
     * Enable the JMS transport listener for this service, this will build up a configuration
     * required by Qpid broker component, like the JNDI properties read from a property file
     * @param serviceName the service name
     * @param csgAdminClient the remote CSG admin client
     * @param userName remote CSG server's user name
     * @param passWord remote CSG server's password
     * @param host the connection url of remote csg server
     * @param domain the domain name parameter
     * @throws CSGException throws in case of an error
     */
    private void enableJMSTransportListner(String serviceName,
                                           CSGAdminClient csgAdminClient,
                                           String userName,
                                           String passWord,
                                           String host,
                                           String domain) throws CSGException {
        try {
            createOrUpdateQpidJNDIFile(csgAdminClient, serviceName, userName, passWord, domain);
            String serviceQueueConFac = serviceName + "QueueConnectionFactory";

            StringBuffer stringBuf = new StringBuffer();
            stringBuf
                .append("<parameter name=\"default\">")
                    .append("<parameter name=\"java.naming.provider.url\">").append("repository").append(File.separator).append("tenants").append(File.separator).append(domain).append(File.separator)
                    .append("csg").append(File.separator).append(CSGConstant.QPID_CONFIG_FILE).append("</parameter>")
                    .append("<parameter name=\"java.naming.factory.initial\">org.apache.qpid.wso2.jndi.TenantAwareInitialContextFactory</parameter>")
                    .append("<parameter name=\"transport.jms.ConnectionFactoryJNDIName\">QueueConnectionFactory</parameter>")
                    .append("<parameter name=\"transport.jms.ConnectionFactoryType\">queue</parameter>")
//                    .append("<parameter name=\"transport.jms.UserName\">").append(userName).append("</parameter>")
//                    .append("<parameter name=\"transport.jms.Password\">").append(passWord).append("</parameter>")
                .append("</parameter>");

            TransportParameter[] transportParam = new TransportParameter[1];
            transportParam[0] = new TransportParameter();
            transportParam[0].setName(serviceQueueConFac);
            transportParam[0].setParamElement(stringBuf.toString());
            getAxisConfig().getService(serviceName).addParameter(CSGConstant.PARAM_JMS_CONFAC,
                    serviceName +
                    "QueueConnectionFactory");
            jmsAdmin.updateServiceSpecificInParameters(serviceName, transportParam);
        } catch (Exception e) {
            handleException("Cloud not enable JMS listener for '" + serviceName + "'", e);
        }
    }

   private void createOrUpdateQpidJNDIFile(
            CSGAdminClient csgAdminClient,
            String serviceName,
            String userName,
            String passWord,
            String domain) throws CSGException {
        try {
            String maskedURL = CSGCommonUtils.getMTAwareConnectionURL(userName, passWord, domain,
                    csgAdminClient.getRemoteConnectionURL());
            String carbonTenantDir = CarbonUtils.getCarbonTenantsDirPath();
            if (carbonTenantDir != null) {
                File qpidConfFile = new File(carbonTenantDir + File.separator + domain +
                        File.separator + "csg" + File.separator, CSGConstant.QPID_CONFIG_FILE);
                String filePath = qpidConfFile.getPath();
                String queueJNDIName = serviceName + CSGConstant.CREATE_ALWAYS;
                String queueName = "queue." + serviceName;
                if (qpidConfFile.exists()) {
                    // set the JNDI name for the queue
                    // eg. queue.SimpleStockQuoteService=SimpleStockQuoteService
                    CSGCommonUtils.updatePropertyFile(qpidConfFile, queueName + "=" + queueJNDIName);
                } else {
                    // fill the new property file with intial content
                    // connectionfactory.QueueConnectionFactory=amqp://guest:guest@clientid/jkh?brokerlist='tcp://localhost:5672'
                    // queue.SimpleStockQuoteService=SimpleStockQuoteService
                    // org.apache.qpid.wso2.default.ConnectionFactoryJNDIName=QueueConnectionFactory
                    CSGCommonUtils.updatePropertyFile(qpidConfFile,
                            "connectionfactory.QueueConnectionFactory" + "=" + maskedURL);
                    CSGCommonUtils.updatePropertyFile(qpidConfFile, queueName + "="
                            + queueJNDIName);
                    CSGCommonUtils.updatePropertyFile(qpidConfFile,
                            CSGConstant.WSO2_QPID_JNDI_STRING);
                }
                Properties prop = CSGCommonUtils.loadProperties(filePath);
                csgAdminClient.createServerQpidJNDIFile(
                        getQpidJNDIString(prop, userName, passWord), domain);
            } else {
                handleException("Carbon Tenant directory could not found, this is required to" +
                        " store the Qpid JNDI property file");
            }
        } catch (AxisFault axisFault) {
            handleException("Cloud not update the Qpid JNDI file", axisFault);
        }
    }

    private void enableJMSTransportSender(String serviceName) throws CSGException{
        try {
            jmsAdmin.updateServiceSpecificOutParameters(serviceName,
                    jmsAdmin.getServiceSpecificOutParameters(serviceName));
            log.info("Enabled JMS transport Sender for the service '" + serviceName + "'");
        } catch (Exception e) {
            handleException("Clound not enable JMSSender for '" + serviceName + "'", e);
        }
    }

    /**
     * We'll be receving URL with the following format and replace that with the actual username
     * and the password
     * @param originalURL the Qpid connection URL
     * @param userName username of the user
     * @param passWord password of the user
     * @return the masked url
     */
    private String maskTheURL(String originalURL, String userName, String passWord){
        // FIXME- we may need to read the direct connection url given the username
        return originalURL.replace(CSGConstant.CSG_AMQP_USER_NAME,userName).
                replace(CSGConstant.CSG_AMQP_PASSWORD, passWord);
    }

    private String getAuthServiceURL(CSGServerBean csgServer){
        return "https://" + csgServer.getHost() + ":" + csgServer.getPort() +
                "/services/AuthenticationAdmin";
    }

    private String getProxyURL(CSGServerBean csgServer){
        return "https://" + csgServer.getHost() + ":" + csgServer.getPort() + "/services/";
    }

    private String getQpidJNDIString(Properties prop, String userName, String passWord){
        StringBuffer jndiBuf = new StringBuffer();
        Iterator itr = prop.keySet().iterator();
        while (itr.hasNext()){
            String key = (String) itr.next();
            if(key.equals("connectionfactory.QueueConnectionFactory")){
                continue;
            }
            jndiBuf.append(key).append("=").append((String)prop.get(key));
            if(itr.hasNext()){
                jndiBuf.append("&");
            }
        }
        jndiBuf.append("&").append(CSGConstant.CSG_AMQP_USER_NAME).append("=").append(userName).
                append("&").append(CSGConstant.CSG_AMQP_PASSWORD).append("=").append(passWord);
        return jndiBuf.toString();
    }

    private String getRegistryJNDIString(String jndiString, String userName, String passWord) {
        String jndiBuf = "";
        String[] tokens = jndiString.split("\n");
        for (String token : tokens) {
            if (token.contains("connectionfactory.QueueConnectionFactory")) {
                continue;
            }
            if (jndiBuf.equals("")) {
                jndiBuf = jndiBuf + token;
            } else {
                jndiBuf = jndiBuf + "&" + token;
            }
        }
        return jndiBuf + "&" + "userName=" + userName + "&passWord=" + passWord;
    }

    private CSGServerBean getCSGServerBean(String csgServerName) throws CSGException {
        CSGServerBean bean = null;
        try {
            String resourceName = CSGConstant.REGISTRY_SERVER_RESOURCE_PATH + "/" + csgServerName;
            if (registry.resourceExists(resourceName)) {
                Resource resource = registry.get(resourceName);
                try {
                    bean = new CSGServerBean();
                    bean.setHost(resource.getProperty(CSGConstant.HOST));
                    bean.setName(resource.getProperty(CSGConstant.NAME));
                    bean.setUserName(resource.getProperty(CSGConstant.USER_NAME));
                    bean.setPort(resource.getProperty(CSGConstant.PORT));
                    bean.setDomainName(resource.getProperty(CSGConstant.DOMAIN_NAME));

                    CryptoUtil cryptoUtil = CryptoUtil.getDefaultCryptoUtil();

                    bean.setPassWord(new String(cryptoUtil.base64DecodeAndDecrypt(
                            resource.getProperty("password"))));
                } catch (CryptoException e) {
                    handleException("Cloud not convert into an AXIOM element");
                }
            } else {
                throw new CSGException("Resource :" + resourceName + " does not exist");
            }
        } catch (RegistryException e) {
            handleException("Cloud not retrieve the server information for server: " +
                    csgServerName, e);
        }
        return bean;
    }

    private void flagServicePublishing(String serviceName,
                                       String serverName,
                                       boolean isPublish,
                                       boolean isJMSAlreadyEnabled)
            throws CSGException {
        try {
            if (!registry.resourceExists(CSGConstant.REGISTRY_CSG_RESOURCE_PATH)) {
                Collection collection = registry.newCollection();
                registry.put(CSGConstant.REGISTRY_CSG_RESOURCE_PATH, collection);
            }

            Resource resource = registry.newResource();
            Resource serverResource = registry.newResource();
            String serverResourcePath = CSGConstant.REGISTRY_FLAG_RESOURCE_PATH + "/" +
                    serviceName + ".server";
            if (isPublish) {
                resource.setContent(CSGConstant.CSG_PUBLISHED_FLAG);
                // FIXME: we need to think how we are going to support the case of publishing a
                // service to more than one server
                serverResource.setContent(serverName);
                if (isJMSAlreadyEnabled) {
                    resource.addProperty(CSGConstant.CSG_IS_JMS_ENABLED, "true");
                } else {
                    resource.addProperty(CSGConstant.CSG_IS_JMS_ENABLED, "false");
                }
            } else {
                resource.setContent(CSGConstant.CSG_UN_PUBLISHED_FLAG);
                // remove the published server from the list
                if (registry.resourceExists(serverResourcePath)) {
                    registry.delete(serverResourcePath);
                }
            }
            registry.put(CSGConstant.REGISTRY_FLAG_RESOURCE_PATH + "/" + serviceName + ".flag",
                    resource);
            registry.put(CSGConstant.REGISTRY_FLAG_RESOURCE_PATH + "/" + serviceName + ".server",
                    serverResource);
        } catch (RegistryException e) {
            handleException("Cloud not flag the service '" + serviceName + "'", e);
        }
    }

    private boolean isExposedOnJMS(String serviceName){
        boolean isJMSEnabled = false;
        try {
            TransportSummary[] summary = transportAdmin.listExposedTransports(serviceName);
            if(summary != null){
                for(TransportSummary exposedTrp:summary){
                    if(CSGConstant.JMS_PREFIX.equals(exposedTrp.getProtocol())){
                        isJMSEnabled = true;
                    }
                }
            }
        } catch (Exception e) {
            isJMSEnabled = false;
        }
        return isJMSEnabled;
    }

    public static String getTenantId(AxisConfiguration axisConfig) {
        SuperTenantCarbonContext carbonContext =
                SuperTenantCarbonContext.getCurrentContext(axisConfig);
        return String.valueOf(carbonContext.getTenantId());
    }

    private boolean hasInOutOperations(AxisService service) {
        for (Iterator<AxisOperation> axisOpItr = service.getOperations(); axisOpItr.hasNext();) {
            AxisOperation axisOp = axisOpItr.next();
            if (axisOp.getAxisSpecificMEPConstant() == WSDLConstants.MEP_CONSTANT_IN_OUT) {
                return true;
            }
        }
        return false;
    }

    private void handleException(String msg, Throwable t) throws CSGException {
        log.error(msg, t);
        throw new CSGException(msg, t);
    }

    private void handleException(String msg) throws CSGException {
        log.error(msg);
        throw new CSGException(msg);
    }
}
TOP

Related Classes of org.wso2.carbon.cloud.csg.agent.jms.JMSServicePublisher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.