All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.quickfixj.dictgenerator.Generator Maven / Gradle / Ivy

There is a newer version: 2.3.1
Show newest version
/*******************************************************************************
 * Copyright (c) quickfixengine.org  All rights reserved.
 *
 * This file is part of the QuickFIX FIX Engine
 *
 * This file may be distributed under the terms of the quickfixengine.org
 * license as defined by quickfixengine.org and appearing in the file
 * LICENSE included in the packaging of this file.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
 * THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE.
 *
 * See http://www.quickfixengine.org/LICENSE for licensing information.
 *
 * Contact [email protected] if any conditions of this licensing
 * are not clear to you.
 ******************************************************************************/

package org.quickfixj.dictgenerator;

import java.io.BufferedWriter;
import java.io.File;
import java.io.Writer;
import java.util.*;

/**
 * QFJ-483: QFJ Dictionary Generator
 * Credit for the initial version goes to Morten Kristiansen.
 * There were some changes made regarding ordering of tags etc, in order to make the
 * dictionaries look more similar to the existing QFJ dictionaries.
 *
 * NB: Do not forget to correct the major/minor number in the session data dictionary afterwards.
 *
 * This generator only works with the FPL 2008/09 repository files (http://fixprotocol.org/repository-2008).
 */
public class Generator {

    private final Repository repository;
    private final int major;
    private final int minor;

    public Generator(File repositoryDir, int major, int minor) throws Exception {
        System.out.println("Building Repository: " + repositoryDir.getAbsolutePath() + "...");
        this.repository = new Repository(repositoryDir);
        this.major = major;
        this.minor = minor;
    }

    public void generate() throws Exception {
        generateDictionary("session.xml", true, false);
        generateDictionary("application.xml", false, false);
        generateDictionary("merged.xml", false, true); // for versions below FIX5.0
    }

