/*
* Copyright 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.transports.sap.bapi.util;
import com.sap.conn.jco.JCoField;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoStructure;
import com.sap.conn.jco.JCoTable;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Iterator;
/** This will contains the required methods that can be use to parser a
* meta data description of a BAPI/RFC call.
* So the BNF grammer for the meta data would looks like :
* bapirfc -> import | tables | both
* import -> structure | field | both
* structure -> 1 or more fields
* tables -> 1 or more table
* table -> row
* row -> 1 or more fields
* field -> name and value
*
* See resources folder for sample meta data description files
*
*/
public class RFCMetaDataParser {
private static Log log = LogFactory.getLog(RFCMetaDataParser.class);
/**
* Start processing of the document
* @param document the document node
* @param function the RFC function to execute
* @throws AxisFault throws in case of an error
*/
public static void processMetaDataDocument(OMElement document, JCoFunction function) throws AxisFault{
Iterator itr = document.getChildElements();
while(itr.hasNext()){
OMElement childElement = (OMElement)itr.next();
processElement(childElement, function);
}
}
/**
* Returns the BAPI/RFC function name
* @param rootElement root document element
* @return the BAPI/RFC function name
* @throws AxisFault throws in case of an error
*/
public static String getBAPIRFCFucntionName(OMElement rootElement) throws AxisFault {
String qname = rootElement.getQName().toString();
if (qname != null) {
if (qname.equals(RFCConstants.BAPIRFC)) {
String rfcFunctionName = rootElement.getAttributeValue(RFCConstants.NAME_Q);
if (rfcFunctionName != null) {
return rfcFunctionName;
} else {
throw new AxisFault("BAPI/RFC function name is mandatory in meta data" +
" configuration");
}
} else {
throw new AxisFault("Invalid meta data root element.Found: " + qname + "" +
". Required:" + RFCConstants.BAPIRFC);
}
}
return null;
}
private static void processElement(OMElement element, JCoFunction function) throws AxisFault{
String qname = element.getQName().toString();
if(qname != null){
if(qname.equals("import")){
processImport(element, function);
}else if(qname.equals("tables")){
processTables(element, function);
}else {
log.warn("Unknown meta data type tag :" + qname + " detected. " +
"This meta data element will be discarded!");
}
}
}
private static void processImport(OMElement element, JCoFunction function) throws AxisFault{
Iterator itr = element.getChildElements();
while (itr.hasNext()){
OMElement childElement = (OMElement) itr.next();
String qname = childElement.getQName().toString();
String name = childElement.getAttributeValue(RFCConstants.NAME_Q);
if(qname.equals("structure")){
processStructure(childElement, function, name);
}else if(qname.equals("field")){
processField(childElement, function, name);
}else{
log.warn("Unknown meta data type tag :" + qname + " detected. " +
"This meta data element will be discarded!");
}
}
}
private static void processStructure(OMElement element, JCoFunction function, String strcutName)
throws AxisFault {
if (strcutName == null) {
throw new AxisFault("A structure should have a name!");
}
JCoStructure jcoStrcture = function.getImportParameterList().getStructure(strcutName);
if (jcoStrcture != null) {
Iterator itr = element.getChildElements();
boolean isRecordFound = false;
while (itr.hasNext()) {
OMElement childElement = (OMElement) itr.next();
String qname = childElement.getQName().toString();
if (qname.equals("field")) {
String fieldName = childElement.getAttributeValue(RFCConstants.NAME_Q);
String fieldValue = childElement.getText();
for (JCoField field : jcoStrcture) {
if (fieldName != null && fieldName.equals(field.getName())) {
isRecordFound = true;
field.setValue(fieldValue); // TODO - may be we need to check for null ?
break;
}
}
if(!isRecordFound){
throw new AxisFault("Invalid configuration! The field : "+ fieldName + "" +
" did not find the the strcture : " + strcutName);
}
} else {
log.warn("Invalid meta data type element found : " + qname + " .This meta data " +
"type will be ignored");
}
}
} else {
log.error("Didn't find the specified structure : " + strcutName + " on the RFC" +
" repository. This structure will be ignored");
}
}
private static void processField(OMElement element, JCoFunction function, String fieldName)
throws AxisFault{
if(fieldName == null){
throw new AxisFault("A field should have a name!");
}
String fieldValue = element.getText();
if (fieldValue != null) {
// TODO-check for avalibility of the field
function.getImportParameterList().setValue(fieldName, fieldValue);
}
}
private static void processTables(OMElement element, JCoFunction function) throws AxisFault{
Iterator itr = element.getChildElements();
while (itr.hasNext()){
OMElement childElement = (OMElement) itr.next();
String qname = childElement.getQName().toString();
String tableName = childElement.getAttributeValue(RFCConstants.NAME_Q);
if(qname.equals("table")){
processTable(childElement, function, tableName);
}else{
log.warn("Invalid meta data type element found : " + qname + " .This meta data " +
"type will be ignored");
}
}
}
private static void processTable(OMElement element, JCoFunction function, String tableName)
throws AxisFault{
JCoTable inputTable = function.getTableParameterList().getTable(tableName);
if(inputTable == null){
throw new AxisFault("Input table :" + tableName + " does not exist");
}
Iterator itr = element.getChildElements();
while (itr.hasNext()){
OMElement childElement = (OMElement)itr.next();
String qname = childElement.getQName().toString();
String id = childElement.getAttributeValue(RFCConstants.ID_Q);
if(qname.equals("row")){
processRow(childElement, inputTable, id);
}else{
log.warn("Invalid meta data type element found : " + qname + " .This meta data " +
"type will be ignored");
}
}
}
private static void processRow(OMElement element, JCoTable table, String id)
throws AxisFault {
int rowId;
try {
rowId = Integer.parseInt(id);
} catch (NumberFormatException ex) {
log.warn("Row ID should be a integer, found " + id + ". Skipping row", ex);
return;
}
if (table.getNumRows() <= rowId) {
//which mean this is a new row
table.appendRow();
} else {
//handle existing row
table.setRow(rowId);
}
Iterator itr = element.getChildElements();
while (itr.hasNext()) {
OMElement childElement = (OMElement) itr.next();
String qname = childElement.getQName().toString();
if (qname != null && qname.equals("field")) {
processField(childElement, table);
} else {
log.warn("Invalid meta data type element found : " + qname + " .This meta data " +
"type will be ignored");
}
}
}
private static void processField(OMElement element, JCoTable table)
throws AxisFault {
String fieldName = element.getAttributeValue(RFCConstants.NAME_Q);
String fieldValue = element.getText();
if (fieldName == null) {
throw new AxisFault("A field should have a name!");
}
if (fieldValue != null) {
table.setValue(fieldName, fieldValue);
}
}
}