/*
* 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 com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.JSException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.ReaderException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.SchemaException;
import org.wso2.carbon.mediator.datamapper.engine.core.exceptions.WriterException;
import org.wso2.carbon.mediator.datamapper.engine.core.executors.Executor;
import org.wso2.carbon.mediator.datamapper.engine.core.executors.ScriptExecutorFactory;
import org.wso2.carbon.mediator.datamapper.engine.core.models.Model;
import org.wso2.carbon.mediator.datamapper.engine.core.notifiers.InputVariableNotifier;
import org.wso2.carbon.mediator.datamapper.engine.core.notifiers.OutputVariableNotifier;
import org.wso2.carbon.mediator.datamapper.engine.input.InputBuilder;
import org.wso2.carbon.mediator.datamapper.engine.output.OutputMessageBuilder;
import org.wso2.carbon.mediator.datamapper.engine.utils.InputOutputDataType;
import org.wso2.carbon.mediator.datamapper.engine.utils.ModelType;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
public class MappingHandler implements InputVariableNotifier, OutputVariableNotifier {
private String dmExecutorPoolSize;
private String inputVariable;
private String outputVariable;
private MappingResource mappingResource;
private OutputMessageBuilder outputMessageBuilder;
private Executor scriptExecutor;
private InputBuilder inputBuilder;
private String propertiesInJSON;
public MappingHandler(MappingResource mappingResource, String inputType, String outputType,
String dmExecutorPoolSize) throws IOException, SchemaException, WriterException {
this.inputBuilder = new InputBuilder(InputOutputDataType.fromString(inputType),
mappingResource.getInputSchema());
this.outputMessageBuilder = new OutputMessageBuilder(InputOutputDataType.fromString(outputType),
ModelType.JAVA_MAP, mappingResource.getOutputSchema());
this.dmExecutorPoolSize = dmExecutorPoolSize;
this.mappingResource = mappingResource;
}
/**
* This method performs the mapping from input message to the specified output schema.
* <p>
* Input message should be passed as an InputStream and any runtime properties can be passed as a Map.
* At the top level of the Properties map, it contains scope name (String) and an individual map for each scope.
* In the next level, a map in a single scope should contain name, value pairs for each property name and its
* value.
* </p>
* <p>
* Map of maps will be converted to a JSON object to be injected to the JavaScript processing engine.
* </p>
*
* @param inputMsg Input message as an InputStream
* @param propertiesMap Map of maps, single map for each scope
* @return Output message created according to the provided OutputSchema using the runtime arguments
* @throws ReaderException
* @throws InterruptedException
* @throws IOException
* @throws SchemaException
* @throws JSException
*/
public String doMap(InputStream inputMsg, Map<String, Map<String, Object>> propertiesMap)
throws ReaderException, InterruptedException, IOException, SchemaException, JSException {
this.scriptExecutor = ScriptExecutorFactory.getScriptExecutor(dmExecutorPoolSize);
this.propertiesInJSON = propertiesMapToJSON(propertiesMap);
inputBuilder.buildInputModel(inputMsg, this);
return outputVariable;
}
@Override
public void notifyInputVariable(Object variable) throws SchemaException, JSException, ReaderException {
this.inputVariable = (String) variable;
Model outputModel = scriptExecutor.execute(mappingResource, inputVariable, propertiesInJSON);
try {
releaseExecutor();
if (outputModel.getModel() instanceof Map) {
outputMessageBuilder.buildOutputMessage(outputModel, this);
} else {
notifyOutputVariable(outputModel.getModel());
}
} catch (InterruptedException | WriterException e) {
throw new ReaderException(e.getMessage());
}
}
private void releaseExecutor() throws InterruptedException {
ScriptExecutorFactory.releaseScriptExecutor(scriptExecutor);
this.scriptExecutor = null;
}
@Override
public void notifyOutputVariable(Object variable) {
outputVariable = (String) variable;
}
/**
* Convert the properties map to a JSON String
* @param propertiesMap
* @return JSON String
* @throws ReaderException
*/
private String propertiesMapToJSON(Map<String, Map<String, Object>> propertiesMap) throws ReaderException {
ObjectMapper mapperObj = new ObjectMapper();
String propertiesInJSON = null;
try {
propertiesInJSON = mapperObj.writeValueAsString(propertiesMap);
} catch (JsonProcessingException e) {
throw new ReaderException("Error while parsing the input properties. " + e.getMessage());
}
return propertiesInJSON;
}
}