Package org.wso2.carbon.dataservices.core

Source Code of org.wso2.carbon.dataservices.core.DBDeployer

/*
*  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*  WSO2 Inc. licenses this file to you 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.dataservices.core;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.deployment.*;
import org.apache.axis2.deployment.repository.util.DeploymentFileData;
import org.apache.axis2.deployment.util.Utils;
import org.apache.axis2.description.*;
import org.apache.axis2.description.java2wsdl.Java2WSDLConstants;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.axis2.i18n.Messages;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.axis2.wsdl.WSDLUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.commons.schema.utils.NamespaceMap;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.core.multitenancy.SuperTenantCarbonContext;
import org.wso2.carbon.dataservices.common.DBConstants;
import org.wso2.carbon.dataservices.common.DBConstants.DBSFields;
import org.wso2.carbon.dataservices.core.description.operation.Operation;
import org.wso2.carbon.dataservices.core.description.query.Query;
import org.wso2.carbon.dataservices.core.description.resource.Resource;
import org.wso2.carbon.dataservices.core.description.resource.Resource.ResourceID;
import org.wso2.carbon.dataservices.core.engine.*;
import org.wso2.carbon.dataservices.core.engine.CallQuery.WithParam;
import org.wso2.carbon.dataservices.core.internal.DataServicesDSComponent;
import org.wso2.carbon.dataservices.core.jmx.DataServiceInstance;
import org.wso2.carbon.dataservices.core.jmx.DataServiceInstanceMBean;
import org.wso2.carbon.user.core.UserStoreException;
import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.CarbonUtils;

import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

/**
* Represents the custom Axis2 deployer used in deploying data-services .dbs files.
*/
public class DBDeployer extends AbstractDeployer {
 
    public static final String HTTP_TRANSPORT = "http";
 
  public static final String HTTPS_TRANSPORT = "https";
 
  private static final Log log = LogFactory.getLog(DBDeployer.class);
 
  /**
   * Data Services directory name to be used in Axis2 service deployment
   */
  public static final String DEPLOYMENT_FOLDER_NAME = "dataservices";
 
  /**
   * Current Axis2 AxisConfiguration
   */
  private AxisConfiguration axisConfig;
 
  /**
   * Current Axis2 ConfigurationContext
   */
  private ConfigurationContext configCtx;
 
  /**
   * Data Services repository directory
   */
  private String repoDir;
 
  /**
   * Data Services file directory (i.e. '.dbs')
   */
  private String extension;
 
  /**
   * used for REST processing
   */
  private Map<String, AxisOperation> httpLocationTable;
 
  public ConfigurationContext getConfigContext() {
    return configCtx;
  }
 
