Package com.cedarsoftware.ncube

Source Code of com.cedarsoftware.ncube.NCubeManager

package com.cedarsoftware.ncube;

import com.cedarsoftware.ncube.formatters.JsonFormatter;
import com.cedarsoftware.util.IOUtilities;
import com.cedarsoftware.util.StringUtilities;
import com.cedarsoftware.util.UniqueIdGenerator;
import com.cedarsoftware.util.io.JsonObject;
import com.cedarsoftware.util.io.JsonReader;
import com.cedarsoftware.util.io.JsonWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;

/**
* This class manages a list of NCubes.  This class is referenced
* by NCube in one place - when it joins to other cubes, it consults
* the NCubeManager to find the joined NCube.
* <p/>
* This class takes care of creating, loading, updating, releasing,
* and deleting NCubes.  It also allows you to get a list of NCubes
* matching a wildcard (SQL Like) string.
*
* @author John DeRegnaucourt (jdereg@gmail.com)
*         <br/>
*         Copyright (c) Cedar Software LLC
*         <br/><br/>
*         Licensed under the Apache License, Version 2.0 (the "License");
*         you may not use this file except in compliance with the License.
*         You may obtain a copy of the License at
*         <br/><br/>
*         http://www.apache.org/licenses/LICENSE-2.0
*         <br/><br/>
*         Unless required by applicable law or agreed to in writing, software
*         distributed under the License is distributed on an "AS IS" BASIS,
*         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*         See the License for the specific language governing permissions and
*         limitations under the License.
*/
public class NCubeManager
{
    private static final Map<String, NCube> cubeList = new ConcurrentHashMap<String, NCube>();
    private static final Log LOG = LogFactory.getLog(NCubeManager.class);
    private static Map<String, Map<String, Advice>> advices = new LinkedHashMap<String, Map<String, Advice>>();

    /**
     * @param name String name of an NCube.
     * @return NCube instance with the given name.  Please note
     * that the cube must be loaded first before calling this.
     */
    public static NCube getCube(String name, String version)
    {
        return cubeList.get(makeCacheKey(name, version));
    }

    static String makeCacheKey(String name, String version)
    {
        return name + '.' + version;
    }

    /**
     * Add a cube to the internal map of available cubes.
     *
     * @param ncube NCube to add to the list.
     */
    static void addCube(NCube ncube, String version)
    {
        synchronized (cubeList)
        {
            ncube.setVersion(version);
            cubeList.put(makeCacheKey(ncube.getName(), version), ncube);
            for (String regex : advices.keySet())
            {
                if (ncube.getName().matches(StringUtilities.wildcardToRegexString(regex)))
                {
                    for (Advice advice : advices.get(regex).values())
                    {
                        ncube.addAdvice(advice);
                    }
                }
            }
        }
    }

    /**
     * @return Map<String, NCube> of all NCubes that are currently
     * loaded (cached) in memory.  A copy of the internal cache
     * is returned.
     */
    public static Map<String, NCube> getCachedNCubes()
    {
        synchronized (cubeList)
        {
            return new TreeMap<String, NCube>(cubeList);
        }
    }

    /**
     * Used for testing.
     */
    public static void clearCubeList()
    {
        synchronized (cubeList)
        {
            cubeList.clear();
            GroovyBase.compiledClasses.clear();
            GroovyBase.groovyClassLoader.clearCache();
            advices.clear();
        }
    }

    /**
     * Associate Advice to all n-cubes that match the passed in regular expression.
     */
    public static void addAdvice(String ncubeNameWildcard, Advice advice)
    {
        synchronized (cubeList)
        {
            Map<String, Advice> current = advices.get(ncubeNameWildcard);
            if (current == null)
            {
                current = new LinkedHashMap<String, Advice>();
                advices.put(ncubeNameWildcard, current);
            }

            current.put(advice.getName(), advice);
            String regex = StringUtilities.wildcardToRegexString(ncubeNameWildcard);

            for (NCube ncube : cubeList.values())
            {
                if (ncube.getName().matches(regex))
                {
                    ncube.addAdvice(advice);
                }
            }
        }
    }

    private static void jdbcCleanup(PreparedStatement stmt)
    {
        if (stmt != null)
        {
            try
            {
                stmt.close();
            }
            catch (SQLException e)
            {
                LOG.error("Error closing JDBC Statement", e);
            }
        }
    }

    private static void validateConnection(Connection c)
    {
        if (c == null)
        {
            throw new IllegalArgumentException("Connection cannot be null");
        }
    }

    public static void validateApp(String app)
    {
        if (StringUtilities.isEmpty(app))
        {
            throw new IllegalArgumentException("App cannot be null or empty");
        }
    }

