<commit_before>/**
 * Copyright (C) 2009-2013 FoundationDB, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.foundationdb.server.service.routines;

import com.foundationdb.ais.model.Routine;
import com.foundationdb.ais.model.SQLJJar;
import com.foundationdb.ais.model.TableName;
import com.foundationdb.server.error.InvalidSQLJDeploymentDescriptorException;
import com.foundationdb.sql.StandardException;
import com.foundationdb.sql.aisddl.AISDDL;
import com.foundationdb.sql.aisddl.DDLHelper;
import com.foundationdb.sql.parser.CreateAliasNode;
import com.foundationdb.sql.parser.DDLStatementNode;
import com.foundationdb.sql.parser.DropAliasNode;
import com.foundationdb.sql.parser.SQLParserException;
import com.foundationdb.sql.parser.StatementNode;
import com.foundationdb.sql.server.ServerQueryContext;
import com.foundationdb.sql.server.ServerSession;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.regex.Pattern;

public class SQLJJarDeployer
{
    public static final String MANIFEST_ATTRIBUTE = "SQLJDeploymentDescriptor";
    public static final String DESCRIPTOR_FILE = "\\s*SQLActions\\s*\\[\\s*\\]\\s*\\=\\s*\\{.*\\}\\s*";
    public static final String BEGIN_INSTALL = "BEGIN INSTALL";
    public static final String END_INSTALL = "END INSTALL";
    public static final String BEGIN_REMOVE = "BEGIN REMOVE";
    public static final String END_REMOVE = "END REMOVE";

    private ServerQueryContext context;
    private TableName jarName;
    private ServerSession server;

    public SQLJJarDeployer(ServerQueryContext context, TableName jarName) {
        this.context = context;
        this.jarName = jarName;
        server = context.getServer();
    }

    public void deploy() {
        loadDeploymentDescriptor(false);
    }
   
    public void undeploy() {
        loadDeploymentDescriptor(true);
    }

    private void loadDeploymentDescriptor(boolean undeploy) {
        ClassLoader classLoader = server.getRoutineLoader().loadSQLJJar(context.getSession(), jarName);
        InputStream mstr = classLoader.getResourceAsStream("META-INF/MANIFEST.MF");
        if (mstr == null) return;
        Manifest manifest;
        try {
            manifest = new Manifest(mstr);
        }
        catch (IOException ex) {
            throw new InvalidSQLJDeploymentDescriptorException(jarName, ex);
        }
        for (Map.Entry<String,Attributes> entry : manifest.getEntries().entrySet()) {
            String val = entry.getValue().getValue(MANIFEST_ATTRIBUTE);
            if ((val != null) && Boolean.parseBoolean(val)) {
                InputStream istr = classLoader.getResourceAsStream(entry.getKey());
                if (istr != null) {
                    loadDeploymentDescriptor(istr, undeploy);
                    break;
                }
            }
        }
    }

    private void loadDeploymentDescriptor(InputStream istr, boolean undeploy) {
        StringBuilder contents = new StringBuilder();
        try {
            BufferedReader reader = 
                new BufferedReader(new InputStreamReader(istr, "UTF-8"));
            while (true) {
                String line = reader.readLine();
                if (line == null) break;
                contents.append(line).append('\n');
            }
        }
        catch (IOException ex) {
            throw new InvalidSQLJDeploymentDescriptorException(jarName, ex);
        }
        if (!Pattern.compile(DESCRIPTOR_FILE).matcher(contents).matches())
            throw new InvalidSQLJDeploymentDescriptorException(jarName, "Incorrect file format");
        String header, footer;
        if (undeploy) {
            header = BEGIN_REMOVE;
            footer = END_REMOVE;
        }
        else {
            header = BEGIN_INSTALL;
            footer = END_INSTALL;
        }
        int start = contents.indexOf(header);
        if (start < 0)
            throw new InvalidSQLJDeploymentDescriptorException(jarName, "Actions not found");
        start += header.length();
        int end = contents.indexOf(footer, start);
        if (end < 0)
            throw new InvalidSQLJDeploymentDescriptorException(jarName, "Actions not terminated");
        String sql = contents.substring(start, end);
        List<StatementNode> stmts;
        try {
            stmts = server.getParser().parseStatements(sql);
        } 
        catch (SQLParserException ex) {
            throw new InvalidSQLJDeploymentDescriptorException(jarName, ex);<commit_msg>Expect newlines in body of actions.<commit_after>/**
 * Copyright (C) 2009-2013 FoundationDB, LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.foundationdb.server.service.routines;

import com.foundationdb.ais.model.Routine;
import com.foundationdb.ais.model.SQLJJar;
import com.foundationdb.ais.model.TableName;
import com.foundationdb.server.error.InvalidSQLJDeploymentDescriptorException;
import com.foundationdb.sql.StandardException;
import com.foundationdb.sql.aisddl.AISDDL;
import com.foundationdb.sql.aisddl.DDLHelper;
import com.foundationdb.sql.parser.CreateAliasNode;
import com.foundationdb.sql.parser.DDLStatementNode;
import com.foundationdb.sql.parser.DropAliasNode;
import com.foundationdb.sql.parser.SQLParserException;
import com.foundationdb.sql.parser.StatementNode;
import com.foundationdb.sql.server.ServerQueryContext;
import com.foundationdb.sql.server.ServerSession;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import java.util.regex.Pattern;

public class SQLJJarDeployer
{
    public static final String MANIFEST_ATTRIBUTE = "SQLJDeploymentDescriptor";
    public static final String DESCRIPTOR_FILE = "\\s*SQLActions\\s*\\[\\s*\\]\\s*\\=\\s*\\{.*\\}\\s*";
    public static final String BEGIN_INSTALL = "BEGIN INSTALL";
    public static final String END_INSTALL = "END INSTALL";
    public static final String BEGIN_REMOVE = "BEGIN REMOVE";
    public static final String END_REMOVE = "END REMOVE";

    private ServerQueryContext context;
    private TableName jarName;
    private ServerSession server;

    public SQLJJarDeployer(ServerQueryContext context, TableName jarName) {
        this.context = context;
        this.jarName = jarName;
        server = context.getServer();
    }

    public void deploy() {
        loadDeploymentDescriptor(false);
    }
   
    public void undeploy() {
        loadDeploymentDescriptor(true);
    }

    private void loadDeploymentDescriptor(boolean undeploy) {
        ClassLoader classLoader = server.getRoutineLoader().loadSQLJJar(context.getSession(), jarName);
        InputStream mstr = classLoader.getResourceAsStream("META-INF/MANIFEST.MF");
        if (mstr == null) return;
        Manifest manifest;
        try {
            manifest = new Manifest(mstr);
        }
        catch (IOException ex) {
            throw new InvalidSQLJDeploymentDescriptorException(jarName, ex);
        }
        for (Map.Entry<String,Attributes> entry : manifest.getEntries().entrySet()) {
            String val = entry.getValue().getValue(MANIFEST_ATTRIBUTE);
            if ((val != null) && Boolean.parseBoolean(val)) {
                InputStream istr = classLoader.getResourceAsStream(entry.getKey());
                if (istr != null) {
                    loadDeploymentDescriptor(istr, undeploy);
                    break;
                }
            }
        }
    }

    private void loadDeploymentDescriptor(InputStream istr, boolean undeploy) {
        StringBuilder contents = new StringBuilder();
        try {
            BufferedReader reader = 
                new BufferedReader(new InputStreamReader(istr, "UTF-8"));
            while (true) {
                String line = reader.readLine();
                if (line == null) break;
                contents.append(line).append('\n');
            }
        }
        catch (IOException ex) {
            throw new InvalidSQLJDeploymentDescriptorException(jarName, ex);
        }
        if (!Pattern.compile(DESCRIPTOR_FILE, Pattern.DOTALL).matcher(contents).matches())
            throw new InvalidSQLJDeploymentDescriptorException(jarName, "Incorrect file format");
        String header, footer;
        if (undeploy) {
            header = BEGIN_REMOVE;
            footer = END_REMOVE;
        }
        else {
            header = BEGIN_INSTALL;
            footer = END_INSTALL;
        }
        int start = contents.indexOf(header);
        if (start < 0)
            throw new InvalidSQLJDeploymentDescriptorException(jarName, "Actions not found");
        start += header.length();
        int end = contents.indexOf(footer, start);
        if (end < 0)
            throw new InvalidSQLJDeploymentDescriptorException(jarName, "Actions not terminated");
        String sql = contents.substring(start, end);
        List<StatementNode> stmts;
        try {
            stmts = server.getParser().parseStatements(sql);
        } 
        catch (SQLParserException ex) {
            throw new InvalidSQLJDeploymentDescriptorException(jarName, ex);
{'fraction_non_alphanumeric': 0.09342203898050974, 'fraction_numerical': 0.0022488755622188904, 'mean_word_length': 2.8853294503094284, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, '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': '6989886', 'n_tokens_mistral': 2934, 'n_tokens_neox': 2844, 'n_words': 757}