  /**
   * Deploys a data service with the given deployment data.
   */
  public void deploy(DeploymentFileData deploymentFileData)
      throws DeploymentException {
    /* set the thread local variable to hold the tenant id */
    try {
            int tenantId = SuperTenantCarbonContext.getCurrentContext(this.configCtx).getTenantId();
            SuperTenantCarbonContext.getCurrentContext().setTenantId(tenantId);
            RealmService realmService = DataServicesDSComponent.getRealmService();
            if (realmService != null) {
                try {
          SuperTenantCarbonContext.getCurrentContext().setUserRealm(realmService.getBootstrapRealm());
        } catch (UserStoreException e) {
          throw new DeploymentException(e);
        }
            }
            SuperTenantCarbonContext.getCurrentContext().setUsername(CarbonConstants.REGISTRY_SYSTEM_USERNAME);
        DBUtils.setDeploymentTimeTenantId(tenantId);
    } catch (Error e) {
      /* during unit tests, this may occur */
      log.warn("Init error at DBDeployer.deploy()", e);
    }
   
    String serviceHierarchy = Utils.getServiceHierarchy(
        deploymentFileData.getAbsolutePath(), this.repoDir);
        if (serviceHierarchy == null){
            serviceHierarchy = "";
        }
       
        /* state variable kept to check if the service was successfully deployed at the end */
    boolean successfullyDeployed = false;
    /* used to store the error message if there is a problem in deploying */
    String errorMessage = null;
    /* Axis2 service to be deployed */
    AxisService service = null;
    try {
      String serviceGroupName = serviceHierarchy + this.getServiceGroupFromDSContents(
          deploymentFileData.getFile());
      AxisServiceGroup serviceGroup = this.axisConfig.getServiceGroup(serviceGroupName);
     
      /* service active property */
      boolean serviceActive = false;
     
      if (serviceGroup != null) {
        service = processService(deploymentFileData, serviceGroup, this.configCtx);
        service.setName(serviceHierarchy + service.getName());
        /* save original value */
        serviceActive = service.isActive();
        this.axisConfig.addServiceToExistingServiceGroup(service, serviceGroupName);
      } else {
        serviceGroup = new AxisServiceGroup();
        serviceGroup.setServiceGroupName(serviceGroupName);
        service = processService(deploymentFileData, serviceGroup, this.configCtx);
        service.setName(serviceHierarchy + service.getName());
        /* save original value */
        serviceActive = service.isActive();
        serviceGroup.addService(service);
        this.axisConfig.addServiceGroup(serviceGroup);
      }
     
      /* restore original service active value */
      service.setActive(serviceActive);
     
      if (log.isDebugEnabled()) {
          log.debug(Messages.getMessage(DeploymentErrorMsgs.DEPLOYING_WS,
              deploymentFileData.getName(), deploymentFileData.getAbsolutePath()));
        }
      /* finished deploying successfully */
      successfullyDeployed = true;

      /* the following section is to remove a faulty service, if there's one already registered */
            String faultyServiceFilePath = deploymentFileData.getFile().getAbsolutePath();
            AxisService faultyService = CarbonUtils.getFaultyService(faultyServiceFilePath, this.configCtx);
            if (faultyService != null) {
              this.axisConfig.removeFaultyService(faultyServiceFilePath);
            }

      super.deploy(deploymentFileData);
    } catch (DataServiceFault e) {
      errorMessage = DBUtils.getStacktraceFromException(e);
      log.error(Messages.getMessage(DeploymentErrorMsgs.INVALID_SERVICE,
          deploymentFileData.getName()), e);
      /* if there is a request to re-schedule in the exception, do it .. */
      if (DBConstants.FaultCodes.CONNECTION_UNAVAILABLE_ERROR.equals(e.getCode())) {       
        this.sheduleRedeploy(deploymentFileData, service);
      }
      DataService ds = e.getSourceDataService();
      try {
        ds.cleanup();
      } catch (DataServiceFault e2) {
        log.warn("Error in data service cleanup: " + e2.getMessage(), e2);
      }
      throw new DeploymentException(Messages.getMessage(
          DeploymentErrorMsgs.INVALID_SERVICE,
          deploymentFileData.getName()), e);
    } catch (Throwable e) {
      errorMessage = DBUtils.getStacktraceFromException(e);
      log.error(Messages.getMessage(DeploymentErrorMsgs.INVALID_SERVICE,
          deploymentFileData.getName()), e);
      throw new DeploymentException(Messages.getMessage(
          DeploymentErrorMsgs.INVALID_SERVICE,
          deploymentFileData.getName()), e);
    } finally {
      if (!successfullyDeployed)  {
        String deploymentFilePath = deploymentFileData.getFile().getAbsolutePath();             
        /* Register the faulty service */
        this.axisConfig.getFaultyServices().put(deploymentFilePath, errorMessage);
                try {
                  CarbonUtils.registerFaultyService(deploymentFilePath,
                        DBConstants.DB_SERVICE_TYPE, configCtx);
                } catch (Exception e) {
                    log.error("Cannot register faulty service with Carbon", e);
                }
      }
    }
  }
   
  /**
   * Creates a timer with a one minute delay, for re-deploying a data service.
   */
  private void sheduleRedeploy(DeploymentFileData deploymentFileData, AxisService service) {
    Runnable faultyServiceRectifier = new FaultyServiceRectifier(service,
        deploymentFileData, configCtx);
    /* Retry in one minute */
    long retryIn = 1000 * 60;
    DBUtils.scheduleTask(faultyServiceRectifier, retryIn);
  }
 
  /**
   * Initializes the deployer.
   */
  public void init(ConfigurationContext configCtx) {
    this.configCtx = configCtx;
    this.axisConfig = this.configCtx.getAxisConfiguration();
    /* init is called after the setDirectory is called so setting the
     * repoDir and the extension here. */
    configCtx.setProperty(DBConstants.DB_SERVICE_REPO, this.repoDir);
    configCtx.setProperty(DBConstants.DB_SERVICE_EXTENSION, this.extension);
    configCtx.setProperty(DBConstants.DB_SERVICE_DEPLOYER, this);
  }

  public void setDirectory(String repoDir) {
    this.repoDir = repoDir;
  }

  public String getRepoDir() {
    return repoDir;
  }
 
  public void setExtension(String extension) {
    this.extension = extension;
  }

  private DataService getDataServiceByServicePath(String servicePath) throws Exception {
    Parameter tmpParam;
    DataService tmpDS;
    String canonicalServicePath = new File(servicePath).getCanonicalPath();
    for (AxisService axisService : this.axisConfig.getServices().values()) {
      tmpParam = axisService.getParameter(DBConstants.DATA_SERVICE_OBJECT);
      if (tmpParam != null) {
        tmpDS = (DataService) tmpParam.getValue();
        if (new File(tmpDS.getDsLocation()).getCanonicalPath().equals(
            canonicalServicePath)) {
            return tmpDS;
          }
      }       
    }
    //throw new DataServiceFault("Data service at '" + servicePath + "' cannot be found");
    return null;
  }
 