    public static void validateCubeName(String cubeName)
    {
        if (StringUtilities.isEmpty(cubeName))
        {
            throw new IllegalArgumentException("n-cube name cannot be null or empty");
        }

        Matcher m = Regexes.validCubeName.matcher(cubeName);
        if (m.find())
        {
            if (cubeName.equals(m.group(0)))
            {
                return;
            }
        }
        throw new IllegalArgumentException("n-cube name can only contain a-z, A-Z, 0-9, :, ., _, -, #, and |");
    }

    public static void validateVersion(String version)
    {
        if (StringUtilities.isEmpty(version))
        {
            throw new IllegalArgumentException("n-cube version cannot be null or empty");
        }

        Matcher m = Regexes.validVersion.matcher(version);
        if (m.find())
        {
            return;
        }
        throw new IllegalArgumentException("n-cube version must follow the form n.n.n where n is a number 0 or greater. The numbers stand for major.minor.revision");
    }

    public static void validateStatus(String status)
    {
        if (StringUtilities.isEmpty(status))
        {
            throw new IllegalArgumentException("n-cube status cannot be null or empty");
        }

        if (status.equals("RELEASE") || status.equals("SNAPSHOT"))
        {
            return;
        }
        throw new IllegalArgumentException("n-cube status must be RELEASE or SNAPSHOT");
    }

