com.baasbox.dao.ScriptsDao.java Source code

Java tutorial

Introduction

Here is the source code for com.baasbox.dao.ScriptsDao.java

Source

/*
 * Copyright (c) 2014.
 *
 * BaasBox - info@baasbox.com
 *
 * 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
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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.
 */

package com.baasbox.dao;

import com.baasbox.dao.exception.InvalidScriptException;
import com.baasbox.dao.exception.ScriptAlreadyExistsException;
import com.baasbox.dao.exception.ScriptException;
import com.baasbox.dao.exception.SqlInjectionException;
import com.baasbox.db.DbHelper;
import com.baasbox.util.QueryParams;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.commons.codec.binary.Base64;
import com.orientechnologies.orient.core.command.OCommand;
import com.orientechnologies.orient.core.command.OCommandRequest;
import com.orientechnologies.orient.core.db.ODatabaseComplex;
import com.orientechnologies.orient.core.db.record.ODatabaseRecordTx;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.db.record.OTrackedList;
import com.orientechnologies.orient.core.id.ORecordId;
import com.orientechnologies.orient.core.index.OIndex;
import com.orientechnologies.orient.core.record.ORecordInternal;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.record.impl.ODocumentHelper;
import com.orientechnologies.orient.core.sql.OCommandSQL;
import com.orientechnologies.orient.core.storage.ORecordCallback;
import com.orientechnologies.orient.core.storage.OStorage;
import com.baasbox.service.logging.BaasBoxLogger;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by Andrea Tortorella on 10/06/14.
 */
public class ScriptsDao {

    public enum ENCODED_TYPE {
        BASE64;

        public String decode(String toDecode) {
            String toReturn = "";
            switch (this) {
            case BASE64:
                byte[] decoded = Base64.decodeBase64(toDecode);
                toReturn = StringUtils.newStringUtf8(decoded);
            }
            BaasBoxLogger.debug("Decode new script sent in {}. Input: {} Output: {}", BASE64, toDecode, toReturn);
            return toReturn;
        }
    }

    public static final String MODEL_NAME = "_BB_Script";
    public static final String NAME = "name";
    public static final String CODE = "code";
    public static final String LANG = "lang";
    public static final String ENCODED = "encoded";
    public static final String LIB = "library";
    public static final String LOCAL_STORAGE = "_storage";
    public static final String INVALID = "_invalid";
    public static final String DATE = "_creation_date";
    public static final String ACTIVE = "active";

    private static final Pattern VALID_NAME_PATTERN = Pattern
            .compile("([a-zA-Z_][a-zA-Z_0-9]*)(\\.([a-zA-Z][a-zA-Z_0-9]*))+");
    private static final String INDEX = MODEL_NAME + "." + NAME;

    private final ODatabaseRecordTx db;

    protected ScriptsDao() {
        db = DbHelper.getConnection();
    }

    public static ScriptsDao getInstance() {
        return new ScriptsDao();
    }

    public boolean delete(String name) {
        ODocument doc = getByName(name);
        if (doc == null) {
            return false;
        } else {
            doc.delete();
            return true;
        }
    }

    //todo update script
    //todo read/update store
    //todo clear log

    public ODocument save(ODocument doc) {
        doc.save();
        return doc;
    }

    public ODocument create(String name, String language, String code, boolean isLibrary, boolean active,
            JsonNode initialStore) throws ScriptException {
        return create(name, language, code, isLibrary, active, initialStore, null);
    }

    public ODocument create(String name, String language, String code, boolean isLibrary, boolean active,
            JsonNode initialStorage, String encodedValue) throws ScriptException {
        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method Start");
        checkValidName(name);
        if (exists(name)) {
            throw new ScriptAlreadyExistsException("Script " + name + " already exists");
        }
        if (encodedValue != null) {
            code = ENCODED_TYPE.valueOf(encodedValue.toUpperCase()).decode(code);
        }
        ODocument doc = createPrivileged(name, language, code, isLibrary, active, initialStorage);
        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method End");
        return doc;
    }

