blob: 08537752044586710dd6eff81ca0c771852b4100 [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Laboratory
*
* 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.onosproject.yangutils.tool;
import org.onosproject.yangutils.datamodel.YangNode;
import org.onosproject.yangutils.datamodel.YangReferenceResolver;
import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
import org.onosproject.yangutils.linker.YangLinker;
import org.onosproject.yangutils.linker.exceptions.LinkerException;
import org.onosproject.yangutils.linker.impl.YangLinkerManager;
import org.onosproject.yangutils.parser.YangUtilsParser;
import org.onosproject.yangutils.parser.exceptions.ParserException;
import org.onosproject.yangutils.parser.impl.YangUtilsParserManager;
import org.onosproject.yangutils.tool.exception.YangToolException;
import org.onosproject.yangutils.utils.io.YangPluginConfig;
import org.slf4j.Logger;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import static java.util.Collections.sort;
import static org.onosproject.yangutils.datamodel.ResolvableType.YANG_DERIVED_DATA_TYPE;
import static org.onosproject.yangutils.datamodel.ResolvableType.YANG_IDENTITYREF;
import static org.onosproject.yangutils.linker.impl.YangLinkerUtils.resolveGroupingInDefinationScope;
import static org.onosproject.yangutils.tool.ToolConstants.E_CODE_GEN_PATH;
import static org.onosproject.yangutils.tool.ToolConstants.E_MISSING_INPUT;
import static org.onosproject.yangutils.translator.tojava.JavaCodeGeneratorUtil.generateJavaCode;
import static org.onosproject.yangutils.translator.tojava.JavaCodeGeneratorUtil.translatorErrorHandler;
import static org.onosproject.yangutils.utils.UtilConstants.NEW_LINE;
import static org.onosproject.yangutils.utils.UtilConstants.SLASH;
import static org.onosproject.yangutils.utils.UtilConstants.TEMP;
import static org.onosproject.yangutils.utils.UtilConstants.YANG_RESOURCES;
import static org.onosproject.yangutils.utils.io.impl.YangIoUtils.createDirectories;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Represents ONOS YANG tool manager.
*/
public class YangToolManager {
private static final Logger log = getLogger(YangToolManager.class);
public static final String DEFAULT_JAR_RES_PATH = SLASH + TEMP + SLASH +
YANG_RESOURCES + SLASH;
public static final String YANG_META_DATA = "YangMetaData";
public static final String SERIALIZED_FILE_EXTENSION = ".ser";
// YANG file information set.
private Set<YangFileInfo> yangFileInfoSet; //initialize in tool invocation;
private final YangUtilsParser yangUtilsParser = new YangUtilsParserManager();
private final YangLinker yangLinker = new YangLinkerManager();
private YangFileInfo curYangFileInfo = new YangFileInfo();
private final Set<YangNode> yangNodeSet = new HashSet<>();
/**
* Provides a list of files from list of strings.
*
* @param yangFileInfo set of yang file information
* @return list of files
*/
private static List<File> getListOfFile(Set<YangFileInfo> yangFileInfo) {
List<File> files = new ArrayList<>();
Iterator<YangFileInfo> yangFileIterator = yangFileInfo.iterator();
while (yangFileIterator.hasNext()) {
YangFileInfo yangFile = yangFileIterator.next();
if (yangFile.isForTranslator()) {
files.add(new File(yangFile.getYangFileName()));
}
}
return files;
}
/**
* Compile te YANG files and generate the corresponding Java files.
* Update the generated bundle with the schema metadata.
*
* @param yangFiles Application YANG files
* @param config tool configuration
* @param plugin invoking plugin
*/
public void compileYangFiles(Set<YangFileInfo> yangFiles,
List<YangNode> dependentSchema,
YangPluginConfig config,
CallablePlugin plugin) throws IOException {
try {
if (config == null || yangFiles == null) {
throw new YangToolException(E_MISSING_INPUT);
}
yangFileInfoSet = yangFiles;
if (config.getCodeGenDir() == null) {
throw new YangToolException(E_CODE_GEN_PATH);
}
// Check if there are any file to translate, if not return.
if (yangFileInfoSet == null || yangFileInfoSet.isEmpty()) {
// No files to translate
return;
}
createDirectories(config.resourceGenDir());
// Resolve inter jar dependency.
addSchemaToFileSet(dependentSchema);
// Carry out the parsing for all the YANG files.
parseYangFileInfoSet();
// Resolve dependencies using linker.
resolveDependenciesUsingLinker();
// Perform translation to JAVA.
translateToJava(config);
// Serialize data model.
Set<YangNode> compiledSchemas = new HashSet<>();
for (YangFileInfo fileInfo : yangFileInfoSet) {
compiledSchemas.add(fileInfo.getRootNode());
}
String serFileName = config.resourceGenDir() + YANG_META_DATA + SERIALIZED_FILE_EXTENSION;
FileOutputStream fileOutputStream = new FileOutputStream(serFileName);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(compiledSchemas);
objectOutputStream.close();
fileOutputStream.close();
//add YANG files to JAR
List<File> files = getListOfFile(yangFileInfoSet);
String path = config.resourceGenDir();
File targetDir = new File(path);
targetDir.mkdirs();
for (File file : files) {
Files.copy(file.toPath(),
new File(path + file.getName()).toPath(),
StandardCopyOption.REPLACE_EXISTING);
}
if (plugin != null) {
plugin.addCompiledSchemaToBundle();
plugin.addGeneratedCodeToBundle();
plugin.addYangFilesToBundle();
}
} catch (IOException | ParserException e) {
YangToolException exception =
new YangToolException(e.getMessage(), e);
exception.setCurYangFile(curYangFileInfo);
if (curYangFileInfo != null &&
curYangFileInfo.getRootNode() != null) {
try {
translatorErrorHandler(curYangFileInfo.getRootNode(),
config);
} catch (IOException ex) {
e.printStackTrace();
throw ex;
}
}
throw exception;
}
}
/**
* Resolved inter-jar dependencies.
*
* @param dependentSchema dependent schema list
* @throws IOException when fails to do IO operations
*/
private void addSchemaToFileSet(List<YangNode> dependentSchema)
throws IOException {
if (dependentSchema == null || dependentSchema.isEmpty()) {
return;
}
for (YangNode node : dependentSchema) {
YangFileInfo dependentFileInfo = new YangFileInfo();
node.setToTranslate(false);
dependentFileInfo.setRootNode(node);
dependentFileInfo.setForTranslator(false);
dependentFileInfo.setYangFileName(node.getName());
yangFileInfoSet.add(dependentFileInfo);
}
}
/**
* Links all the provided schema in the YANG file info set.
*
* @throws YangToolException failed to link schema
*/
public void resolveDependenciesUsingLinker() {
createYangNodeSet();
try {
yangLinker.resolveDependencies(yangNodeSet);
} catch (LinkerException e) {
printLog(e.getFileName(), e.getLineNumber(), e.getCharPositionInLine(),
e.getMessage(), e.getLocalizedMessage());
throw new YangToolException(e.getMessage());
}
}
/**
* Creates YANG nodes set.
*/
public void createYangNodeSet() {
for (YangFileInfo yangFileInfo : yangFileInfoSet) {
yangNodeSet.add(yangFileInfo.getRootNode());
}
}
/**
* Parses all the provided YANG files and generates YANG data model tree.
*
* @throws IOException a violation in IO
*/
public void parseYangFileInfoSet()
throws IOException {
for (YangFileInfo yangFileInfo : yangFileInfoSet) {
curYangFileInfo = yangFileInfo;
if (yangFileInfo.isForTranslator()) {
try {
YangNode yangNode = yangUtilsParser.getDataModel(
yangFileInfo.getYangFileName());
yangFileInfo.setRootNode(yangNode);
resolveGroupingInDefinationScope((YangReferenceResolver) yangNode);
try {
((YangReferenceResolver) yangNode)
.resolveSelfFileLinking(YANG_DERIVED_DATA_TYPE);
((YangReferenceResolver) yangNode)
.resolveSelfFileLinking(YANG_IDENTITYREF);
} catch (DataModelException e) {
printLog(e.getFileName(), e.getLineNumber(), e
.getCharPositionInLine(), e.getMessage(), e
.getLocalizedMessage());
}
} catch (ParserException e) {
printLog(e.getFileName(), e.getLineNumber(), e
.getCharPositionInLine(), e.getMessage(), e
.getLocalizedMessage());
throw e;
}
}
}
}
/**
* Translates to java code corresponding to the YANG schema.
*
* @param pluginConfig YANG plugin config
* @throws IOException when fails to generate java code file the current node
*/
public void translateToJava(YangPluginConfig pluginConfig)
throws IOException {
List<YangNode> yangNodeSortedList = new LinkedList<>();
yangNodeSortedList.addAll(yangNodeSet);
sort(yangNodeSortedList);
for (YangNode node : yangNodeSortedList) {
if (node.isToTranslate()) {
generateJavaCode(node, pluginConfig);
}
}
}
/**
* Adds log info for exception.
*
* @param fileName file name
* @param line line number
* @param position character position
* @param msg error message
* @param localMsg local message
*/
private void printLog(String fileName, int line, int position, String
msg, String localMsg) {
String logInfo = "Error in file: " + fileName;
if (line != 0) {
logInfo = logInfo + " at line: " + line + " at position: "
+ position;
}
if (msg != null) {
logInfo = logInfo + NEW_LINE + localMsg;
}
log.info(logInfo);
}
}