createGlobalPlan(String,Function,List)   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
dl 0
loc 5
ccs 0
cts 3
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
/*
2
 * Copyright 2014, Armenak Grigoryan, Matthew Eaton, and individual contributors as indicated
3
 * by the @authors tag. See the copyright.txt in the distribution for a
4
 * full listing of individual contributors.
5
 *
6
 * This is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU Lesser General Public License as
8
 * published by the Free Software Foundation; either version 2.1 of
9
 * the License, or (at your option) any later version.
10
 *
11
 * This software is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
 * Lesser General Public License for more details.
15
 */
16
package com.strider.datadefender.requirement.file;
17
18
import com.strider.datadefender.database.DatabaseException;
19
import com.strider.datadefender.database.metadata.TableMetaData;
20
import com.strider.datadefender.database.metadata.TableMetaData.ColumnMetaData;
21
import com.strider.datadefender.requirement.Column;
22
import com.strider.datadefender.requirement.plan.Argument;
23
import com.strider.datadefender.requirement.plan.Function;
24
import com.strider.datadefender.requirement.Requirement;
25
import com.strider.datadefender.requirement.Requirement.AutoresolvePackage;
26
import com.strider.datadefender.requirement.Table;
27
import com.strider.datadefender.requirement.plan.GlobalPlan;
28
import com.strider.datadefender.requirement.plan.PlanRef;
29
import com.strider.datadefender.requirement.registry.ClassAndFunctionRegistry;
30
31
import java.io.File;
32
import java.sql.Date;
33
import java.sql.Timestamp;
34
import java.util.ArrayList;
35
import java.util.Collection;
36
import java.util.List;
37
import java.util.Map;
38
import java.util.Objects;
39
import java.util.stream.Collectors;
40
import javax.xml.XMLConstants;
41
import javax.xml.bind.JAXBContext;
42
import javax.xml.bind.JAXBException;
43
import javax.xml.bind.Marshaller;
44
import javax.xml.validation.Schema;
45
import javax.xml.validation.SchemaFactory;
46
47
import org.apache.commons.collections4.CollectionUtils;
48
import org.apache.commons.lang3.StringUtils;
49
import org.xml.sax.SAXException;
50
51
import lombok.extern.log4j.Log4j2;
52
53
/**
54
 * Utility class to help handling requirement objects
55
 * @author Matthew Eaton
56
 */
