/*
* Copyright (c) 2016, 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.mediator.datamapper.engine.core.mapper;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.JSException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.SchemaException;
import org.wso2.carbon.mediator.datamapper.engine.core.schemas.JacksonJSONSchema;
import org.wso2.carbon.mediator.datamapper.engine.core.schemas.Schema;
import org.wso2.carbon.mediator.datamapper.engine.utils.InputOutputDataType;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.BRACKET_CLOSE;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.BRACKET_OPEN;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.FUNCTION_NAME_CONST_1;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.FUNCTION_NAME_CONST_2;
import static org.wso2.carbon.mediator.datamapper.engine.utils.DataMapperEngineConstants.JS_STRINGIFY;
public class MappingResource {
public static final String NAMESPACE_DELIMETER = ":";
public static final String NEW_LINE = "\n";
private Schema inputSchema;
private Schema outputSchema;
private String inputRootelement;
private String outputRootelement;
private JSFunction function;
private List<String> propertiesList;
/**
* @param inputSchema respective output json schema as a a stream of bytes
* @param outputSchema respective output json schema as a a stream of bytes
* @param mappingConfig mapping configuration file as a stream of bytes
* @throws IOException when input errors, If there any parser exception occur while passing
* above schemas method
* will this exception
*/
public MappingResource(InputStream inputSchema, InputStream outputSchema, InputStream mappingConfig,
String outputType) throws SchemaException, JSException {
this.inputSchema = getJSONSchema(inputSchema);
this.outputSchema = getJSONSchema(outputSchema);
this.inputRootelement = this.inputSchema.getName();
this.outputRootelement = this.outputSchema.getName();
this.propertiesList = new ArrayList<>();
this.function = createFunction(mappingConfig, outputType);
}
private Schema getJSONSchema(InputStream inputSchema) throws SchemaException {
return new JacksonJSONSchema(inputSchema);
}
public Schema getInputSchema() {
return inputSchema;
}
public Schema getOutputSchema() {
return outputSchema;
}
public JSFunction getFunction() {
return function;
}
/**
* propertiesList contains a list of WSO2 ESB Properties used in the Data Mapper Mapping configuration.
* These will be extracted by processing the mapping configuration file and will be included as Strings
* in the format of : "SCOPE['PROP_NAME']"
*
* @return propertiesList
*/
public List getPropertiesList() {
return propertiesList;
}
/**
* need to create java script function by passing the configuration file
* Since this function going to execute every time when message hit the mapping backend
* so this function save in the resource model
*
* @param mappingConfig mapping configuration
* @return java script function
*/
private JSFunction createFunction(InputStream mappingConfig, String outputType) throws JSException {
BufferedReader configReader = new BufferedReader(new InputStreamReader(mappingConfig, StandardCharsets.UTF_8));
//need to identify the main method of the configuration because that method going to
// execute in engine
String[] inputRootElementArray = inputRootelement.split(NAMESPACE_DELIMETER);
String inputRootElement = inputRootElementArray[inputRootElementArray.length - 1];
String[] outputRootElementArray = outputRootelement.split(NAMESPACE_DELIMETER);
String outputRootElement = outputRootElementArray[outputRootElementArray.length - 1];
String jsFunctionBody;
String propertiesPattern = "(DM_PROPERTIES.)([a-zA-Z_$][a-zA-Z_$0-9]*)\\['([a-zA-Z_$][a-zA-Z-_.$0-9]*)'\\]";
Pattern pattern = Pattern.compile(propertiesPattern);
Matcher match;
String fnName =
FUNCTION_NAME_CONST_1 + inputRootElement + FUNCTION_NAME_CONST_2 + outputRootElement + BRACKET_OPEN
+ BRACKET_CLOSE;
if (InputOutputDataType.JSON.toString().equals(outputType)) {
fnName = JS_STRINGIFY + BRACKET_OPEN + fnName + BRACKET_CLOSE;
}
String configLine;
StringBuilder configScriptBuilder = new StringBuilder();
try {
while ((configLine = configReader.readLine()) != null) {
configScriptBuilder.append(configLine);
configScriptBuilder.append(NEW_LINE);
}
} catch (IOException e) {
throw new JSException(e.getMessage());
}
jsFunctionBody = configScriptBuilder.toString();
match = pattern.matcher(jsFunctionBody);
while (match.find()) {
propertiesList.add(match.group(2) + "['" + match.group(3) + "']");
}
if (fnName != null) {
return new JSFunction(fnName, jsFunctionBody);
} else {
throw new JSException("Could not find mapping JavaScript function.");
}
}
}