    /**
     * Load an NCube from the database (any joined sub-cubes will also be loaded).
     *
     * @return NCube that matches, or null if not found.
     */
    public static NCube loadCube(Connection connection, String app, String name, String version, String status, Date sysDate)
    {
        validateConnection(connection);
        validateApp(app);
        validateCubeName(name);
        validateStatus(status);
        if (sysDate == null)
        {
            sysDate = new Date();
        }

        synchronized (cubeList)
        {
            PreparedStatement stmt = null;
            try
            {
                java.sql.Date systemDate = new java.sql.Date(sysDate.getTime());
                stmt = connection.prepareStatement("SELECT cube_value_bin FROM n_cube WHERE n_cube_nm = ? AND app_cd = ? AND sys_effective_dt <= ? AND (sys_expiration_dt IS NULL OR sys_expiration_dt >= ?) AND version_no_cd = ? AND status_cd = ?");

                stmt.setString(1, name);
                stmt.setString(2, app);
                stmt.setDate(3, systemDate);
                stmt.setDate(4, systemDate);
                stmt.setString(5, version);
                stmt.setString(6, status);
                ResultSet rs = stmt.executeQuery();

                if (rs.next())
                {
                    byte[] jsonBytes = rs.getBytes("cube_value_bin");
                    String json = new String(jsonBytes, "UTF-8");
                    NCube ncube = ncubeFromJson(json);

                    if (rs.next())
                    {
                        throw new IllegalStateException("More than one NCube matching name: " + ncube.getName() + ", app: " + app + ", version: " + version + ", status: " + status + ", sysDate: " + sysDate);
                    }

                    addCube(ncube, version);
                    Set<String> subCubeList = ncube.getReferencedCubeNames();

                    for (String cubeName : subCubeList)
                    {
                        final String cacheKey = makeCacheKey(cubeName, version);
                        if (!cubeList.containsKey(cacheKey))
                        {
                            loadCube(connection, app, cubeName, version, status, sysDate);
                        }
                    }
                    return ncube;
                }
                return null; // Indicates not found
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to load nNCube: " + name + ", app: " + app + ", version: " + version + ", status: " + status + ", sysDate: " + sysDate + " from database";
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt);
            }
        }
    }

    /**
     * Retrieve all cube names that are deeply referenced by the named app, cube (name), version, and status.
     */
    public static void getReferencedCubeNames(Connection connection, String app, String name, String version, String status, Date sysDate, Set<String> refs)
    {
        validateConnection(connection);
        validateApp(app);
        validateCubeName(name);
        validateVersion(version);
        validateStatus(status);
        if (sysDate == null)
        {
            sysDate = new Date();
        }
        if (refs == null)
        {
            throw new IllegalArgumentException("null passed in for Set to hold referenced n-cube names");
        }

        PreparedStatement stmt = null;
        try
        {
            java.sql.Date systemDate = new java.sql.Date(sysDate.getTime());
            stmt = connection.prepareStatement("SELECT cube_value_bin FROM n_cube WHERE n_cube_nm = ? AND app_cd = ? AND sys_effective_dt <= ? AND (sys_expiration_dt IS NULL OR sys_expiration_dt >= ?) AND version_no_cd = ? AND status_cd = ?");

            stmt.setString(1, name);
            stmt.setString(2, app);
            stmt.setDate(3, systemDate);
            stmt.setDate(4, systemDate);
            stmt.setString(5, version);
            stmt.setString(6, status);
            ResultSet rs = stmt.executeQuery();

            if (rs.next())
            {
                byte[] jsonBytes = rs.getBytes("cube_value_bin");
                String json = new String(jsonBytes, "UTF-8");
                NCube ncube = ncubeFromJson(json);

                if (rs.next())
                {
                    throw new IllegalStateException("More than one NCube matching name: " + ncube.getName() + ", app: " + app + ", version: " + version + ", status: " + status + ", sysDate: " + sysDate);
                }

                Set<String> subCubeList = ncube.getReferencedCubeNames();
                refs.addAll(subCubeList);

                for (String cubeName : subCubeList)
                {
                    if (!refs.contains(cubeName))
                    {
                        getReferencedCubeNames(connection, app, cubeName, version, status, sysDate, refs);
                    }
                }
            }
        }
        catch (IllegalStateException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            String s = "Unable to load nNCube: " + name + ", app: " + app + ", version: " + version + ", status: " + status + ", sysDate: " + sysDate + " from database";
            LOG.error(s, e);
            throw new RuntimeException(s, e);
        }
        finally
        {
            jdbcCleanup(stmt);
        }
    }

    /**
     * Retrieve all n-cubes that have a name that matches the SQL like statement, within the specified app, status,
     * version, and system date.
     */
    public static Object[] getNCubes(Connection connection, String app, String version, String status, String sqlLike, Date sysDate)
    {
        validateConnection(connection);
        validateApp(app);
        validateVersion(version);
        validateStatus(status);

        if (sqlLike == null)
        {
            sqlLike = "%";
        }

        if (sysDate == null)
        {
            sysDate = new Date();
        }

        PreparedStatement stmt = null;
        try
        {
            java.sql.Date systemDate = new java.sql.Date(sysDate.getTime());
            stmt = connection.prepareStatement("SELECT n_cube_id, n_cube_nm, notes_bin, version_no_cd, status_cd, app_cd, create_dt, update_dt, " +
                    "create_hid, update_hid, sys_effective_dt, sys_expiration_dt, business_effective_dt, business_expiration_dt FROM n_cube WHERE n_cube_nm LIKE ? AND app_cd = ? AND version_no_cd = ? AND status_cd = ? AND sys_effective_dt <= ? AND (sys_expiration_dt IS NULL OR sys_expiration_dt >= ?)");
            stmt.setString(1, sqlLike);
            stmt.setString(2, app);
            stmt.setString(3, version);
            stmt.setString(4, status);
            stmt.setDate(5, systemDate);
            stmt.setDate(6, systemDate);

            ResultSet rs = stmt.executeQuery();
            List<NCubeInfoDto> records = new ArrayList<NCubeInfoDto>();

            while (rs.next())
            {
                NCubeInfoDto dto = new NCubeInfoDto();
                dto.id = Long.toString(rs.getLong("n_cube_id"));
                dto.name = rs.getString("n_cube_nm");
                byte[] notes = rs.getBytes("notes_bin");
                dto.notes = new String(notes == null ? "".getBytes() : notes, "UTF-8");
                dto.version = rs.getString("version_no_cd");
                dto.status = rs.getString("status_cd");
                dto.app = rs.getString("app_cd");
                dto.createDate = rs.getDate("create_dt");
                dto.updateDate = rs.getDate("update_dt");
                dto.createHid = rs.getString("create_hid");
                dto.updateHid = rs.getString("update_hid");
                dto.sysEffDate = rs.getDate("sys_effective_dt");
                dto.sysEndDate = rs.getDate("sys_expiration_dt");
                dto.bizEffDate = rs.getDate("business_effective_dt");
                dto.bizExpDate = rs.getDate("business_expiration_dt");
                records.add(dto);
            }
            return records.toArray();
        }
        catch (Exception e)
        {
            String s = "Unable to fetch NCubes matching '" + sqlLike + "' from database";
            LOG.error(s, e);
            throw new RuntimeException(s, e);
        }
        finally
        {
            jdbcCleanup(stmt);
        }
    }

    /**
     * Duplicate the specified n-cube, given it the new name, and the same app, version, status as the source n-cube.
     */
    public static void duplicate(Connection connection, String newName, String name, String newApp, String app, String newVersion, String version, String status, Date sysDate)
    {
        NCube ncube = loadCube(connection, app, name, version, status, sysDate);
        NCube copy = ncube.duplicate(newName);
        createCube(connection, newApp, copy, newVersion);
        String json = getTestData(connection, app, name, version, sysDate);
        updateTestData(connection, newApp, newName, newVersion, json);
        String notes = getNotes(connection, app, name, version, sysDate);
        updateNotes(connection, newApp, newName, newVersion, notes);
    }

    /**
     * Return an array [] of Strings containing all unique App names.
     */
    public static Object[] getAppNames(Connection connection, Date sysDate)
    {
        validateConnection(connection);
        if (sysDate == null)
        {
            sysDate = new Date();
        }

        PreparedStatement stmt = null;
        try
        {
            java.sql.Date systemDate = new java.sql.Date(sysDate.getTime());
            stmt = connection.prepareStatement("SELECT DISTINCT app_cd FROM n_cube WHERE sys_effective_dt <= ? AND (sys_expiration_dt IS NULL OR sys_expiration_dt >= ?)");
            stmt.setDate(1, systemDate);
            stmt.setDate(2, systemDate);
            ResultSet rs = stmt.executeQuery();
            List<String> records = new ArrayList<String>();

            while (rs.next())
            {
                records.add(rs.getString(1));
            }
            Collections.sort(records);
            return records.toArray();
        }
        catch (Exception e)
        {
            String s = "Unable to fetch all ncube app names from database";
            LOG.error(s, e);
            throw new RuntimeException(s, e);
        }
        finally
        {
            jdbcCleanup(stmt);
        }
    }

    /**
     * Return an array [] of Strings containing all unique App names.
     */
    public static Object[] getAppVersions(Connection connection, String app, String status, Date sysDate)
    {
        validateConnection(connection);
        validateApp(app);
        validateStatus(status);
        if (sysDate == null)
        {
            sysDate = new Date();
        }

        PreparedStatement stmt = null;
        try
        {
            java.sql.Date systemDate = new java.sql.Date(sysDate.getTime());
            stmt = connection.prepareStatement("SELECT DISTINCT version_no_cd FROM n_cube WHERE app_cd = ? and status_cd = ? AND sys_effective_dt <= ? AND (sys_expiration_dt IS NULL OR sys_expiration_dt >= ?)");
            stmt.setString(1, app);
            stmt.setString(2, status);
            stmt.setDate(3, systemDate);
            stmt.setDate(4, systemDate);

            ResultSet rs = stmt.executeQuery();
            List<String> records = new ArrayList<String>();

            while (rs.next())
            {
                records.add(rs.getString(1));
            }
            Collections.sort(records)// May need to enhance to ensure 2.19.1 comes after 2.2.1
            return records.toArray();
        }
        catch (Exception e)
        {
            String s = "Unable to fetch all ncube app versions from database";
            LOG.error(s, e);
            throw new RuntimeException(s, e);
        }
        finally
        {
            jdbcCleanup(stmt);
        }
    }

    /**
     * Update the passed in NCube.  Only SNAPSHOT ncubes can be updated.
     *
     * @param connection JDBC connection
     * @param ncube      NCube to be updated.
     * @return boolean true on success, false otherwise
     */
    public static boolean updateCube(Connection connection, String app, NCube ncube, String version)
    {
        validateConnection(connection);
        validateApp(app);
        validateVersion(version);
        if (ncube == null)
        {
            throw new IllegalArgumentException("NCube cannot be null for updating");
        }

        synchronized (cubeList)
        {
            PreparedStatement stmt = null;
            try
            {
                stmt = connection.prepareStatement("UPDATE n_cube SET cube_value_bin=?, update_dt=? WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.SNAPSHOT + "'");
                stmt.setBytes(1, new JsonFormatter().format(ncube).getBytes("UTF-8"));
                stmt.setDate(2, new java.sql.Date(System.currentTimeMillis()));
                stmt.setString(3, app);
                stmt.setString(4, ncube.getName());
                stmt.setString(5, version);
                int count = stmt.executeUpdate();
                if (count != 1)
                {
                    throw new IllegalStateException("Only one (1) row should be updated.");
                }
                ncube.setVersion(version);
                return true;
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to update NCube: " + ncube.getName() + ", app: " + app + ", version: " + version;
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt);
            }
        }
    }

    /**
     * Persist the passed in NCube
     *
     * @param connection JDBC connection
     * @param ncube      NCube to be persisted
     */
    public static void createCube(Connection connection, String app, NCube ncube, String version)
    {
        validateConnection(connection);
        validateApp(app);
        validateVersion(version);
        if (ncube == null)
        {
            throw new IllegalArgumentException("NCube cannot be null when creating a new n-cube");
        }
        validateCubeName(ncube.getName());

        synchronized (cubeList)
        {
            PreparedStatement stmt = null;
            try
            {
                stmt = connection.prepareStatement("SELECT n_cube_id AS \"id\" FROM n_cube WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ?");
                stmt.setString(1, app);
                stmt.setString(2, ncube.getName());
                stmt.setString(3, version);
                ResultSet rs = stmt.executeQuery();

                if (rs.next())
                {    // NCube with same name and version number already exists.
                    throw new IllegalStateException("NCube '" + ncube.getName() + "' (" + version + ") already exists.");
                }
                else
                {   // Do INSERT
                    stmt.close();
                    stmt = connection.prepareStatement("INSERT INTO n_cube (n_cube_id, app_cd, n_cube_nm, cube_value_bin, version_no_cd, create_dt, sys_effective_dt) VALUES (?, ?, ?, ?, ?, ?, ?)");
                    stmt.setLong(1, UniqueIdGenerator.getUniqueId());
                    stmt.setString(2, app);
                    stmt.setString(3, ncube.getName());
                    String json = new JsonFormatter().format(ncube);
                    //                    String json = JsonWriter.objectToJson(ncube);
                    stmt.setBytes(4, json.getBytes("UTF-8"));
                    stmt.setString(5, version);
                    java.sql.Date now = new java.sql.Date(System.currentTimeMillis());
                    stmt.setDate(6, now);
                    stmt.setDate(7, now);
                    int rowCount = stmt.executeUpdate();
                    if (rowCount != 1)
                    {
                        throw new IllegalStateException("error saving new NCube: " + ncube.getName() + "', app: " + app + ", version: " + version + " (" + rowCount + " rows inserted, should be 1)");
                    }
                }

                addCube(ncube, version);
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to save NCube: " + ncube.getName() + ", app: " + app + ", version: " + version + " to database";
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt);
            }
        }
    }

    /**
     * Move ncubes matching the passed in version and APP_CD from SNAPSHOT to RELEASE
     * state. All ncubes move version at the same time.  This is by design so that the
     * cube join commands do not need to mess with determining what ncube versions
     * they join with.
     *
     * @param connection JDBC connection
     * @param version    String version to move from SNAPSHOT to RELEASE
     * @return int count of ncubes that were released
     */
    public static int releaseCubes(Connection connection, String app, String version)
    {
        validateConnection(connection);
        validateApp(app);
        validateVersion(version);

        synchronized (cubeList)
        {
            PreparedStatement stmt1 = null;
            PreparedStatement stmt2 = null;

            try
            {
                stmt1 = connection.prepareStatement("SELECT n_cube_id FROM n_cube WHERE app_cd = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.RELEASE + "'");
                stmt1.setString(1, app);
                stmt1.setString(2, version);
                ResultSet rs = stmt1.executeQuery();
                if (rs.next())
                {
                    throw new IllegalStateException("A RELEASE version " + version + " already exists. Have system admin renumber your SNAPSHOT version.");
                }

                stmt2 = connection.prepareStatement("UPDATE n_cube SET update_dt = ?, status_cd = '" + ReleaseStatus.RELEASE + "' WHERE app_cd = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.SNAPSHOT + "'");
                stmt2.setDate(1, new java.sql.Date(System.currentTimeMillis()));
                stmt2.setString(2, app);
                stmt2.setString(3, version);
                return stmt2.executeUpdate();
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to release NCubes for app: " + app + ", version: " + version + ", due to an error: " + e.getMessage();
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt1);
                jdbcCleanup(stmt2);
            }
        }
    }

    /**
     * This API creates a SNAPSHOT set of cubes by copying all of
     * the RELEASE ncubes that match the oldVersion and app to
     * the new version in SNAPSHOT mode.  Basically, it duplicates
     * an entire set of NCubes and places a new version label on them,
     * in SNAPSHOT status.
     */
    public static int createSnapshotCubes(Connection connection, String app, String relVersion, String newSnapVer)
    {
        validateConnection(connection);
        validateApp(app);
        validateVersion(relVersion);
        validateVersion(newSnapVer);

        if (relVersion.equals(newSnapVer))
        {
            throw new IllegalArgumentException("New SNAPSHOT version " + relVersion + " cannot be the same as the RELEASE version.");
        }

        synchronized (cubeList)
        {
            PreparedStatement stmt0 = null;
            PreparedStatement stmt1 = null;
            PreparedStatement stmt2 = null;

            try
            {
                stmt0 = connection.prepareStatement("SELECT n_cube_id FROM n_cube WHERE app_cd = ? AND version_no_cd = ?");
                stmt0.setString(1, app);
                stmt0.setString(2, newSnapVer);
                ResultSet rs = stmt0.executeQuery();
                if (rs.next())
                {
                    throw new IllegalStateException("New SNAPSHOT Version specified (" + newSnapVer + ") matches an existing version.  Specify new SNAPSHOT version that does not exist.");
                }
                rs.close();

                stmt1 = connection.prepareStatement(
                        "SELECT n_cube_nm, cube_value_bin, create_dt, update_dt, create_hid, update_hid, version_no_cd, status_cd, sys_effective_dt, sys_expiration_dt, business_effective_dt, business_expiration_dt, app_cd, test_data_bin, notes_bin\n" +
                                "FROM n_cube\n" +
                                "WHERE app_cd = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.RELEASE + "'"
                );

                stmt1.setString(1, app);
                stmt1.setString(2, relVersion);
                rs = stmt1.executeQuery();

                stmt2 = connection.prepareStatement(
                        "INSERT INTO n_cube (n_cube_id, n_cube_nm, cube_value_bin, create_dt, update_dt, create_hid, update_hid, version_no_cd, status_cd, sys_effective_dt, sys_expiration_dt, business_effective_dt, business_expiration_dt, app_cd, test_data_bin, notes_bin)\n" +
                                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
                );
                int count = 0;

                while (rs.next())
                {
                    count++;
                    stmt2.setLong(1, UniqueIdGenerator.getUniqueId());
                    stmt2.setString(2, rs.getString("n_cube_nm"));
                    stmt2.setBytes(3, rs.getBytes("cube_value_bin"));
                    stmt2.setDate(4, new java.sql.Date(System.currentTimeMillis()));
                    stmt2.setDate(5, new java.sql.Date(System.currentTimeMillis()));
                    stmt2.setString(6, rs.getString("create_hid"));
                    stmt2.setString(7, rs.getString("update_hid"));
                    stmt2.setString(8, newSnapVer);
                    stmt2.setString(9, ReleaseStatus.SNAPSHOT.name());
                    stmt2.setDate(10, rs.getDate("sys_effective_dt"));
                    stmt2.setDate(11, rs.getDate("sys_expiration_dt"));
                    stmt2.setDate(12, rs.getDate("business_effective_dt"));
                    stmt2.setDate(13, rs.getDate("business_expiration_dt"));
                    stmt2.setString(14, rs.getString("app_cd"));
                    stmt2.setBytes(15, rs.getBytes("test_data_bin"));
                    stmt2.setBytes(16, rs.getBytes("notes_bin"));
                    stmt2.executeUpdate();
                }
                return count;
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to create SNAPSHOT NCubes for app: " + app + ", version: " + newSnapVer + ", due to an error: " + e.getMessage();
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt0);
                jdbcCleanup(stmt1);
                jdbcCleanup(stmt2);
            }
        }
    }

    /**
     * Change the SNAPSHOT version value.
     */
    public static void changeVersionValue(Connection connection, String app, String currVersion, String newSnapVer)
    {
        validateConnection(connection);
        validateApp(app);
        validateVersion(currVersion);
        validateVersion(newSnapVer);

        synchronized (cubeList)
        {
            PreparedStatement stmt1 = null;
            PreparedStatement stmt2 = null;

            try
            {
                stmt1 = connection.prepareStatement("SELECT n_cube_id FROM n_cube WHERE app_cd = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.RELEASE + "'");
                stmt1.setString(1, app);
                stmt1.setString(2, newSnapVer);
                ResultSet rs = stmt1.executeQuery();
                if (rs.next())
                {
                    throw new IllegalStateException("RELEASE n-cubes found with version " + newSnapVer + ".  Choose a different SNAPSHOT version.");
                }

                stmt2 = connection.prepareStatement("UPDATE n_cube SET update_dt = ?, version_no_cd = ? WHERE app_cd = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.SNAPSHOT + "'");
                stmt2.setDate(1, new java.sql.Date(System.currentTimeMillis()));
                stmt2.setString(2, newSnapVer);
                stmt2.setString(3, app);
                stmt2.setString(4, currVersion);
                int count = stmt2.executeUpdate();
                if (count < 1)
                {
                    throw new IllegalStateException("No SNAPSHOT n-cubes found with version " + currVersion + ", therefore nothing changed.");
                }
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to change SNAPSHOT version from " + currVersion + " to " + newSnapVer + " for app: " + app + ", due to an error: " + e.getMessage();
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt1);
                jdbcCleanup(stmt2);
            }
        }
    }

    public static boolean renameCube(Connection connection, String oldName, String newName, String app, String version)
    {
        validateConnection(connection);
        validateApp(app);
        validateVersion(version);
        validateCubeName(oldName);
        validateCubeName(newName);

        if (oldName.equalsIgnoreCase(newName))
        {
            throw new IllegalArgumentException("Old name cannot be the same as the new name, name: " + oldName);
        }

        synchronized (cubeList)
        {
            PreparedStatement stmt1 = null;

            try
            {
                stmt1 = connection.prepareStatement("UPDATE n_cube SET n_cube_nm = ? WHERE app_cd = ? AND version_no_cd = ? AND n_cube_nm = ? AND status_cd = '" + ReleaseStatus.SNAPSHOT + "'");
                stmt1.setString(1, newName);
                stmt1.setString(2, app);
                stmt1.setString(3, version);
                stmt1.setString(4, oldName);
                int count = stmt1.executeUpdate();
                if (count < 1)
                {
                    throw new IllegalArgumentException("No n-cube found to rename, for app:" + app + ", version: " + version + ", original name: " + oldName);
                }

                cubeList.remove(makeCacheKey(oldName, version));
                return true;
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to rename n-cube due to an error: " + e.getMessage();
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt1);
            }
        }
    }

    /**
     * Delete the named NCube from the database
     *
     * @param connection JDBC connection
     * @param name       NCube to be deleted
     */
    public static boolean deleteCube(Connection connection, String app, String name, String version, boolean allowDelete)
    {
        validateConnection(connection);
        validateApp(app);
        validateCubeName(name);
        validateVersion(version);

        synchronized (cubeList)
        {
            PreparedStatement stmt = null;
            try
            {
                if (allowDelete)
                {
                    stmt = connection.prepareStatement("DELETE FROM n_cube WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ?");
                }
                else
                {
                    stmt = connection.prepareStatement("DELETE FROM n_cube WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.SNAPSHOT + "'");
                }
                stmt.setString(1, app);
                stmt.setString(2, name);
                stmt.setString(3, version);
                int rows = stmt.executeUpdate();
                if (rows > 0)
                {
                    cubeList.remove(makeCacheKey(name, version));
                    return true;
                }
                return false;
            }
            catch (Exception e)
            {
                String s = "Unable to delete NCube: " + name + ", app: " + app + ", version: " + version + " from database: " + e.getMessage();
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt);
            }
        }
    }

    /**
     * Update the notes associated to an NCube
     *
     * @return true if the update succeeds, false otherwise
     */
    public static boolean updateNotes(Connection connection, String app, String name, String version, String notes)
    {
        validateConnection(connection);
        validateApp(app);
        validateCubeName(name);
        validateVersion(version);

        synchronized (cubeList)
        {
            PreparedStatement stmt = null;
            try
            {
                stmt = connection.prepareStatement("UPDATE n_cube SET notes_bin = ?, update_dt = ? WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ?");
                stmt.setBytes(1, notes == null ? null : notes.getBytes("UTF-8"));
                stmt.setDate(2, new java.sql.Date(System.currentTimeMillis()));
                stmt.setString(3, app);
                stmt.setString(4, name);
                stmt.setString(5, version);
                int count = stmt.executeUpdate();
                if (count > 1)
                {
                    throw new IllegalStateException("Only one (1) row's notes should be updated.");
                }
                if (count == 0)
                {
                    throw new IllegalStateException("No NCube matching app: " + app + ", name: " + name + ", version: " + version);
                }
                return true;
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                throw new RuntimeException("Unable to update notes for NCube: " + name + ", app: " + app + ", version: " + version, e);
            }
            finally
            {
                jdbcCleanup(stmt);
            }
        }
    }

    /**
     * Get the notes associated to an NCube
     *
     * @return String notes.
     */
    public static String getNotes(Connection connection, String app, String name, String version, Date sysDate)
    {
        validateConnection(connection);
        validateApp(app);
        validateCubeName(name);
        validateVersion(version);
        if (sysDate == null)
        {
            sysDate = new Date();
        }

        PreparedStatement stmt = null;
        try
        {
            java.sql.Date systemDate = new java.sql.Date(sysDate.getTime());
            stmt = connection.prepareStatement("SELECT notes_bin FROM n_cube WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ? AND sys_effective_dt <= ? AND (sys_expiration_dt IS NULL OR sys_expiration_dt >= ?)");
            stmt.setString(1, app);
            stmt.setString(2, name);
            stmt.setString(3, version);
            stmt.setDate(4, systemDate);
            stmt.setDate(5, systemDate);
            ResultSet rs = stmt.executeQuery();

            if (rs.next())
            {
                byte[] notes = rs.getBytes("notes_bin");
                return new String(notes == null ? "".getBytes() : notes, "UTF-8");
            }
            throw new IllegalArgumentException("No NCube matching passed in parameters.");
        }
        catch (IllegalArgumentException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            String s = "Unable to fetch notes for NCube: " + name + ", app: " + app + ", version: " + version;
            LOG.error(s, e);
            throw new RuntimeException(s, e);
        }
        finally
        {
            jdbcCleanup(stmt);
        }
    }

    /**
     * Update the test data associated to an NCube
     *
     * @return true if the update succeeds, false otherwise
     */
    public static boolean updateTestData(Connection connection, String app, String name, String version, String testData)
    {
        validateConnection(connection);
        validateApp(app);
        validateCubeName(name);
        validateVersion(version);

        synchronized (cubeList)
        {
            PreparedStatement stmt = null;
            try
            {
                stmt = connection.prepareStatement("UPDATE n_cube SET test_data_bin=?, update_dt=? WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ? AND status_cd = '" + ReleaseStatus.SNAPSHOT + "'");
                stmt.setBytes(1, testData == null ? null : testData.getBytes("UTF-8"));
                stmt.setDate(2, new java.sql.Date(System.currentTimeMillis()));
                stmt.setString(3, app);
                stmt.setString(4, name);
                stmt.setString(5, version);
                int count = stmt.executeUpdate();
                if (count > 1)
                {
                    throw new IllegalStateException("Only one (1) row's test data should be updated.");
                }
                if (count == 0)
                {
                    throw new IllegalStateException("No NCube matching app: " + app + ", name: " + name + ", version: " + version);
                }
                return true;
            }
            catch (IllegalStateException e)
            {
                throw e;
            }
            catch (Exception e)
            {
                String s = "Unable to update test data for NCube: " + name + ", app: " + app + ", version: " + version;
                LOG.error(s, e);
                throw new RuntimeException(s, e);
            }
            finally
            {
                jdbcCleanup(stmt);
            }
        }
    }

    /**
     * Get the Test Data associated to the NCube.
     *
     * @return String serialized JSON test data.  Use JsonReader to turn it back into
     * Java objects.
     */
    public static String getTestData(Connection connection, String app, String name, String version, Date sysDate)
    {
        validateConnection(connection);
        validateApp(app);
        validateCubeName(name);
        validateVersion(version);
        if (sysDate == null)
        {
            sysDate = new Date();
        }

        PreparedStatement stmt = null;
        try
        {
            java.sql.Date systemDate = new java.sql.Date(sysDate.getTime());
            stmt = connection.prepareStatement("SELECT test_data_bin FROM n_cube WHERE app_cd = ? AND n_cube_nm = ? AND version_no_cd = ? AND sys_effective_dt <= ? AND (sys_expiration_dt IS NULL OR sys_expiration_dt >= ?)");
            stmt.setString(1, app);
            stmt.setString(2, name);
            stmt.setString(3, version);
            stmt.setDate(4, systemDate);
            stmt.setDate(5, systemDate);
            ResultSet rs = stmt.executeQuery();

            if (rs.next())
            {
                byte[] testData = rs.getBytes("test_data_bin");
                return new String(testData == null ? "".getBytes() : testData, "UTF-8");
            }
            throw new IllegalArgumentException("No NCube matching passed in parameters.");
        }
        catch (IllegalArgumentException e)
        {
            throw e;
        }
        catch (Exception e)
        {
            String s = "Unable to fetch test data for NCube: " + name + ", app: " + app + ", version: " + version;
            LOG.error(s, e);
            throw new RuntimeException(s, e);
        }
        finally
        {
            jdbcCleanup(stmt);
        }
    }

    private static String getResourceAsString(String name) throws IOException
    {
        ByteArrayOutputStream out = new ByteArrayOutputStream(8192);
        URL url = NCubeManager.class.getResource("/" + name);
        IOUtilities.transfer(new File(url.getFile()), out);
        return new String(out.toByteArray(), "UTF-8");
    }

    public static NCube getNCubeFromResource(String name)
    {
        try
        {
            String json = getResourceAsString(name);
            NCube ncube = ncubeFromJson(json);
            addCube(ncube, "file");
            return ncube;
        }
        catch (IOException e)
        {
            String s = "Failed to load ncube from resource: " + name;
            LOG.error(s, e);
            throw new RuntimeException(s, e);
        }
    }

    /**
     * Still used in getNCubesFromResource
     */
    private static JsonObject getJsonObjectFromResource(String name) throws IOException
    {
        JsonReader reader = null;
        try
        {
            URL url = NCubeManager.class.getResource("/" + name);
            File jsonFile = new File(url.getFile());
            InputStream in = new BufferedInputStream(new FileInputStream(jsonFile));
            reader = new JsonReader(in, true);
            return (JsonObject) reader.readObject();
        }
        finally
        {
            IOUtilities.close(reader);
        }
    }

    public static List<NCube> getNCubesFromResource(String name)
    {
        String lastSuccessful = "";
        try
        {
            JsonObject ncubes = getJsonObjectFromResource(name);
            Object[] cubes = ncubes.getArray();
            List<NCube> cubeList = new ArrayList<NCube>(cubes.length);

            for (Object cube : cubes)
            {
                JsonObject ncube = (JsonObject) cube;
                String json = JsonWriter.objectToJson(ncube);
                NCube nCube = NCube.fromSimpleJson(json);
                addCube(nCube, "file");
                lastSuccessful = nCube.getName();
                cubeList.add(nCube);
            }

            return cubeList;
        }
        catch (Exception e)
        {
            String s = "Failed to load ncubes from resource: " + name + ", last successful cube: " + lastSuccessful;
            LOG.error(s);
            throw new RuntimeException(s, e);
        }
    }

    static NCube ncubeFromJson(String json) throws IOException
    {
        try
        {
            return NCube.fromSimpleJson(json);
        }
        catch (Exception e)
        {
            return (NCube) JsonReader.jsonToJava(json);
        }
    }
}
TOP

Related Classes of com.cedarsoftware.ncube.NCubeManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.