    private void generateDictionary(String file, boolean admin, boolean merged) {
        File dictionaryFile = new File(file);
        System.out.println("Creating file: " + dictionaryFile.getAbsolutePath());
        StringBuilder builder = new StringBuilder();
        if (!merged) {
            if (admin) {
                builder.append("\n");
            } else {
                builder.append("\n");
            }
        } else {
            builder.append("\n");
        }

        Map msgTypes = new LinkedHashMap<>();
        if (!merged) {
            if (admin) {
                msgTypes.putAll(repository.getSessionMsgTypes());
            } else {
                msgTypes.putAll(repository.getApplicationMsgTypes());
            }
        } else {
            msgTypes.putAll(repository.getSessionMsgTypes());
            msgTypes.putAll(repository.getApplicationMsgTypes());
        }
        Set fieldsUsed = getAllFieldsUsed(msgTypes);
        Set componentsUsed = getAllComponentsUsed(msgTypes);

        // Header
        if (!merged) {
            if (admin) {
                builder.append("  
\n"); Component standardHeader = repository.getStandardHeader(getNextMsgType(msgTypes)); addMsgContents(builder, standardHeader.getMsgContent(), " "); builder.append("
\n"); builder.append(" \n"); Component standardTrailer = repository.getStandardTrailer(getNextMsgType(msgTypes)); addMsgContents(builder, standardTrailer.getMsgContent(), " "); builder.append(" \n"); } else { builder.append("
\n"); builder.append(" \n"); } } else { builder.append("
\n"); Component standardHeader = repository.getStandardHeader(getNextMsgType(msgTypes)); addMsgContents(builder, standardHeader.getMsgContent(), " "); builder.append("
\n"); builder.append(" \n"); Component standardTrailer = repository.getStandardTrailer(getNextMsgType(msgTypes)); addMsgContents(builder, standardTrailer.getMsgContent(), " "); builder.append(" \n"); } // Message if (!merged) { String msgcat = admin ? "admin" : "app"; builder.append(" \n"); for (MsgType msgType : msgTypes.values()) { if (msgType.getMsgType().equals("n")) { builder.append(" \n"); } } builder.append(" \n"); } else { builder.append(" \n"); for (MsgType msgType : msgTypes.values()) { String msgcat = msgType.getCategory().equals("Session") ? "admin" : "app"; if (msgType.getMsgType().equals("n")) { builder.append(" \n"); } } builder.append(" \n"); } // Components builder.append(" \n"); Map components = repository.getComponents(); for (String name : componentsUsed) { Component component = components.get(name); builder.append(" \n"); Field numInGroup = null; for (Object o : component.getMsgContent()) { if (o instanceof Field && ((Field) o).isNumInGroup()) { numInGroup = (Field) o; break; } } if (numInGroup != null) { builder.append(" \n"); addMsgContents(builder, component.getMsgContent(), " "); builder.append(" \n"); } else { addMsgContents(builder, component.getMsgContent(), " "); } builder.append(" \n"); } builder.append(" \n"); // Fields builder.append(" \n"); Map fields = repository.getFields(); for (Integer tagInt : fieldsUsed) { String tag = String.valueOf(tagInt); Field field = fields.get(tag); String fieldType = field.getType(); builder.append(" \n"); Set enumDescCache = new HashSet<>(); for (Enum theEnum : field.getEnums()) { String enumDesc = theEnum.getDesc().toUpperCase(); enumDesc = enumDesc.replaceAll("\\(.*\\)", ""); // remove stuff in parentheses enumDesc = enumDesc.replaceAll("'", ""); // replace ticks (as in DON'T_KNOW_TRADE) enumDesc = enumDesc.replaceAll("\"", ""); enumDesc = enumDesc.trim(); // trim leading and trailing whitespaces enumDesc = enumDesc.replaceAll("\\W+", "_"); // replace rest of non-word characters by _ char firstChar = enumDesc.charAt(0); if (Character.isDigit(firstChar)) { enumDesc = "_" + enumDesc; // make it a valid JAVA identifier } boolean add = enumDescCache.add(enumDesc); if (add) { builder.append(" \n"); } else { // FIXME ugly workaround to avoid duplicate entries enumDesc = enumDesc + "_1"; enumDescCache.add(enumDesc); builder.append(" \n"); } } builder.append(" \n"); } else { builder.append("/>\n"); } } builder.append(" \n"); builder.append(""); try { Writer writer = new BufferedWriter(new java.io.FileWriter(dictionaryFile)); writer.write(builder.toString()); writer.flush(); writer.close(); } catch (Exception e) { e.printStackTrace(); } } private MsgType getNextMsgType(Map msgTypes) { Iterator it = msgTypes.values().iterator(); if(it.hasNext()) { return it.next(); } else { throw new RuntimeException("Message type not found. Check the MsgType.xml file."); } } private void addMsgContents(StringBuilder builder, List msgContents, String prefix) { for (Object o : msgContents) { if (o instanceof Field) { Field field = (Field) o; if (field.isNumInGroup()) { continue; } builder.append(prefix).append("\n"); } else if (o instanceof Component) { Component component = (Component) o; if (component.isStandardHeader() || component.isStandardTrailer()) { continue; } builder.append(prefix).append("\n"); } } } private Set getAllFieldsUsed(Map msgTypes) { Set result = new TreeSet<>(); for (MsgType msgType : msgTypes.values()) { result = addFields(result, msgType.getMsgContent()); } System.out.println("Fields used: " + result); return result; } private Set addFields(Set result, List msgContents) { for (Object o : msgContents) { if (o instanceof Field) { result.add(Integer.valueOf(((Field) o).getTag())); } if (o instanceof Component) { result = addFields(result, ((Component) o).getMsgContent()); } } return result; } private Set getAllComponentsUsed(Map msgTypes) { Set result = new HashSet<>(); for (MsgType msgType : msgTypes.values()) { result = addComponents(result, msgType.getMsgContent()); } System.out.println("Components used: " + result); return result; } private Set addComponents(Set result, List msgContents) { for (Object o : msgContents) { if (o instanceof Component) { Component component = (Component) o; if (!component.isStandardHeader() && !component.isStandardTrailer()) { result.add(((Component) o).getName()); } result = addComponents(result, ((Component) o).getMsgContent()); } } return result; } public static void main(String[] args) throws Exception { if (args == null || args.length < 3) { System.err.println("Usage: Generator [repository path] [major number] [minor number]"); System.exit(1); return; } File repository = new File(args[0]); if (!repository.exists() || !repository.isDirectory()) { System.err.println("Invalid repository: " + repository.getAbsolutePath()); System.exit(1); return; } int major = Integer.parseInt(args[1]); int minor = Integer.parseInt(args[2]); new Generator(repository, major, minor).generate(); } }