  /**
   * Undeploys a service.
   */
  public void undeploy(String servicePath) throws DeploymentException {
    try {
            //set the thread local variable to hold the tenant id
            int tenantId = SuperTenantCarbonContext.getCurrentContext(this.configCtx).getTenantId();
            SuperTenantCarbonContext.getCurrentContext().setTenantId(tenantId);
            DBUtils.setDeploymentTimeTenantId(tenantId);

      DataService dataService = this.getDataServiceByServicePath(servicePath);
      if (dataService == null) {
        /* must be a faulty service */
        return;
      }
      String serviceHierarchy = Utils.getServiceHierarchy(servicePath, this.repoDir);         
          if (serviceHierarchy == null){
              serviceHierarchy = "";
          }
          String serviceGroupName = serviceHierarchy + dataService.getServiceGroup();
          String serviceName = serviceHierarchy + dataService.getName();
      AxisServiceGroup serviceGroup = this.axisConfig.getServiceGroup(serviceGroupName);
      if (serviceGroup == null) { /* must be a faulty service */
        this.axisConfig.removeFaultyService(servicePath);
      } else {
        /* cleanup data service */       
        dataService.cleanup();
        this.axisConfig.removeService(serviceName);
        /* if the service group is now empty, remove it as well */
        if (!serviceGroup.getServices().hasNext()) {
          /* when the service group is removed re-deployment causes problems */
          this.axisConfig.removeServiceGroup(serviceGroup.getServiceGroupName());
        }
      }
            if (log.isDebugEnabled()) {
                log.debug(Messages.getMessage(DeploymentErrorMsgs.SERVICE_REMOVED, serviceGroupName));
            }
            super.undeploy(servicePath);
    } catch (Exception e) {
      String msg = "Error in undeploying service";
      log.error(msg, e);
      throw new DeploymentException(msg, e);
    }
  }
 
  private String getServiceGroupFromDSContents(File file) throws Exception {
    StAXOMBuilder builder = new StAXOMBuilder(new FileInputStream(file.getAbsoluteFile()));
      OMElement serviceEl = builder.getDocumentElement();
      String serviceGroup = serviceEl.getAttributeValue(new QName(DBSFields.SERVICE_GROUP));
      if (DBUtils.isEmptyString(serviceGroup)) {
        serviceGroup = serviceEl.getAttributeValue(new QName(DBSFields.NAME));
      }
      builder.close();
      if (DBUtils.isEmptyString(serviceGroup)) {
      throw new DataServiceFault("Service group cannot be determined for the data service at '"
              + file.getAbsolutePath() + "'");
      }
      return serviceGroup;
    }

  /**
   * Configuration files prior to multiple data source support did not have id attribute
   * for config element. Adding that & saving.
   */
  @SuppressWarnings("unchecked")
  private void convertConfigToMultipleDSFormat(String configFilePath)
      throws DataServiceFault {
    FileInputStream fis = null;
    boolean changed = false;
    try {
      fis = new FileInputStream(configFilePath);
      OMElement configElement = (new StAXOMBuilder(fis)).getDocumentElement();
      configElement.build();
      Iterator<OMElement> configElements = configElement.getChildrenWithName(
          new QName(DBSFields.CONFIG));
      int emptyConfigs = 0;
      while (configElements.hasNext()) {
        OMElement config = configElements.next();
        String configId = config.getAttributeValue(new QName(DBSFields.ID));
        if (configId == null || configId.trim().length() == 0) {
          config.addAttribute(DBSFields.ID, DBConstants.DEFAULT_CONFIG_ID, null);
          changed = true;
          emptyConfigs++;
          if (emptyConfigs > 1) {
            throw new DataServiceFault("More than one config elements found in " +
                configFilePath);
          }
        }
      }
      Iterator<OMElement> queryElements = configElement.getChildrenWithName(new QName(DBSFields.QUERY));
      while (queryElements.hasNext()) {
        OMElement query = queryElements.next();
        String useConfig = query.getAttributeValue(new QName(
            DBSFields.USE_CONFIG));
        if (useConfig == null || useConfig.trim().length() == 0) {
          query.addAttribute(DBSFields.USE_CONFIG, DBConstants.DEFAULT_CONFIG_ID, null);
          changed = true;
        }
      }
      if (changed) {
        if (log.isDebugEnabled()) {
          log.debug("Converting " + configFilePath +
              " to support multiple data sources.");
        }
        BufferedWriter out = new BufferedWriter(new FileWriter(configFilePath));
        configElement.serialize(out);
        out.close();
        DBUtils.prettifyXMLFile(configFilePath);
      }
    } catch (Exception e) {
      throw new DataServiceFault(e);
    } finally {
      if (fis != null) {
        try {
          fis.close();
        } catch (IOException e) {
          log.error("Error in closing data service configuration file", e);
        }
      }
    }
  }
 
  /**
   * Creates an AxisOperation with the given data service operation object.
   * @see Operation
   * @see AxisOperation
   */
  private AxisOperation createAxisOperationFromDSOperation(Operation operation,
      AxisBinding soap11Binding, AxisBinding soap12Binding,
      AxisBinding httpBinding) throws AxisFault {
    String opName = operation.getName();
    String requestName = operation.getRequestName();
   
    int index = opName.indexOf(":");
    if (index > -1) {
      opName = opName.substring(index + 1);
    }   
    boolean hasResult = operation.getCallQueryGroup().isHasResult()
        || operation.isReturnRequestStatus()
    String description = operation.getDescription();
    return createAxisOperation(requestName, opName, HTTPConstants.HTTP_METHOD_POST, hasResult,
        soap11Binding, soap12Binding, httpBinding, description);
  }
 
