OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 19 | Rev 93 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 package org.openconcerto.sql.utils;
15
 
16
import static java.util.Collections.singleton;
17
import org.openconcerto.sql.Log;
18
import org.openconcerto.sql.model.ConnectionHandlerNoSetup;
19
import org.openconcerto.sql.model.DBRoot;
20
import org.openconcerto.sql.model.DBSystemRoot;
19 ilm 21
import org.openconcerto.sql.model.SQLBase;
17 ilm 22
import org.openconcerto.sql.model.SQLDataSource;
23
import org.openconcerto.sql.model.SQLRow;
24
import org.openconcerto.sql.model.SQLSchema;
25
import org.openconcerto.sql.model.SQLServer;
26
import org.openconcerto.sql.model.SQLSyntax;
27
import org.openconcerto.sql.model.SQLSystem;
28
import org.openconcerto.sql.model.SQLTable;
29
import org.openconcerto.utils.FileUtils;
30
import org.openconcerto.utils.LogUtils;
31
import org.openconcerto.utils.cc.IClosure;
32
 
33
import java.io.File;
34
import java.io.FileOutputStream;
35
import java.io.IOException;
36
import java.io.OutputStreamWriter;
37
import java.io.Writer;
38
import java.net.URISyntaxException;
39
import java.sql.SQLException;
40
import java.util.Collections;
41
import java.util.Set;
42
import java.util.logging.Level;
43
 
44
/**
45
 * To dump or restore a database. For each root there's a folder with its name, and inside a CSV
46
 * file for each table and a SQL file for each system.
47
 *
48
 * @author Sylvain
49
 */
