<commit_before>/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */
package org.jboss.as.controller.persistence;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

import org.jboss.as.controller.persistence.ConfigurationPersister.SnapshotInfo;
import org.jboss.as.protocol.StreamUtils;

/**
 * Encapsulates the configuration file and manages its history
 * @author <a href="<EMAIL>"><NAME></a>
 * @version $Revision: 1.1 $
 */
public class ConfigurationFile {

    private static final String LAST = "last";
    private static final String INITIAL = "initial";
    private static final String ORIGINAL = "original";

    private static final int CURRENT_HISTORY_LENGTH = 100;
    private static final int HISTORY_DAYS = 30;
    private static final String TIMESTAMP_STRING = "\\d\\d\\d\\d\\d\\d\\d\\d-\\d\\d\\d\\d\\d\\d\\d\\d\\d";
    private static final Pattern TIMESTAMP_PATTERN = Pattern.compile(TIMESTAMP_STRING);
    private static final Pattern VERSION_PATTERN = Pattern.compile("v\\d+");
    private static final Pattern SNAPSHOT_XML = Pattern.compile(TIMESTAMP_STRING + ".xml");


    private final AtomicInteger sequence = new AtomicInteger();
    private final AtomicBoolean doneBootup = new AtomicBoolean();
    private final File configurationDir;
    private volatile File bootFile;
    private volatile File mainFile;
    private final File historyRoot;
    private final File currentHistory;
    private final File snapshotsDirectory;


    public ConfigurationFile(final File configurationDir, final String rawName, final String name) {
        this(configurationDir, rawName, name, false);
    }

    public ConfigurationFile(final File configurationDir, final String rawName, final String name, boolean validate) {
        if (!configurationDir.exists() || !configurationDir.isDirectory()) {
            throw new IllegalArgumentException("No directory " + configurationDir.getAbsolutePath() + " was found");
        }
        this.configurationDir = configurationDir;
        this.mainFile = new File(configurationDir, rawName);
        this.historyRoot = mkdir(new File(configurationDir, rawName.replace('.', '_')));
        this.currentHistory = new File(historyRoot, "current");
        this.snapshotsDirectory = mkdir(new File(historyRoot, "snapshot"));
        this.bootFile = name.equals(rawName) ? mainFile : determineBootFile(configurationDir, name);
    }

    private File determineBootFile(final File configurationDir, final String name) {
        if (name.equals(LAST) || name.equals(INITIAL) || name.equals(ORIGINAL)) {
            return addSuffixToFile(mainFile, name);
        } else if (VERSION_PATTERN.matcher(name).matches()) {
            return getVersionedFile(mainFile, name);
        }
        final File snapshot = findSnapshotWithPrefix(name, false);
        if (snapshot != null) {
            return snapshot;
        }
        final File directoryFile = new File(configurationDir, name);
        if (directoryFile.exists()) {
            return directoryFile;
        }
        final File absoluteFile = new File(name);
        if (absoluteFile.exists()) {
            return absoluteFile;
        }
        throw new IllegalArgumentException("Neither " + directoryFile.getAbsolutePath() + " nor " + absoluteFile.getAbsolutePath() + " exist");
    }

    File getBootFile() {
        //System.out.println("----- Boot file " + bootFile.getAbsolutePath());
        return bootFile;
    }

    File getMainFile() {
        //System.out.println("----- Using file " + mainFile.getAbsolutePath());
        return mainFile;
    }


    public boolean isMainFile() {
        return mainFile.equals(bootFile);
    }

    public void overrideFile(final String name) {
        if (doneBootup.get()) {
            throw new IllegalArgumentException("Cannot change files in already booted server");
        }
        final File file = new File(configurationDir, name);
        if (!file.exists()) {
            throw new IllegalArgumentException(file.getAbsolutePath() + " does not exist");
        }
        mainFile = file;
        bootFile = file;
    }

    void successfulBoot() throws ConfigurationPersistenceException {
        synchronized (this) {
            if (doneBootup.get()) {
                return;
            }

            try {
                createHistoryDirectory();

                final File last = addSuffixToFile(mainFile, LAST);
                final File original = addSuffixToFile(mainFile, ORIGINAL);
                final File initial = addSuffixToFile(mainFile, INITIAL);

                if (!initial.exists()) {
                    copyFile(mainFile, initial);
                }

                if (!last.exists()) {
                    copyFile(mainFile, last);
                }
                if (!original.exists() || (last.exists() && mainFile.lastModified() > last.lastModified())) {
                    copyFile(mainFile, original);
                    snapshot();
                    last.setLastModified(System.currentTimeMillis());
                }
            } catch (IOException e) {
                // AutoGenerated
                throw new RuntimeException(e);
            }
            doneBootup.set(true);
        }
    }


    void backup() throws ConfigurationPersistenceException {
        if (!doneBootup.get()) {
            return;
        }
        try {
            moveFile(mainFile, getVersionedFile(mainFile));
            int seq = sequence.get();
            if (seq > CURRENT_HISTORY_LENGTH) {
                File delete = getVersionedFile(mainFile, seq - CURRENT_HISTORY_LENGTH);
                if (delete.exists()) {
                    delete.delete();
                }
            }
        } catch (IOException e) {
            throw new ConfigurationPersistenceException("Failed to back up " + mainFile, e);
        }
    }<commit_msg>[JBAS-8680] Create last and original on every boot<commit_after>/*
 * JBoss, Home of Professional Open Source
 * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
 * as indicated by the @authors tag. All rights reserved.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU Lesser General Public License, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public License,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 */
package org.jboss.as.controller.persistence;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

import org.jboss.as.controller.persistence.ConfigurationPersister.SnapshotInfo;
import org.jboss.as.protocol.StreamUtils;

/**
 * Encapsulates the configuration file and manages its history
 * @author <a href="<EMAIL>"><NAME></a>
 * @version $Revision: 1.1 $
 */
public class ConfigurationFile {