57
@Log4j2
58
public class Generator {
59
60
    private static Map<String, GlobalPlan> plans = Map.of(
61
        "lipsum-similar", createGlobalPlan(
62
            "lipsum-similar",
63
            new Function("Lipsum#similar", false),
64
            List.of(new Argument("text", String.class, true))
65
        ),
66
        "core-date", createGlobalPlan(
67
            "core-date",
68
            new Function("Core#randomDate", false),
69
            List.of(
70
                new Argument("start", String.class, "1970-01-01"),
71
                new Argument("end", String.class, "2005-01-01"),
72
                new Argument("format", String.class, "yyyy-MM-dd")
73
            )
74
        ),
75
        "core-date-time", createGlobalPlan(
76
            "core-date-time",
77
            new Function("Core#randomDateTime", false),
78
            List.of(
79
                new Argument("start", String.class, "2010-01-01 00:00:00"),
80
                new Argument("end", String.class, "2020-04-01 00:00:00"),
81
                new Argument("format", String.class, "yyyy-MM-dd HH:mm:ss")
82
            )
83
        ),
84
        "core-date-string", createGlobalPlan(
85
            "core-date-string",
86
            new Function("Core#randomString", false),
87
            List.of(new Argument("text", String.class, true))
88
        )        
89
    );
90
91
    private static GlobalPlan createGlobalPlan(String name, Function fn, List<Argument> arguments) {
92
        GlobalPlan plan = new GlobalPlan(name);
93
        fn.setArguments(arguments);
94
        plan.setFunctions(List.of(fn));
95
        return plan;
96
    }
97
98
    private static void setDefaultFunction(final String table, final Column column) {
99
        if (Objects.equals(column.getType(), Date.class)) {
100
            column.setPlanRef(new PlanRef(plans.get("core-date")));
101
        } else if (Objects.equals(column.getType(), Timestamp.class)) {
102
            column.setPlanRef(new PlanRef(plans.get("core-date-time")));
103
        } else {
104
            column.setPlanRef(new PlanRef(plans.get("lipsum-similar")));
105
        }
106
    }
107
108
    /**
109
     * Create a requirement from sorted (by (schema.)table) List of matching columns.
110
     * @param matches
111
     * @return
112
     */
113
    public static Requirement create(final Collection<ColumnMetaData> matches) {
114
115
        List<Table> tables = new ArrayList<>();
116
        List<TableMetaData> tableMetas = matches.stream()
117
            .map((c) -> c.getTable()).collect(Collectors.toSet())
118
            .stream().sorted().collect(Collectors.toList());
119
        for (final TableMetaData tMeta : tableMetas) {
120
            Table table = new Table(tMeta.getCanonicalTableName());
121
            final List<ColumnMetaData> pks = tMeta.getPrimaryKeys();
122
            if (pks.size() == 0) {
123
                table.setPrimaryKey("NONE-SET");
124
            } else if (pks.size() == 1) {    // only one pk
125
                table.setPrimaryKey(pks.get(0).getColumnName());
126
            } else {                  // multiple key pk
127
                final List<String> keys = pks.stream().map((col) -> col.getColumnName()).collect(Collectors.toList());
128
                table.setPrimaryKeys(keys);
129
            }
130
            table.setColumns(
131
                matches.stream()
132
                .filter((c) -> c.getTable() == tMeta)
133
                .sorted()
134
                .map((c) -> {
135
                    Column column = new Column(c.getColumnName());
136
                    column.setType(c.getColumnType());
137
                    setDefaultFunction(table.getName(), column);
138
                    return column;
139
                })
140
                .collect(Collectors.toList())
141
            );
142
            tables.add(table);
143
        }
144
145
        final Requirement req = new Requirement();
146
        req.setPlans(List.copyOf(plans.values()));
147
        ClassAndFunctionRegistry.singleton().clearAutoResolvePackages();
148
        req.setAutoresolve(List.of(
149
            new AutoresolvePackage("java.lang", true),
150
            new AutoresolvePackage("org.apache.commons.lang3", true),
151
            new AutoresolvePackage("com.strider.datadefender.anonymizer.functions", true)
152
        ));
153
154
        req.setProject("Autogenerated Template Project");
155
        req.setVersion("1.0");
156
        req.setTables(tables);
157
158
        return req;
159
    }
160
161
    /**
162
     * Write requirement to file.
163
     * @param requirement
164
     * @param outFile
165
     * @throws DatabaseException
166
     */
167
    public static void write(final Requirement requirement, final File outFile) throws DatabaseException, JAXBException, SAXException {
168
        log.info("Requirement.write() to file: " + outFile.getName());
169
170
        final JAXBContext jc = JAXBContext.newInstance(Requirement.class);
171
        final Marshaller  marshaller = jc.createMarshaller();
172
        final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
173
        final Schema schema = schemaFactory.newSchema(Generator.class.getResource("requirement.xsd"));
174
175
        marshaller.setSchema(schema);
176
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
177
        marshaller.marshal(requirement, outFile);
178
    }
179
180
    /**
181
     * Returns argument of name "file" if exists else returns null
182
     * @param arguments List of function arguments
183
     * @return File parameter object
184
     */
185
    public static Argument getFileParameter(final List<Argument> arguments) {
186
        return CollectionUtils
187
            .emptyIfNull(arguments)
188
            .stream()
189
            .filter((a) -> StringUtils.equals(a.getName(), "file"))
190
            .findAny()
191
            .orElse(null);
192
    }
193
}
194