  /**
   * Creates an AxisOperation with the given data service resource object.
   * @see Operation
   * @see AxisOperation
   */
  private AxisOperation createAxisOperationFromDSResource(Resource resource,
      AxisBinding soap11Binding, AxisBinding soap12Binding,
      AxisBinding httpBinding) {
    ResourceID resourceId = resource.getResourceId();
    String method = resourceId.getMethod();
    String path = resourceId.getPath();
    String requestName = resource.getRequestName();
    String description = resource.getDescription();
    boolean hasResult = resource.getCallQueryGroup().isHasResult()
        || resource.isReturnRequestStatus();   
    return createAxisOperation(requestName, path, method, hasResult, soap11Binding,
        soap12Binding, httpBinding, description);
  }
 
  /**
   * Utility method for creating AxisOperation objects.
   */
  private AxisOperation createAxisOperation(String operationName, String httpLocation,
      String method, boolean hasResult,
      AxisBinding soap11Binding, AxisBinding soap12Binding, AxisBinding httpBinding,
      String description) {
    AxisOperation axisOperation = null;
    if (hasResult) {
      axisOperation = new InOutAxisOperation(new QName(operationName));
      DBInOutMessageReceiver inoutMsgReceiver = new DBInOutMessageReceiver();
      axisOperation.setMessageReceiver(inoutMsgReceiver);
      axisOperation.setMessageExchangePattern(WSDL2Constants.MEP_URI_IN_OUT);
    } else {
      axisOperation = new InOnlyAxisOperation(new QName(operationName));
      DBInOnlyMessageReceiver inonlyMsgReceiver = new DBInOnlyMessageReceiver();
      axisOperation.setMessageReceiver(inonlyMsgReceiver);
      axisOperation.setMessageExchangePattern(WSDL2Constants.MEP_URI_ROBUST_IN_ONLY);
    }

    axisOperation.setStyle(WSDLConstants.STYLE_DOC);

    String opName = axisOperation.getName().getLocalPart();
    // Create a default SOAP 1.1 Binding operation
    AxisBindingOperation soap11BindingOperation = createDefaultSOAP11BindingOperation(
        axisOperation, httpLocation, "urn:" + opName, soap11Binding);

    // Create a default SOAP 1.2 Binding operation
    AxisBindingOperation soap12BindingOperation = createDefaultSOAP12BindingOperation(
        axisOperation, httpLocation, "urn:" + opName, soap12Binding);

    // Create a default HTTP Binding operation
    AxisBindingOperation httpBindingOperation = createDefaultHTTPBindingOperation(
        axisOperation, httpLocation, method, httpBinding);
   
    String httpLocationString = WSDLUtil.getConstantFromHTTPLocation(httpLocation, method);
    this.httpLocationTable.put(httpLocationString, axisOperation);

    // Create the in and out axis messages for this operation
    AxisMessage inMessage = axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
    if (inMessage != null) {
      inMessage.setName(operationName + Java2WSDLConstants.MESSAGE_SUFFIX);
      createAxisBindingMessage(soap11BindingOperation, inMessage, WSDLConstants.MESSAGE_LABEL_IN_VALUE, false);
      createAxisBindingMessage(soap12BindingOperation, inMessage, WSDLConstants.MESSAGE_LABEL_IN_VALUE, false);
      createAxisBindingMessage(httpBindingOperation, inMessage, WSDLConstants.MESSAGE_LABEL_IN_VALUE, false);
    }

    if (axisOperation instanceof InOutAxisOperation) {
      AxisMessage outMessage = axisOperation.getMessage(WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
      if (outMessage != null) {
        outMessage.setName(operationName + Java2WSDLConstants.RESPONSE_MESSAGE);
        createAxisBindingMessage(soap11BindingOperation, outMessage, WSDLConstants.MESSAGE_LABEL_OUT_VALUE, false);
        createAxisBindingMessage(soap12BindingOperation, outMessage, WSDLConstants.MESSAGE_LABEL_OUT_VALUE, false);
        createAxisBindingMessage(httpBindingOperation, outMessage, WSDLConstants.MESSAGE_LABEL_OUT_VALUE, false);
      }
    }
   
    AxisMessage faultMessage = new AxisMessage();
    faultMessage.setName(DBConstants.DS_FAULT_ELEMENT);
    faultMessage.setElementQName(new QName(DBConstants.WSO2_DS_NAMESPACE, DBConstants.DS_FAULT_ELEMENT));
    axisOperation.setFaultMessages(faultMessage);
   
    createAxisBindingMessage(soap11BindingOperation, faultMessage, WSDLConstants.MESSAGE_LABEL_FAULT_VALUE, true);
    createAxisBindingMessage(soap12BindingOperation, faultMessage, WSDLConstants.MESSAGE_LABEL_FAULT_VALUE, true);
    createAxisBindingMessage(httpBindingOperation, faultMessage, WSDLConstants.MESSAGE_LABEL_FAULT_VALUE, true);
   
    axisOperation.setDocumentation(description);
    return axisOperation;
  }
 
  /**
   * Creates a schema from a DataService object, to be used later in WSDL generation.
   */
  @SuppressWarnings ("unchecked")
  private void createDSSchema(AxisService axisService, DataService dataService)
      throws DataServiceFault {
    NamespaceMap map = new NamespaceMap();
    map.put(Java2WSDLConstants.DEFAULT_SCHEMA_NAMESPACE_PREFIX,
        Java2WSDLConstants.URI_2001_SCHEMA_XSD);
    axisService.setNamespaceMap(map);
    DataServiceDocLitWrappedSchemaGenerator.populateServiceSchema(axisService);
  }
 
  /**
   * Validate the data service to see if the data service is invalid.
   */
  private void validateDataService(DataService dataService) throws DataServiceFault {
    this.validateRequestCallQuery(dataService);
    this.validateRequestQueryParams(dataService);
    this.validateRequestQueryResults(dataService);
  }
 
  /**
   * Check call-queries of callable requests (i.e. operations, resources) to see if the queries
   * exists.
   */
  private void validateRequestCallQuery(DataService dataService) throws DataServiceFault {
    for (CallableRequest cr : dataService.getCallableRequests().values()) {
      for (CallQuery callQuery : cr.getCallQueryGroup().getCallQueries()) {
        if (callQuery.getQuery() == null) {
          DataServiceFault dsf = new DataServiceFault("Invalid DBS",
              "Call query with id: " + callQuery.getQueryId() +
              " doesn't exist as referenced by the operation/resource: " +
              cr.getRequestName());
          dsf.setSourceDataService(dataService);
          throw dsf;
        }
      }     
    }
  }
 
  /**
   * Check query-params if they exist in the query as mentioned in the 'with-params' in
   * operation/resource, the computational complexity of this code is not an issue, since this is
   * deployment time.
   */
  private void validateRequestQueryParams(DataService dataService) throws DataServiceFault {
    for (CallableRequest cr : dataService.getCallableRequests().values()) {
      for (CallQuery callQuery : cr.getCallQueryGroup().getCallQueries()) {
        Query query = callQuery.getQuery();
        for (WithParam withParam : callQuery.getWithParams().values()) {
          boolean found = false;
          for (QueryParam queryParam : query.getQueryParams()) {
            if (withParam.getName().equals(queryParam.getName())) {
              found = true;
              break;
            }
          }
          if (found) {
            /* param found, move onto next 'with-param' */
            continue;
          } else {
              /* the param is not found in the query, throw an exception */
            DataServiceFault dsf = new DataServiceFault("Invalid DBS",
                "with-param with name: " + withParam.getName()
                    + " doesn't exist in query with id: " + query.getQueryId()
                    + " as referenced by the operation/resource: "
                    + cr.getRequestName());
            dsf.setSourceDataService(dataService);
            throw dsf;
          }       
        }
      }     
    }
  }
 
  /**
   * Check if an request's query has a result, and if that result contain an element wrapper.
   */
  private void validateRequestQueryResults(DataService dataService) throws DataServiceFault {
    for (CallableRequest request : dataService.getCallableRequests().values()) {
      CallQueryGroup cqGroup = request.getCallQueryGroup();
      if (cqGroup == null) {
        /* we are not validating these here */
        continue;
      }
      CallQuery callQuery = cqGroup.getDefaultCallQuery();
      if (callQuery == null) {
        continue;
      }
      Query query = callQuery.getQuery();
      if (query == null) {
        continue;
      }
      if (query.getResult() != null) {
        if (DBUtils.isEmptyString(query.getResult().getElementName())) {
          throw new DataServiceFault("The request '" + request.getRequestName()
              + "' contains the query with id '" + query.getQueryId()
              + "' contains a result with no element wrapper.");
        }
      }
    }
  }
 
  /**
   * Creates AxisService from DBS.
   */
  private AxisService createDBService(String configFilePath,
      AxisConfiguration axisConfiguration) throws DataServiceFault {   
    FileInputStream fis = null;   
    try {
      /* convert to multiple config format */
      convertConfigToMultipleDSFormat(configFilePath);
     
      fis = new FileInputStream(configFilePath);
      OMElement dbsElement = (new StAXOMBuilder(fis)).getDocumentElement();
      dbsElement.build();
     
      /* create the data service object from dbs */
      DataService dataService = DataServiceFactory.createDataService(
          dbsElement, configFilePath);
     
      /* validate the data service */
      this.validateDataService(dataService);
           
      String serviceName = dataService.getName();           
      String interfaceName = serviceName + WSDL2Constants.INTERFACE_PREFIX;
     
      AxisService axisService = new AxisService(serviceName);
            try {
                axisService.setFileName(new URL("file://" + configFilePath));
            } catch (MalformedURLException e) {
                throw new DataServiceFault(e);
            }
     
      /* set service target namespace */
      axisService.setTargetNamespace(dataService.getServiceNamespace());
     
      /* Used by the container to find out what kind of a service this is. */
      axisService.addParameter(new Parameter(DBConstants.AXIS2_SERVICE_TYPE,
          DBConstants.DB_SERVICE_TYPE));
     
      /* save the data service object in the AxisService */
      axisService.addParameter(DBConstants.DATA_SERVICE_OBJECT, dataService);
     
      /* set service description */
      axisService.setDocumentation(dataService.getDescription());

      this.httpLocationTable = new TreeMap<String, AxisOperation>(
          new Comparator<String>() {
            public int compare(String o1, String o2) {
              return (-1 * o1.compareTo(o2));
            }
          });

      AxisBinding soap11Binding = createDefaultSOAP11Binding(
          serviceName, interfaceName);
      AxisBinding soap12Binding = createDefaultSOAP12Binding(
          serviceName, interfaceName);
      AxisBinding httpBinding = createDefaultHTTPBinding(serviceName,
          interfaceName);

      /* REST processing - adding DS resources to AxisService */
      Set<ResourceID> resourceIds = dataService.getResourceIds();
      for (ResourceID resourceId : resourceIds) {
        Resource resource = dataService.getResource(resourceId);
        AxisOperation axisOperation = createAxisOperationFromDSResource(
            resource, soap11Binding, soap12Binding, httpBinding);
        axisService.addOperation(axisOperation);
        axisConfig.getPhasesInfo().setOperationPhases(axisOperation);
      }

      /* add operations */
      Iterator<String> opPathItr = dataService.getOperationNames()
          .iterator();
      while (opPathItr.hasNext()) {
        Operation operation = dataService
            .getOperation(opPathItr.next());
        AxisOperation axisOperation = createAxisOperationFromDSOperation(
            operation, soap11Binding, soap12Binding, httpBinding);
        axisService.addOperation(axisOperation);
        axisConfig.getPhasesInfo().setOperationPhases(axisOperation);
      }

      createDefaultEndpoints(axisService, soap11Binding, soap12Binding,
          httpBinding);

      /* create schema */
      createDSSchema(axisService, dataService);
     
      /* set session scope type for boxcarring */
      if (dataService.isBoxcarringEnabled()) {
        axisService.setScope(Constants.SCOPE_TRANSPORT_SESSION);
      }
     
      /* register JMX MBean */
      this.registerMBean(dataService);
     
      /* set service status */
      axisService.setActive(!dataService.isServiceInactive());
     
      return axisService;
    } catch (FileNotFoundException e) {
      throw new DataServiceFault(e, "Error reading service configuration file.");
    } catch (XMLStreamException e) {
      throw new DataServiceFault(e, "Error while parsing the service configuration file.");
    } catch (AxisFault e) {
      throw new DataServiceFault(e);
    } finally {
      try {
        if (fis != null) {
            fis.close();
        }
      } catch (IOException e) {
        log.error("Error in closing data services configuration file", e);
      }
    }
  }
 
  /**
   * Registers an MBean representing the given data service.
   */
  private void registerMBean(DataService dataService) {
    DataServiceInstanceMBean dsMBean = new DataServiceInstance(dataService);
    MBeanServer server = ManagementFactory.getPlatformMBeanServer();
    if (server != null) {
      try {
        ObjectName objectName = new ObjectName(DBConstants.DATA_SERVICES_JMX_DOMAIN +
              ":section=Services,service=" +
              dsMBean.getServiceName());
        try {
          server.unregisterMBean(objectName);
        } catch (Exception ignore) {
          /* ignore if it doesn't exist */
        }
          server.registerMBean(dsMBean, objectName);
      } catch (Exception e) {
        log.error("Error in Registering Data Services MBean", e);
      }
    }
  }

  /**
   * Creates AxisBindingMessage and populates it.
   */
  private void createAxisBindingMessage(
      AxisBindingOperation bindingOperation, AxisMessage inMessage, String label, boolean isFault) {
    AxisBindingMessage soap11InBindingMessage = new AxisBindingMessage();
    soap11InBindingMessage.setName(inMessage.getName());
    soap11InBindingMessage.setAxisMessage(inMessage);
    soap11InBindingMessage.setParent(bindingOperation);
    if (isFault) {
      soap11InBindingMessage.setFault(true);
      bindingOperation.addFault(soap11InBindingMessage);
    } else {
      soap11InBindingMessage.setFault(false);
      bindingOperation.addChild(label, soap11InBindingMessage);
    }   
  }

  /**
   * Creates AxisBindingOperation and populates it with HTTP properties
   */
  private AxisBindingOperation createDefaultHTTPBindingOperation(
      AxisOperation axisOp, String httpLocation, String httpMethod,
      AxisBinding httpBinding) {
    AxisBindingOperation httpBindingOperation = new AxisBindingOperation();
    httpBindingOperation.setAxisOperation(axisOp);
    httpBindingOperation.setName(axisOp.getName());
    httpBindingOperation.setParent(httpBinding);
    httpBindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_LOCATION, httpLocation);
    httpBindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_METHOD, httpMethod);
    httpBinding.addChild(httpBindingOperation.getName(), httpBindingOperation);
    return httpBindingOperation;
  }

  /**
   * Creates AxisBindingOperation and populates it with SOAP 1.2 properties
   */ 
  private AxisBindingOperation createDefaultSOAP12BindingOperation(
      AxisOperation axisOp, String httpLocation, String inputAction,
      AxisBinding soap12Binding) {
    AxisBindingOperation soap12BindingOperation = new AxisBindingOperation();
    soap12BindingOperation.setAxisOperation(axisOp);
    soap12BindingOperation.setName(axisOp.getName());
    soap12BindingOperation.setParent(soap12Binding);
    soap12BindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_LOCATION,
        httpLocation);
    soap12Binding.addChild(soap12BindingOperation.getName(),
        soap12BindingOperation);
    soap12BindingOperation.setProperty(WSDL2Constants.ATTR_WSOAP_ACTION,
        inputAction);
    return soap12BindingOperation;
  }
 
  /**
   * Creates AxisBindingOperation and populates it with SOAP 1.1 properties
   */
  private AxisBindingOperation createDefaultSOAP11BindingOperation(   
      AxisOperation axisOp, String httpLocation, String inputAction,
      AxisBinding soap11Binding) {
    AxisBindingOperation soap11BindingOperation = new AxisBindingOperation();
    soap11BindingOperation.setAxisOperation(axisOp);
    soap11BindingOperation.setName(axisOp.getName());
    soap11BindingOperation.setParent(soap11Binding);
    soap11BindingOperation.setProperty(WSDL2Constants.ATTR_WHTTP_LOCATION,
        httpLocation);
    soap11Binding.addChild(soap11BindingOperation.getName(),
        soap11BindingOperation);
    soap11BindingOperation.setProperty(WSDL2Constants.ATTR_WSOAP_ACTION,
        inputAction);
    return soap11BindingOperation;
  }

 
  /**
   * Creates a AxisBinding and populates it with default SOAP 1.1 properties
   */
  private AxisBinding createDefaultSOAP11Binding(String name, String interfaceName) {
    AxisBinding soap11Binding = new AxisBinding();
    soap11Binding.setName(new QName(name + Java2WSDLConstants.BINDING_NAME_SUFFIX));
    soap11Binding.setType(WSDL2Constants.URI_WSDL2_SOAP);
    soap11Binding.setProperty(WSDL2Constants.ATTR_WSOAP_PROTOCOL,
        WSDL2Constants.HTTP_PROTOCAL);
    soap11Binding.setProperty(WSDL2Constants.ATTR_WSOAP_VERSION,
        SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI);
    soap11Binding.setProperty(WSDL2Constants.INTERFACE_LOCAL_NAME, interfaceName);
    soap11Binding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
    return soap11Binding;
  }

  /**
   * Creates a AxisBinding and populates it with default HTTP properties
   */
  private AxisBinding createDefaultHTTPBinding(String name, String interfaceName) {
    AxisBinding httpBinding = new AxisBinding();
    httpBinding.setName(new QName(name + Java2WSDLConstants.HTTP_BINDING));
    httpBinding.setType(WSDL2Constants.URI_WSDL2_HTTP);
    httpBinding.setProperty(WSDL2Constants.INTERFACE_LOCAL_NAME, interfaceName);
    httpBinding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
    return httpBinding;
  }
 
  /**
   * Creates a AxisBinding and populates it with default SOAP 1.2 properties
   */
  private AxisBinding createDefaultSOAP12Binding(String name, String interfaceName) {
    AxisBinding soap12Binding = new AxisBinding();
    soap12Binding.setName(new QName(name + Java2WSDLConstants.SOAP12BINDING_NAME_SUFFIX));
    soap12Binding.setType(WSDL2Constants.URI_WSDL2_SOAP);
    soap12Binding.setProperty(WSDL2Constants.ATTR_WSOAP_PROTOCOL,
        WSDL2Constants.HTTP_PROTOCAL);
    soap12Binding.setProperty(WSDL2Constants.ATTR_WSOAP_VERSION,
        SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI);
    soap12Binding.setProperty(WSDL2Constants.INTERFACE_LOCAL_NAME, interfaceName);
    soap12Binding.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
    return soap12Binding;
  }


  /**
   * Creates a set of default endpoints for this service
   */ 
  private void createDefaultEndpoints(AxisService axisService, AxisBinding soap11Binding,
      AxisBinding soap12Binding, AxisBinding httpBinding) {
    Map<String, TransportInDescription> transportsIn = axisConfig.getTransportsIn();
    Iterator<TransportInDescription> iterator = transportsIn.values().iterator();
    while (iterator.hasNext()) {
      /*
       * Used to indicate whether a HTTPEndpoint is needed. Http endpoint
       * is needed only for http and https transports
       */
      boolean needHttp = false;

      /* The prefix is used to generate endpoint names */
      String prefix = "";
      TransportInDescription transportIn = iterator.next();
      String transportInName = transportIn.getName();
      if (HTTP_TRANSPORT.equalsIgnoreCase(transportInName)) {
        needHttp = true;
      } else if (HTTPS_TRANSPORT.equalsIgnoreCase(transportInName)) {
        needHttp = true;
        prefix = WSDL2Constants.DEFAULT_HTTPS_PREFIX;
      } else if (transportInName != null) {
        prefix = transportInName.toUpperCase();
      }

      /* Creates a default SOAP 1.1 endpoint */
      AxisEndpoint soap11Endpoint = new AxisEndpoint();
      String soap11EndpointName = prefix
          + WSDL2Constants.DEFAULT_SOAP11_ENDPOINT_NAME;
      soap11Endpoint.setName(soap11EndpointName);
      soap11Endpoint.setBinding(soap11Binding);
      soap11Endpoint.setParent(axisService);
      soap11Endpoint.setTransportInDescription(transportInName);
      soap11Endpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
      axisService.addEndpoint(soap11EndpointName, soap11Endpoint);
     
            /* setting soap11 endpoint as the default endpoint */
      axisService.setEndpointName(soap11EndpointName);

      /* Creates a default SOAP 1.2 endpoint */
      AxisEndpoint soap12Endpoint = new AxisEndpoint();
      String soap12EndpointName = prefix
          + WSDL2Constants.DEFAULT_SOAP12_ENDPOINT_NAME;
      soap12Endpoint.setName(soap12EndpointName);
      soap12Endpoint.setBinding(soap12Binding);
      soap12Endpoint.setParent(axisService);
      soap12Endpoint.setTransportInDescription(transportInName);
      soap12Endpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
      axisService.addEndpoint(soap12EndpointName, soap12Endpoint);

      /* Creates a HTTP endpoint if its http or https transport is used */
      if (needHttp) {
        AxisEndpoint httpEndpoint = new AxisEndpoint();
        String httpEndpointName = prefix
            + WSDL2Constants.DEFAULT_HTTP_ENDPOINT_NAME;
        httpEndpoint.setName(httpEndpointName);
        httpEndpoint.setBinding(httpBinding);
        httpEndpoint.setParent(axisService);
        httpEndpoint.setTransportInDescription(transportInName);
        httpEndpoint.setProperty(WSDL2Constants.HTTP_LOCATION_TABLE, httpLocationTable);
        axisService.addEndpoint(httpEndpointName, httpEndpoint);
      }
    }
  }

  /**
   * This method checks if the given data service has a corresponding "services.xml" is available,
   * if so, the AxisService representing the data service is applied the instructions from its
   * "services.xml".
   */
  private AxisService handleServicesXML(String dbsPath, AxisServiceGroup axisServiceGroup,
      AxisService axisService) throws DataServiceFault {
    try {
      String serviceXMLPath = dbsPath.substring(0, dbsPath.length() - 4) +
              DBConstants.DBS_SERVICES_XML_SUFFIX;
      File servicesXMLFile = new File(serviceXMLPath);
      if (servicesXMLFile.exists()) {
        XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(
            new FileInputStream(servicesXMLFile));
        StAXOMBuilder builder = new StAXOMBuilder(parser);
        OMElement documentElement =  builder.getDocumentElement();
        if (documentElement.getLocalName().equals(DBConstants.AXIS2_SERVICE_GROUP)) {
          HashMap<String, AxisService> wsdlServices = new HashMap<String, AxisService>();
          wsdlServices.put(axisService.getName(), axisService);
          ServiceGroupBuilder sgb = new ServiceGroupBuilder(documentElement,
              wsdlServices, this.getConfigContext());
          axisService = sgb.populateServiceGroup(axisServiceGroup).get(0);         
        } else if (documentElement.getLocalName().equals(DBConstants.AXIS2_SERVICE)) {
          ServiceBuilder sb = new ServiceBuilder(this.getConfigContext(),
              axisService);
          axisService = sb.populateService(documentElement);
        } else {
          throw new DataServiceFault("services xml file: " + serviceXMLPath +
              " is not valid, cannot find the 'service' or 'serviceGroup' element");
        }
      }
    } catch (Exception e) {
      throw new DataServiceFault(e, "Error in processing services.xml");
    }
    return axisService;
  }
 
  /**
   * Creates AxisService with the given deployment information.
   */
  private AxisService processService(DeploymentFileData currentFile,
      AxisServiceGroup axisServiceGroup, ConfigurationContext configCtx)
      throws DataServiceFault {
    AxisService axisService = createDBService(currentFile.getAbsolutePath(),
        configCtx.getAxisConfiguration());
    axisService.setParent(axisServiceGroup);
    axisService.setClassLoader(axisConfig.getServiceClassLoader());
        /* handle services.xml, if exists */
    this.handleServicesXML(currentFile.getAbsolutePath(), axisServiceGroup, axisService);
    return axisService;
  }
 
}
TOP

Related Classes of org.wso2.carbon.dataservices.core.DBDeployer

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.