    private static final String LAST = "last";
    private static final String INITIAL = "initial";
    private static final String ORIGINAL = "original";

    private static final int CURRENT_HISTORY_LENGTH = 100;
    private static final int HISTORY_DAYS = 30;
    private static final String TIMESTAMP_STRING = "\\d\\d\\d\\d\\d\\d\\d\\d-\\d\\d\\d\\d\\d\\d\\d\\d\\d";
    private static final Pattern TIMESTAMP_PATTERN = Pattern.compile(TIMESTAMP_STRING);
    private static final Pattern VERSION_PATTERN = Pattern.compile("v\\d+");
    private static final Pattern SNAPSHOT_XML = Pattern.compile(TIMESTAMP_STRING + ".xml");


    private final AtomicInteger sequence = new AtomicInteger();
    private final AtomicBoolean doneBootup = new AtomicBoolean();
    private final File configurationDir;
    private volatile File bootFile;
    private volatile File mainFile;
    private final File historyRoot;
    private final File currentHistory;
    private final File snapshotsDirectory;


    public ConfigurationFile(final File configurationDir, final String rawName, final String name) {
        this(configurationDir, rawName, name, false);
    }

    public ConfigurationFile(final File configurationDir, final String rawName, final String name, boolean validate) {
        if (!configurationDir.exists() || !configurationDir.isDirectory()) {
            throw new IllegalArgumentException("No directory " + configurationDir.getAbsolutePath() + " was found");
        }
        this.configurationDir = configurationDir;
        this.mainFile = new File(configurationDir, rawName);
        this.historyRoot = mkdir(new File(configurationDir, rawName.replace('.', '_')));
        this.currentHistory = new File(historyRoot, "current");
        this.snapshotsDirectory = mkdir(new File(historyRoot, "snapshot"));
        this.bootFile = name.equals(rawName) ? mainFile : determineBootFile(configurationDir, name);
    }

    private File determineBootFile(final File configurationDir, final String name) {
        if (name.equals(LAST) || name.equals(INITIAL) || name.equals(ORIGINAL)) {
            return addSuffixToFile(mainFile, name);
        } else if (VERSION_PATTERN.matcher(name).matches()) {
            return getVersionedFile(mainFile, name);
        }
        final File snapshot = findSnapshotWithPrefix(name, false);
        if (snapshot != null) {
            return snapshot;
        }
        final File directoryFile = new File(configurationDir, name);
        if (directoryFile.exists()) {
            return directoryFile;
        }
        final File absoluteFile = new File(name);
        if (absoluteFile.exists()) {
            return absoluteFile;
        }
        throw new IllegalArgumentException("Neither " + directoryFile.getAbsolutePath() + " nor " + absoluteFile.getAbsolutePath() + " exist");
    }

    File getBootFile() {
        //System.out.println("----- Boot file " + bootFile.getAbsolutePath());
        return bootFile;
    }

    File getMainFile() {
        //System.out.println("----- Using file " + mainFile.getAbsolutePath());
        return mainFile;
    }


    public boolean isMainFile() {
        return mainFile.equals(bootFile);
    }

    public void overrideFile(final String name) {
        if (doneBootup.get()) {
            throw new IllegalArgumentException("Cannot change files in already booted server");
        }
        final File file = new File(configurationDir, name);
        if (!file.exists()) {
            throw new IllegalArgumentException(file.getAbsolutePath() + " does not exist");
        }
        mainFile = file;
        bootFile = file;
    }

    void successfulBoot() throws ConfigurationPersistenceException {
        synchronized (this) {
            if (doneBootup.get()) {
                return;
            }

            try {
                createHistoryDirectory();

                final File last = addSuffixToFile(mainFile, LAST);
                final File original = addSuffixToFile(mainFile, ORIGINAL);
                final File initial = addSuffixToFile(mainFile, INITIAL);

                if (!initial.exists()) {
                    copyFile(mainFile, initial);
                }

                copyFile(mainFile, last);
                copyFile(mainFile, original);
                snapshot();
            } catch (IOException e) {
                // AutoGenerated
                throw new RuntimeException(e);
            }
            doneBootup.set(true);
        }
    }


    void backup() throws ConfigurationPersistenceException {
        if (!doneBootup.get()) {
            return;
        }
        try {
            moveFile(mainFile, getVersionedFile(mainFile));
            int seq = sequence.get();
            if (seq > CURRENT_HISTORY_LENGTH) {
                File delete = getVersionedFile(mainFile, seq - CURRENT_HISTORY_LENGTH);
                if (delete.exists()) {
                    delete.delete();
                }
            }
        } catch (IOException e) {
            throw new ConfigurationPersistenceException("Failed to back up " + mainFile, e);
        }
    }
{'fraction_non_alphanumeric': 0.09700063816209317, 'fraction_numerical': 0.003970786357512586, 'mean_word_length': 2.6435029708085764, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5455394', 'n_tokens_mistral': 3693, 'n_tokens_neox': 3545, 'n_words': 1089}