    private ODocument createPrivileged(String name, String language, String code, boolean isLibrary, boolean active,
            JsonNode initialStore) {
        ODocument doc = makeScript(name, language, code, isLibrary, active, initialStore);
        save(doc);
        return doc;
    }

    public ODocument update(String name, String code) throws ScriptException {
        ODocument doc = getByName(name);
        if (doc == null) {
            throw new ScriptException("Script: " + name + " does not exists");
        }
        OTrackedList<String> codeVersions = doc.field(CODE);
        codeVersions.add(0, code);
        save(doc);
        return doc;
    }

    //used by the service
    public void revertToLastVersion(ODocument updated) {
        OTrackedList<String> code = updated.<OTrackedList<String>>field(CODE);
        code.remove(0);
        save(updated);
    }

    private ODocument makeScript(String name, String language, String code, boolean isLibrary, boolean active,
            JsonNode initialStore) {
        ODocument doc = new ODocument(MODEL_NAME);
        doc.field(NAME, name);
        doc.field(LANG, language);
        List<String> codes = Collections.singletonList(code);
        doc.field(CODE, codes);
        doc.field(DATE, new Date());
        doc.field(LIB, isLibrary);
        doc.field(ACTIVE, active);
        ODocument local = new ODocument();
        if (initialStore != null) {
            local.fromJSON(initialStore.toString());
        }
        doc.field(LOCAL_STORAGE, local);
        doc.field(INVALID, false);
        return doc;
    }

    public List<ODocument> getAll(QueryParams params) throws SqlInjectionException {
        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method Start");
        List<ODocument> docs = null;
        params = params == null ? QueryParams.getInstance() : params;
        OCommandRequest command = DbHelper.selectCommandBuilder(MODEL_NAME, params.justCountTheRecords(), params);
        docs = DbHelper.commandExecute(command, params.getParams());

        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method End");
        return docs;
    }

    public List<ODocument> getAll() throws SqlInjectionException {
        return getAll(QueryParams.getInstance());
    }

    public static void checkValidName(String name) throws ScriptException {
        if (name == null || name.trim().length() == 0) {
            throw new InvalidScriptException("Script must have non empty name");
        }
        if (!VALID_NAME_PATTERN.matcher(name).matches()) {
            throw new InvalidScriptException(
                    "Script names must be composed of letters numbers and underscores, and cannot start with numbers. Script must have at least one namespace part. Valid example: mynamespace.myscript");
        }
        if (isInternalName(name)) {
            throw new InvalidScriptException("User scripts cannot belong to 'baasbox' namespace");
        }
    }

    private static boolean isInternalName(String name) {
        return name != null && name.startsWith("baasbox");
    }

    public boolean exists(String name) {
        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method Start");
        boolean exists = findByName(name) != null;
        if (BaasBoxLogger.isDebugEnabled())
            BaasBoxLogger.debug("Exists " + exists);
        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method End");
        return exists;
    }

    public ODocument getByName(String name) {
        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method Start");
        OIdentifiable id = findByName(name);
        ODocument doc = id == null ? null : (ODocument) db.load(id.getIdentity());
        if (BaasBoxLogger.isTraceEnabled())
            BaasBoxLogger.trace("Method End");
        return doc;
    }

    private OIdentifiable findByName(String name) {
        OIndex idx = db.getMetadata().getIndexManager().getIndex(INDEX);
        return (OIdentifiable) idx.get(name);
    }

    public void invalidate(ODocument script) {
        script.field(INVALID, true);
        save(script);
    }

    public ODocument getByNameLocked(String name) {
        OIndex idx = db.getMetadata().getIndexManager().getIndex(INDEX);
        OIdentifiable idf = (OIdentifiable) idx.get(name);
        if (idf == null) {
            return null;
        }
        ODocument doc = db.load(idf.getIdentity(), null, false, false,
                OStorage.LOCKING_STRATEGY.KEEP_EXCLUSIVE_LOCK);

        return doc;
    }

    public boolean activate(ODocument script, boolean activate) {
        boolean current = script.<Boolean>field(ACTIVE);
        script.field(ACTIVE, activate);
        script.save();
        return current != activate;
    }

}