50
public class Copy {
51
 
52
    public static final String ROOTS_TO_MAP = "rootsToMap";
53
    private static final String NO_STRUCT = "noStruct";
54
    private static final String NO_DATA = "noData";
55
    public static final String DELETE_TABLE = "deleteTable";
56
    public static final String NAME_TO_STORE = "nameToStore";
57
 
58
    private static void usage() {
59
        System.out.println("Usage: " + Copy.class.getName() + " [ -store | -load ] url directory");
60
        System.out.println("Dump or restore a root or table from/to url to/from files.");
61
        System.out.println("System properties:");
62
        System.out.println("\t" + ROOTS_TO_MAP + " = comma separated list of roots to map");
63
        System.out.println("\t" + NO_STRUCT + " = true to avoid dumping/restoring the structure");
64
        System.out.println("\t" + NO_DATA + " = true to avoid dumping/restoring the data");
65
        System.out.println("\t" + DELETE_TABLE + " = (only for loading) true to empty tables before loading data");
66
        System.out.println("\t" + NAME_TO_STORE + " = (only for storing) root name to use when storing, e.g. allow to copy one root to another");
67
    }
68
 
69
    public static void main(String[] args) throws SQLException, IOException, URISyntaxException {
70
        if (args.length < 3) {
71
            usage();
72
            System.exit(1);
73
        }
74
 
75
        final boolean store;
76
        if (args[0].equals("-store"))
77
            store = true;
78
        else if (args[0].equals("-load"))
79
            store = false;
80
        else
81
            throw new IllegalArgumentException("-store or -load");
82
        final SQL_URL url = SQL_URL.create(args[1]);
83
        final File dir = new File(args[2]);
84
 
85
        LogUtils.rmRootHandlers();
86
        LogUtils.setUpConsoleHandler();
87
        Log.get().setLevel(Level.INFO);
88
 
19 ilm 89
        System.setProperty(SQLBase.ALLOW_OBJECT_REMOVAL, "true");
17 ilm 90
        // we're backup/restore tool: don't touch the data at all
91
        System.setProperty(SQLSchema.NOAUTO_CREATE_METADATA, "true");
92
 
93
        final DBSystemRoot sysRoot = SQLServer.create(url, SQLRow.toList(System.getProperty(ROOTS_TO_MAP, "")), true, new IClosure<SQLDataSource>() {
94
            @Override
95
            public void executeChecked(SQLDataSource input) {
96
                input.addConnectionProperty("allowMultiQueries", "true");
97
            }
98
        });
99
        new Copy(store, dir, sysRoot, Boolean.getBoolean(NO_STRUCT), Boolean.getBoolean(NO_DATA)).applyTo(url.getRootName(), System.getProperty(NAME_TO_STORE), url.getTableName());
100
        sysRoot.getServer().destroy();
101
    }
102
 
103
    private final boolean store;
104
    private final boolean noStruct;
105
    private final boolean noData;
106
    private final File dir;
107
    private final DBSystemRoot sysRoot;
108
 
109
    public Copy(final boolean store, final File dir, final DBSystemRoot base, boolean noStruct, boolean noData) throws SQLException, IOException {
110
        this.store = store;
111
        this.noStruct = noStruct;
112
        this.noData = noData;
113
        this.dir = dir;
114
        FileUtils.mkdir_p(dir);
115
 
116
        this.sysRoot = base;
117
    }
118
 
119
    /**
120
     * Apply the copy operation to the passed root or table (and only it).
121
     *
122
     * @param rootName the name of the root to copy, cannot be <code>null</code>.
123
     * @param tableName the name of a table in <code>rootName</code>, <code>null</code> meaning all.
124
     * @throws SQLException if the database couldn't be accessed.
125
     * @throws IOException if the files couldn't be accessed.
126
     */
127
    public final void applyTo(final String rootName, final String tableName) throws SQLException, IOException {
128
        this.applyTo(rootName, rootName, tableName);
129
    }
130
 
131
    public final void applyTo(final String rootName, final String newRootName, final String tableName) throws SQLException, IOException {
132
        SQLUtils.executeAtomic(this.sysRoot.getDataSource(), new ConnectionHandlerNoSetup<Object, IOException>() {
133
            @Override
134
            public Object handle(SQLDataSource ds) throws SQLException, IOException {
135
                applyToP(rootName, newRootName == null ? rootName : newRootName, tableName);
136
                return null;
137
            }
138
        });
139
    }
140
 
141
    private void applyToP(final String rootName, final String newRootName, final String tableName) throws IOException, SQLException {
142
        DBRoot r = this.sysRoot.contains(rootName) ? this.sysRoot.getRoot(rootName) : null;
143
 
144
        if (!this.noStruct) {
83 ilm 145
            System.err.print("Structure of " + rootName + " ... ");
17 ilm 146
            if (this.store) {
147
                if (r == null)
148
                    throw new IllegalArgumentException(rootName + " does not exist in " + this.sysRoot);
149
                final SQLTable t;
150
                if (tableName != null) {
151
                    t = r.getTable(tableName);
152
                    if (t == null)
153
                        throw new IllegalArgumentException(tableName + " does not exist in " + r);
154
                } else
155
                    t = null;
156
                final File rootDir = this.getDir(newRootName);
157
                rootDir.delete();
158
                rootDir.mkdirs();
159
                for (final SQLSystem sys : SQLSystem.values()) {
160
                    if (sys.getSyntax() != null) {
161
                        final Writer w = new OutputStreamWriter(new FileOutputStream(getSQLFile(newRootName, tableName, sys)), "UTF8");
162
                        if (t != null)
163
                            w.write(t.getCreateTable(sys).asString(newRootName));
164
                        else
165
                            w.write(r.getDefinitionSQL(sys).asString(newRootName));
166
                        w.close();
167
                    }
168
                }
169
            } else {
170
                final SQLSystem system = this.sysRoot.getServer().getSQLSystem();
83 ilm 171
                String sql = FileUtils.readUTF8(getSQLFile(rootName, tableName, system));
172
                // for tables export there's no CREATE SCHEMA generated
173
                if (r == null && tableName != null) {
174
                    sql = new SQLCreateRoot(SQLSyntax.get(this.sysRoot), rootName).asString() + ";\n" + sql;
175
                }
17 ilm 176
                // 'CREATE SCHEMA' doit être la première instruction d'un traitement de requêtes.
177
                if (system == SQLSystem.MSSQL)
178
                    SQLUtils.executeScript(sql, this.sysRoot);
179
                else
180
                    this.sysRoot.getDataSource().execute(sql);
181
                this.sysRoot.refetch(Collections.singleton(rootName));
182
                r = this.sysRoot.getRoot(rootName);
183
            }
184
            System.err.println("done");
185
        }
186
 
187
        if (!this.noData) {
83 ilm 188
            System.err.println("Data of " + rootName + " ... ");
17 ilm 189
            final SQLSyntax syntax = this.sysRoot.getServer().getSQLSystem().getSyntax();
190
            final Set<String> tableNames = tableName == null ? null : singleton(tableName);
191
            // TODO support table with non-ASCII chars
192
            // eg : if on win with MySQL SET character_set_filesystem = latin1
193
            // may be just zip all data
194
            if (this.store)
195
                syntax.storeData(r, tableNames, this.getDir(newRootName));
196
            else
197
                syntax.loadData(this.getDir(rootName), r, tableNames, Boolean.getBoolean(DELETE_TABLE));
198
            System.err.println("Data done");
199
        }
200
    }
201
 
202
    private File getDir(final String rootName) {
203
        return new File(this.dir, rootName);
204
    }
205
 
206
    private File getSQLFile(final String rootName, final String tableName, final SQLSystem system) {
207
        final String t = tableName == null ? "" : tableName + "-";
208
        return new File(this.getDir(rootName), t + system.name().toLowerCase() + ".sql");
209
    }
210
}