Java tutorial
/* * 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.util.AXIOMUtil; import org.apache.axis2.AxisFault; import org.apache.axis2.description.*; import org.apache.axis2.engine.AxisConfiguration; import org.apache.axis2.schema.CompilerOptions; import org.apache.axis2.schema.SchemaCompilationException; import org.apache.axis2.schema.SchemaCompiler; import org.apache.axis2.util.XMLPrettyPrinter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.ws.commons.schema.*; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.wso2.carbon.dataservices.common.DBConstants; import org.wso2.carbon.dataservices.core.auth.AuthorizationProvider; import org.wso2.carbon.dataservices.core.auth.UserStoreAuthorizationProvider; import org.wso2.carbon.dataservices.core.description.config.Config; import org.wso2.carbon.dataservices.core.description.config.RDBMSConfig; import org.wso2.carbon.dataservices.core.description.operation.Operation; import org.wso2.carbon.dataservices.core.description.query.SQLQuery; import org.wso2.carbon.dataservices.core.engine.*; import org.wso2.carbon.dataservices.core.engine.CallQuery.WithParam; import org.wso2.carbon.dataservices.core.validation.Validator; import javax.xml.namespace.QName; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.*; import java.net.URL; import java.util.*; /** * This class is used to create a data service using a given WSDL (create * contract first data services). */ public class WSDLToDataService { private static final Log log = LogFactory.getLog(WSDLToDataService.class); private static final String WSDL20_ROOT_ELEMENT = "description"; private WSDLToDataService() { } /** * Checks if the given data is from a WSDL2.0 document. * @param wsdlContent The WSDL document data * @return true if it is a WSDL2.0 document * @throws DataServiceFault */ private static boolean isWSDL20(byte[] wsdlContent) throws DataServiceFault { try { return (AXIOMUtil.stringToOM(new String(wsdlContent, DBConstants.DEFAULT_CHAR_SET_TYPE)).getLocalName() .equals(WSDL20_ROOT_ELEMENT)); } catch (Exception e) { throw new DataServiceFault(e); } } /** * Creates and deploys a contract first data service with the given WSDL * data. * @param axisConfig The current axis configuration * @param wsdlContent The WSDL content * @throws DataServiceFault */ public static void deployDataService(AxisConfiguration axisConfig, byte[] wsdlContent) throws DataServiceFault { try { AxisService axisService = getAxisServiceFromWSDL(wsdlContent); String serviceName = axisService.getName(); DataService dataService = createDataServiceFromAxisService(axisService); String dsContents = DataServiceSerializer.serializeDataService(dataService).toString(); writeToRepository(axisConfig, serviceName, dsContents); } catch (DataServiceFault e) { log.error("Error in deploying contract first data service", e); throw e; } } /** * Populates and returns an AxisService from a WSDL. * @param wsdlContent The WSDL content * @return AxisService which represents the given WSDL * @throws DataServiceFault */ private static AxisService getAxisServiceFromWSDL(byte[] wsdlContent) throws DataServiceFault { try { AxisService axisService; ByteArrayInputStream byteIn = new ByteArrayInputStream(wsdlContent); if (isWSDL20(wsdlContent)) { axisService = new WSDL20ToAxisServiceBuilder(byteIn, null, null).populateService(); } else { // Must be WSDL11 axisService = new WSDL11ToAxisServiceBuilder(byteIn, null, null).populateService(); } return axisService; } catch (AxisFault e) { String message = "Error in getting AxisService from WSDL"; throw new DataServiceFault(e, message); } } /** * Write the data service to the deployment directory. * @param axisConfig The current AxisConfiguration * @param serviceName The name of the service to be deployed * @param dsContents The contents of the data service configuration * @throws DataServiceFault */ private static void writeToRepository(AxisConfiguration axisConfig, String serviceName, String dsContents) throws DataServiceFault { try { URL repositoryURL = axisConfig.getRepository(); String dataservicesFile = repositoryURL.getPath() + File.separator + DBDeployer.DEPLOYMENT_FOLDER_NAME + File.separator + serviceName + "." + DBConstants.DBS_FILE_EXTENSION; File parentFile = new File(dataservicesFile).getParentFile(); if (!parentFile.exists()) { parentFile.mkdirs(); } BufferedWriter writer = new BufferedWriter(new FileWriter(dataservicesFile)); writer.write(dsContents); writer.close(); XMLPrettyPrinter.prettify(new File(dataservicesFile)); } catch (IOException e) { String message = "Error in writing the contract first data service to the repository"; throw new DataServiceFault(e, message); } } /** * Creates a dummy data source config. * @param dataService The current data service * @param configId The configuration id of the config to be created * @return The newly created dummy config * @throws DataServiceFault */ private static Config getDummyConfig(DataService dataService, String configId) throws DataServiceFault { Map<String, String> props = new HashMap<String, String>(); props.put(DBConstants.RDBMS.DRIVER_CLASSNAME, null); props.put(DBConstants.RDBMS.URL, null); props.put(DBConstants.RDBMS.USERNAME, null); props.put(DBConstants.RDBMS.PASSWORD, null); RDBMSConfig config = new RDBMSConfig(dataService, configId, props); return config; } private static String extractServiceNameFromHeirachicalName(String name) { int lastIndex = name.length() - 1; int index = name.lastIndexOf('\\'); if (index != -1 && index < lastIndex) { return name.substring(index + 1); } index = name.lastIndexOf('/'); if (index != -1 && index < lastIndex) { return name.substring(index + 1); } return name; } /** * Create a DataService from an AxisService. * @param axisService The AxisService used to create the DS * @return The newly created data service * @throws DataServiceFault */ @SuppressWarnings("unchecked") private static DataService createDataServiceFromAxisService(AxisService axisService) throws DataServiceFault { DataService dataService = new DataService(extractServiceNameFromHeirachicalName(axisService.getName()), null, null, null, DBConstants.ServiceStatusValues.INACTIVE, false, false, null); /* setting default authorization provider */ dataService.setAuthorizationProvider(new UserStoreAuthorizationProvider()); /* add dummy config */ String dummyConfigId = DBConstants.DEFAULT_CONFIG_ID; dataService.addConfig(getDummyConfig(dataService, dummyConfigId)); /* compile schema */ Map<QName, Document> modelMap; Map<QName, String> elementMap; try { CompilerOptions options = new CompilerOptions(); SchemaCompiler schemaCompiler = new SchemaCompiler(options); schemaCompiler.compile(axisService.getSchema()); modelMap = schemaCompiler.getProcessedModelMap(); elementMap = schemaCompiler.getProcessedElementMap(); } catch (SchemaCompilationException e) { throw new DataServiceFault(e, "Error in schema compile"); } /* add queries/operations */ AxisOperation axisOperation; String operationName; String queryId; List<QueryParam> queryParams; for (Iterator<AxisOperation> axisOperations = axisService.getOperations(); axisOperations.hasNext();) { axisOperation = axisOperations.next(); operationName = axisOperation.getName().getLocalPart(); queryId = operationName + DBConstants.CONTRACT_FIRST_QUERY_SUFFIX; queryParams = getQueryParamsFromAxisOperation(modelMap, elementMap, axisOperation); /* query */ dataService.addQuery(new SQLQuery(dataService, queryId, dummyConfigId, false, false, null, DBConstants.CONTRACT_FIRST_DUMMY_SQL, queryParams, getResultFromAxisOperation(dataService, axisOperation), null, null, new HashMap<String, String>(), dataService.getServiceNamespace())); /* operation */ dataService.addOperation(new Operation(dataService, operationName, null, getOperationCallQueryFromQueryParams(dataService, queryId, queryParams), false, null, false, false)); } return dataService; } private static CallQuery getOperationCallQueryFromQueryParams(DataService dataService, String queryId, List<QueryParam> queryParams) throws DataServiceFault { Map<String, WithParam> withParams = new HashMap<String, WithParam>(); for (QueryParam qp : queryParams) { withParams.put(qp.getName(), new WithParam(qp.getName(), qp.getName(), qp.getName(), DBConstants.DBSFields.QUERY_PARAM)); } return new CallQuery(dataService, queryId, withParams, new HashSet<String>()); } private static AxisMessage getAxisMessageFromOperation(AxisOperation axisOperation, String direction) { Iterator<AxisMessage> msgs = axisOperation.getMessages(); AxisMessage tmpAxisMessage = null; while (msgs.hasNext()) { tmpAxisMessage = msgs.next(); if (tmpAxisMessage.getDirection().equals(direction)) { return tmpAxisMessage; } } return null; } /** * Prints the given DOM document, * used for debugging purposes. */ public static void printDOM(Document dom) { try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); DOMSource domSource = new DOMSource(dom); StreamResult streamResult = new StreamResult(System.out); transformer.transform(domSource, streamResult); } catch (Exception e) { e.printStackTrace(); } } private static List<QueryParam> getQueryParamsFromAxisOperation(Map<QName, Document> modelMap, Map<QName, String> elementMap, AxisOperation axisOperation) throws DataServiceFault { AxisMessage axisMessage = getAxisMessageFromOperation(axisOperation, "in"); if (axisMessage == null) { throw new DataServiceFault( "Valid in message cannot be found for the operation '" + axisOperation.getName() + "'"); } XmlSchemaElement inMsgElement = axisMessage.getSchemaElement(); /* no query params - return empty list */ if (inMsgElement == null) { return new ArrayList<QueryParam>(); } XmlSchemaType inMsgType = inMsgElement.getSchemaType(); if (!(inMsgType instanceof XmlSchemaComplexType)) { throw new DataServiceFault("Xmlschema complex type is expected for the in message of the operation '" + axisOperation.getName() + "'"); } QName inMsgTypeName = inMsgElement.getQName(); String elementName = elementMap.get(inMsgTypeName); Document operationDoc = modelMap.get(new QName(inMsgTypeName.getNamespaceURI(), elementName)); ModelBean operationBean = createModelBean(modelMap, operationDoc); List<QueryParam> queryParams = new ArrayList<QueryParam>(); String tmpType; List<ModelProperty> props = operationBean.getProperties(); ModelProperty prop; int count = props.size(); for (int i = 0; i < count; i++) { prop = props.get(i); tmpType = prop.getSimpleType(); if (tmpType == null) { if (prop.getType().isSimple()) { tmpType = prop.getType().getProperties().get(0).getSimpleType(); } else { throw new DataServiceFault( "A list of elements with simple types are expected at the in message of the operation '" + axisOperation.getName() + "'"); } } queryParams.add(new QueryParam(prop.getName(), DBUtils.getSQLTypeFromXsdType(tmpType), DBConstants.QueryTypes.IN, prop.isArray() ? DBConstants.QueryParamTypes.ARRAY : DBConstants.QueryParamTypes.SCALAR, i + 1, // ordinal null, null, new ArrayList<Validator>())); } return queryParams; } private static Result getResultFromAxisOperation(DataService dataService, AxisOperation axisOperation) throws DataServiceFault { AxisMessage axisMessage = getAxisMessageFromOperation(axisOperation, "out"); // if no out message, then no result if (axisMessage == null) { return null; } String elementName = null, rowName = null, namespace = null; XmlSchemaElement wrapperSchemaElement = axisMessage.getSchemaElement(); elementName = wrapperSchemaElement.getName(); namespace = wrapperSchemaElement.getQName().getNamespaceURI(); XmlSchemaType wrapperSchemaType = wrapperSchemaElement.getSchemaType(); if (!(wrapperSchemaType instanceof XmlSchemaComplexType)) { throw new DataServiceFault("Xmlschema complex type is expected for the out message of the operation '" + axisOperation.getName() + "'"); } XmlSchemaComplexType wrapperSchemaComplexType = (XmlSchemaComplexType) wrapperSchemaType; XmlSchemaComplexType dataFieldsType; if (hasResultRowName(wrapperSchemaComplexType)) { rowName = getResultRowName(wrapperSchemaComplexType); dataFieldsType = getRowNameBasedSchemaComplexType(wrapperSchemaComplexType); } else { dataFieldsType = wrapperSchemaComplexType; } Result result = new Result(elementName, rowName, namespace, null, DBConstants.ResultTypes.XML); OutputElementGroup defGroup = new OutputElementGroup(null, null, null, null); XmlSchemaObjectCollection dataSchemaObjects = getSchemaObjectsFromComplexType(dataFieldsType); int count = dataSchemaObjects.getCount(); XmlSchemaObject sequenceDataObject; XmlSchemaElement sequenceDataElement; XmlSchemaAttribute sequenceDataAttr; for (int i = 0; i < count; i++) { sequenceDataObject = dataSchemaObjects.getItem(i); if (sequenceDataObject instanceof XmlSchemaElement) { sequenceDataElement = (XmlSchemaElement) sequenceDataObject; if (!(sequenceDataElement.getSchemaType() instanceof XmlSchemaSimpleType)) { throw new DataServiceFault( "Xmlschema sequence's data fields at the out message of the operation '" + axisOperation.getName() + "' should only contain xml elements with simple types"); } defGroup.addElementEntry(new StaticOutputElement(dataService, sequenceDataElement.getName(), sequenceDataElement.getName(), sequenceDataElement.getName(), DBConstants.DBSFields.COLUMN, DBConstants.DBSFields.ELEMENT, namespace, sequenceDataElement.getSchemaTypeName(), new HashSet<String>(), DBConstants.DataCategory.VALUE, DBConstants.ResultTypes.XML, null, ParamValue.PARAM_VALUE_SCALAR, null)); } else if (sequenceDataObject instanceof XmlSchemaAttribute) { sequenceDataAttr = (XmlSchemaAttribute) sequenceDataObject; defGroup.addElementEntry(new StaticOutputElement(dataService, sequenceDataAttr.getName(), sequenceDataAttr.getName(), sequenceDataAttr.getName(), DBConstants.DBSFields.COLUMN, DBConstants.DBSFields.ATTRIBUTE, namespace, sequenceDataAttr.getSchemaTypeName(), new HashSet<String>(), DBConstants.DataCategory.VALUE, DBConstants.ResultTypes.XML, null, ParamValue.PARAM_VALUE_SCALAR, null)); } else { throw new DataServiceFault( "Xmlschema sequence at the out message's data field section of the operation '" + axisOperation.getName() + "' should only contain xml elements/attributes"); } } result.setDefaultElementGroup(defGroup); return result; } private static boolean hasResultRowName(XmlSchemaComplexType wrapperSchemaComplexType) { XmlSchemaParticle wrapperSchemaParticle = wrapperSchemaComplexType.getParticle(); // a single sequence must be there if (!(wrapperSchemaParticle instanceof XmlSchemaSequence)) { return false; } XmlSchemaSequence wrapperSchemaSequence = (XmlSchemaSequence) wrapperSchemaParticle; XmlSchemaObjectCollection objects = wrapperSchemaSequence.getItems(); if (objects.getCount() != 1) { return false; } XmlSchemaObject schemaObject = objects.getItem(0); if (!(schemaObject instanceof XmlSchemaElement)) { return false; } XmlSchemaElement schemaElement = (XmlSchemaElement) schemaObject; if (!((((XmlSchemaComplexType) schemaElement.getSchemaType()) .getParticle()) instanceof XmlSchemaSequence)) { return false; } // cannot contain any attributes if (wrapperSchemaComplexType.getAttributes().getCount() > 0) { return false; } return true; } private static String getResultRowName(XmlSchemaComplexType wrapperSchemaComplexType) { return ((XmlSchemaElement) ((XmlSchemaSequence) wrapperSchemaComplexType.getParticle()).getItems() .getItem(0)).getName(); } private static XmlSchemaComplexType getRowNameBasedSchemaComplexType( XmlSchemaComplexType wrapperSchemaComplexType) { return (((XmlSchemaComplexType) ((XmlSchemaElement) ((XmlSchemaSequence) wrapperSchemaComplexType .getParticle()).getItems().getItem(0)).getSchemaType())); } private static XmlSchemaObjectCollection getSchemaObjectsFromComplexType( XmlSchemaComplexType schemaComplexType) { XmlSchemaObjectCollection collection = new XmlSchemaObjectCollection(); XmlSchemaSequence sequence = (XmlSchemaSequence) schemaComplexType.getParticle(); if (sequence != null) { XmlSchemaObjectCollection seqItems = sequence.getItems(); int c = seqItems.getCount(); for (int i = 0; i < c; i++) { // add elements collection.add(seqItems.getItem(i)); } } XmlSchemaObjectCollection attrItems = schemaComplexType.getAttributes(); int c = attrItems.getCount(); for (int i = 0; i < c; i++) { // add attributes collection.add(attrItems.getItem(i)); } return collection; } private static ModelBean createModelBean(Map<QName, Document> modelMap, QName typeName) { return createModelBean(modelMap, modelMap.get(typeName)); } private static ModelBean createModelBean(Map<QName, Document> modelMap, Document doc) { ModelBean bean = new ModelBean(); if (doc == null) { return null; } Node beanEl = doc.getFirstChild(); /* populate bean attributes */ NamedNodeMap beanAttrs = beanEl.getAttributes(); bean.setName(beanAttrs.getNamedItem("originalName").getNodeValue()); bean.setNsURI(beanAttrs.getNamedItem("nsuri").getNodeValue()); Node isSimpleNode = beanAttrs.getNamedItem("simple"); if (isSimpleNode != null) { bean.setSimple("yes".equals(isSimpleNode.getNodeValue())); } else { bean.setSimple(false); } /* populate child elements / properties */ NodeList propsElList = beanEl.getChildNodes(); int count = propsElList.getLength(); Node propEl; for (int i = 0; i < count; i++) { propEl = propsElList.item(i); bean.addProperty(createModelProperty(modelMap, propEl)); } return bean; } private static ModelProperty createModelProperty(Map<QName, Document> modelMap, Node propEl) { ModelProperty property = new ModelProperty(); NamedNodeMap propAttrs = propEl.getAttributes(); property.setName(propAttrs.getNamedItem("name").getNodeValue()); Node isArrayNode = propAttrs.getNamedItem("array"); if (isArrayNode != null) { property.setArray("yes".equals(isArrayNode.getNodeValue())); } else { property.setArray(false); } Node isPrimitiveNode = propAttrs.getNamedItem("primitive"); boolean primitive; if (isPrimitiveNode != null) { primitive = "yes".equals(isPrimitiveNode.getNodeValue()); } else { primitive = false; } Node isSimpleNode = propAttrs.getNamedItem("simple"); boolean simple; if (isSimpleNode != null) { simple = "yes".equals(isSimpleNode.getNodeValue()); } else { simple = false; } ModelBean type = null; if (!primitive && !simple) { type = createModelBean(modelMap, new QName(propAttrs.getNamedItem("nsuri").getNodeValue(), propAttrs.getNamedItem("shorttypename").getNodeValue())); } if (type != null) { property.setType(type); } else { property.setSimpleType(propAttrs.getNamedItem("shorttypename").getNodeValue()); } return property; } /** * Represents a "Bean" element after schema compilation. */ public static class ModelBean { private boolean simple; private String nsURI; /** type name */ private String name; /** list of elements */ private List<ModelProperty> properties; public ModelBean() { this.properties = new ArrayList<ModelProperty>(); } public boolean isSimple() { return simple; } public void setSimple(boolean simple) { this.simple = simple; } public String getNsURI() { return nsURI; } public void setNsURI(String nsURI) { this.nsURI = nsURI; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<ModelProperty> getProperties() { return properties; } public void setProperties(List<ModelProperty> properties) { this.properties = properties; } public void addProperty(ModelProperty property) { this.getProperties().add(property); } public String toString() { StringBuffer buff = new StringBuffer(); buff.append("{\n"); buff.append("Name:" + this.getName() + "\n"); buff.append("NsURI:" + this.getNsURI() + "\n"); buff.append("Properties: {\n"); List<ModelProperty> propsList = this.getProperties(); int count = propsList.size(); for (int i = 0; i < count; i++) { buff.append(propsList.get(i).toString()); if (i + 1 < count) { buff.append(",\n"); } } buff.append("}\n"); buff.append("}\n"); return buff.toString(); } } /** * Represents a "Property" element after schema compilation. */ public static class ModelProperty { /** element name */ private String name; private boolean array; private String simpleType; private ModelBean type; public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isArray() { return array; } public void setArray(boolean array) { this.array = array; } public String getSimpleType() { return simpleType; } public void setSimpleType(String simpleType) { this.simpleType = simpleType; } public ModelBean getType() { return type; } public void setType(ModelBean type) { this.type = type; } public String toString() { StringBuffer buff = new StringBuffer(); buff.append("{\n"); buff.append("Name:" + this.getName() + "\n"); buff.append("IsArray:" + this.isArray() + "\n"); if (this.getType() != null) { buff.append("Type:" + this.getType() + "\n"); } else { buff.append("Type:" + this.getSimpleType()); } buff.append("}\n"); return buff.toString(); } } }